【问题标题】: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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-11-20
            • 2021-12-06
            • 1970-01-01
            • 2012-10-15
            • 1970-01-01
            • 1970-01-01
            • 2013-08-15
            • 1970-01-01
            相关资源
            最近更新 更多