eval族のスコープについてまとめた
ややこしかったので、まとめました。
eval(Bindingなし)
実行中のコンテキストに出現する変数に対しての操作が可能
foo = "foo" eval('p foo') #=> foo
eval(Bindingあり)
以下のように、Bindingオブジェクトを使うことで、以下のようにコンテキストを指定できます。
class C def instance_binding foo = "foooo" binding end end foo = "foo" binding_object = C.new.instance_binding eval('p foo', binding_object) #=> foooo # このようにも書ける binding_object.eval('p foo') #=> foooo
module_eval, class_eval
module_eval
は class_eval
の別名です。
文字列を渡した場合とブロックを渡した場合で、どのスコープで評価されるかが変わります。
文字列を引数とした場合は、レシーバーのスコープで評価されます。
class C; end C.class_eval(<<-EOF) Foo = "bar" def hoge p Foo end EOF Foo = "foo"
ブロックを引数とした場合は、そのコンテキストのスコープで評価されます。 つまり、以下ではトップレベルで定義したことになります。
class C; end C.class_eval do Foo = "bar" def hoge p Foo end end Foo = "foo" C.new.hoge # => warning: already initialized constant Foo # warning: previous definition of Foo was here # "foo" p Object.const_get(:Foo) # => "foo"
instance_eval
module_eval
, class_eval
と同じく、文字列で渡すときとブロックで渡すときで変わります。
module_exec, class_exec
module_exec
は class_exec
の別名です。
ブロックで渡されたときのスコープは、module_eval
と同じです。
文字列での評価はできません。
class C; end C.class_exec do Foo = "bar" def hoge p Foo end end Foo = "foo" C.new.hoge
また、引数をとりブロック引数として、評価する式に値を渡すことができます。
class C; end C.class_exec(:foo) do |foo| define_method(foo) do p "foo" end end C.new.foo #=> "foo"
instance_exec
module_exec
は class_exec
と同じく、引数で値を渡すことができます。