如何 – 没有inheritance – 覆盖类方法并从新方法中调用原始方法?

我找到了一个成功覆盖Time.strftime源代码,如下所示:

 class Time alias :old_strftime :strftime def strftime #do something old_strftime end end 

麻烦的是, strftime是一个实例方法。 我需要覆盖Time.now – 一个类方法 – 在任何调用者获取我的新方法的同时,新方法仍然调用原始的.now方法。 我看过alias_method并没有成功。

这有点难以理解,但你需要打开“特征类”,这是与特定类对象相关联的单例。 这个语法是类<< self do ... end。

 class Time alias :old_strftime :strftime def strftime puts "got here" old_strftime end end class Time class << self alias :old_now :now def now puts "got here too" old_now end end end t = Time.now puts t.strftime 

类方法只是方法。 我强烈建议不要这样做,但你有两个相同的选择:

 class Time class << self alias_method :old_time_now, :now def now my_now = old_time_now # new code my_now end end end class << Time alias_method :old_time_now, :now def now my_now = old_time_now # new code my_now end end 

如果你需要为了测试目的而覆盖它(我通常想要覆盖Time.now的原因),Ruby模拟/存根框架将很容易为你做到这一点。 例如,使用RSpec(使用flexmock):

 Time.stub!(:now).and_return(Time.mktime(1970,1,1)) 

顺便说一句,我强烈建议通过为您的类提供一个可重写的时钟来避免使用Time.now:

 class Foo def initialize(clock=Time) @clock = clock end def do_something time = @clock.now # ... end end 

我一直在试图弄清楚如何使用模块覆盖实例方法。

 module Mo def self.included(base) base.instance_eval do alias :old_time_now :now def now my_now = old_time_now puts 'overrided now' # new code my_now end end end end Time.send(:include, Mo) unless Time.include?(Mo) > Time.now overrided now => Mon Aug 02 23:12:31 -0500 2010