テストとかでやりたくなると思うけど、こんなくだらないことに gem とか使いたくないので、簡単に書ける方法をさがしてる。
class Foo def hello puts "Hello" end end
みたいなクラスがあったとして、hello メソッドを一時的に上書きしたい (そして戻したい) とき
あるオブジェクトのメソッドだけを上書き
これは singleton class を使ったらすぐできるのでかんたん
foo = Foo.new
orig = foo.method(:hello) # 元のメソッドを呼びたいときだけ必要
foo.define_singleton_method(:hello) do
puts "before hello"
orig.call
puts "after hello"
end
foo.hello #=>
# before hello
# Hello
# after hello
# 元に戻す
foo.singleton_class.send(:remove_method, :hello)
foo.hello #=>
# Hello
この方法は define_singleton_method だけでほぼ終わるし、元に戻すのも元のメソッドを保存しておく必要がないので (継承ツリーで上書きするので)、簡単
class << foo; alias ....; end
みたいなやりかたもあるけど alias でかぶったら嫌だし、alias の引数の順番覚えられないし好みではない
グローバルにあるクラスに属するメソッドを上書き
これはちょっと面倒な感じがする
# klass に定義された method メソッドをブロックで上書きする。
# ブロックには第1引数にオリジナルのメソッドが渡される
# 返り値は元に戻すための Proc インスタンス
def localize_method(klass, method, &block)
unbound = klass.instance_method(method)
klass.send(:define_method, method) do |*args|
block.call(unbound.bind(self), *args)
end
lambda {
klass.send(:define_method, method, unbound)
}
end
みたいなのを定義して
foo = Foo.new
bar = Foo.new
puts "===="
foo.hello
puts "----"
bar.hello
# ====
# Hello
# ----
# Hello
release = localize_method(Foo, :hello) do |orig|
puts "before hello"
orig.call
puts "after hello"
end
puts "===="
foo.hello
puts "----"
bar.hello
# ====
# before hello
# Hello
# after hello
# ----
# before hello
# Hello
# after hello
# 元に戻す
release.call
puts "===="
foo.hello
puts "----"
bar.hello
# ====
# Hello
# ----
# Hello
みたいに使えばいいのかな。もっと簡単にできたらいいけどできなそう…