没有继承的人如何重写一个类方法并从新方法中调用原始方法?

问题描述:

我发现,成功地推翻Time.strftime这样一个来源:没有继承的人如何重写一个类方法并从新方法中调用原始方法?

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

麻烦的是,strftime是一个实例方法。我需要重写Time.now - 一种类方法 - 以便让任何呼叫者获得我的新方法,而新方法仍然调用原始方法.now。我看过alias_method,但没有成功。

这是有点难以有时身边让你的头,但你需要打开“eigenclass”,这是一类特殊对象关联的单。这个语法是类< < 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),红宝石嘲讽/斯塔宾框架会为你轻松做到这一点。例如,使用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