Ruby でメソッドの一時的な上書き
テストとかでやりたくなると思うけど、こんなくだらないことに 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 みたいに使えばいいのかな。もっと簡単にできたらいいけどできなそう…
関連エントリー
- Ruby でスコープをはずれたときに自動で何かをする Guard オブジェクト Perl だと Guard オブジェクトとかいうハックがあって、スコープを出るタイミングで必ず呼ばれるファイナライ...
- perl 5.19.9 の signatures 構文 (普通に引数を書ける構文) を試す Perl 5.19.9 で実装された signatures の構文をためしてみる - tokuhirom blog を見てそんなのできたのか...
- Ruby で sysfs 経由での GPIO 操作 GPIO の操作はいろいろやる方法があるみたいだけど、LL からだと sysfs への IO を行うのが一番簡単っぽい。以下のような感じでか...
- Ruby でネストした構造体文字列をネストした配列として unpack する Cの構造体とかだと、構造体の中に他の構造体ということは普通にあります。 こういった構造体の文字列を unpack すると、全部フラットな配列...
- RaspberryPi を家庭内 LAN の DNS キャッシュサーバーに LAN向けのDNSキャッシュサーバ 経緯としてRTX1200 の DNS 機能が TCP フォールバックに対応してないのでオフにした、という...