Rubyで特異メソッドを定義するとき、外側のスコープに存在する変数を参照したい場合があります(よね?)。
i = 42 x = Object.new def x.hoge p i end x.hoge #=> NameError: undefined local variable or method `i' |
このように、defで定義すると外側の変数は見られません。
そこでどうするかというと、ブロック引数で定義するdefine_methodの出番です。それには、class_evalが必要で、class_evalのレシーバとなる特異クラスを最初に入手する必要があって、と考えるとこうなりました。
i = 42 y = Object.new (class << y; self; end).class_eval do define_method(:hoge) do p i end end y.hoge #=> 42 i = 201 y.hoge #=> 201 |
class << y; self; endは1つのイディオムのようです。
なお、Ruby on Rails、正確にはActiveSupportを使っているなら、Kernelモジュールにclass_eval(特異クラスを取り出してそこでclass_evalする)が追加されており、このように書けました。
i = 42 z = Object.new z.class_eval do define_method(:hoge) do p i end end |
さらに、class << z; self; endに相当するKernel#singleton_classもあります。これも便利そうです。
スポンサード リンク |
この記事のカテゴリ
- Ruby ⇒ 外側のスコープを参照しつつ特異メソッドを書く