継承なしでクラスメソッドをオーバーライドし、新しいメソッド内から元のメソッドを呼び出す方法は?
-
08-07-2019 - |
質問
次のように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
所属していません StackOverflow