10

我找到了一个像这样成功覆盖的来源Time.strftime

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

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

4

4 回答 4

12

有时这有点难以理解,但您需要打开“eigenclass”,它是与特定类对象关联的单例。其语法是 class << 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
于 2008-11-13T20:05:03.760 回答
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
于 2008-11-13T20:03:38.710 回答
1

如果您出于测试目的需要覆盖它(我通常想要覆盖 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
于 2008-11-13T20:10:00.863 回答
0

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

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
于 2010-08-03T04:16:18.060 回答