【问题标题】:How does one - without inheritance - override a class method and call the original from within the new method?没有继承的人如何覆盖类方法并从新方法中调用原始方法?
【发布时间】:2010-09-22 05:28:30
【问题描述】:
我找到了一个成功覆盖Time.strftime 的来源,如下所示:
class Time
alias :old_strftime :strftime
def strftime
#do something
old_strftime
end
end
麻烦的是,strftime 是一个实例方法。我需要重写Time.now——一个类方法——这样任何调用者都可以得到我的新方法,而新方法仍然调用原来的.now方法。我查看了alias_method 并没有成功。
【问题讨论】:
标签:
ruby
class
time
overriding
alias
【解决方案1】:
有时这有点难以理解,但您需要打开“eigenclass”,它是与特定类对象关联的单例。其语法是 class
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
【解决方案2】:
类方法只是方法。我强烈建议不要这样做,但您有两个等效的选择:
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
【解决方案3】:
如果您出于测试目的需要重写它(我通常想要重写 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
【解决方案4】:
我一直在试图弄清楚如何使用模块覆盖实例方法。
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