継承なしでクラスメソッドをオーバーライドし、新しいメソッド内から元のメソッドを呼び出す方法は?

StackOverflow https://stackoverflow.com/questions/288020

質問

次のようにTime.strftimeを正常に上書きしたソースが1つ見つかりました:

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

問題は、strftimeはインスタンスメソッドです。新しいメソッドが元のTime.nowメソッドを呼び出している間に、呼び出し元が私の新しいメソッドを取得するような.now-クラスメソッドをオーバーライドする必要があります。 alias_methodを確認しましたが、成功しませんでした。

役に立ちましたか?

解決

これはときどき頭を動かすのが難しいですが、<!> quot; eigenclass <!> quot;を開く必要があります。これは、特定のクラスオブジェクトに関連付けられたシングルトンです。この構文はクラス<!> lt; <!> lt;です。自己は...終わり。

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

テスト目的でオーバーライドする必要がある場合(通常は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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top