instance_evalとスコープ
これはfooがすでにローカル変数として宣言されているからそっちが優先された話でしょう。
foo.instance_eval { foo } # => #
foo.instance_eval{ defined? foo } # => "local-variable"
foo.instance_eval{ defined? bar } # => "method"
最初見たとき理解不能だった。
え、instance_evalってレシーバのコンテキストで評価されるんじゃないの?( ゚д゚)
なんで、外側のスコープにあるfooが見れるの???
で、調べてみると。
オブジェクトのコンテキストで評価するとは self をそのオブジェクトにして実行するということです。また、文字列/ブロック中でメソッドを定義すれば self の特異メソッドが定義されます。
ただし、ローカル変数だけは instance_eval の外側のスコープと共有します。
なるほど。ローカル変数はアクセスできるのね。
こういうことか。
S = Struct.new(:s) hoge = 1 S.new.instance_eval{hoge} #=> 1 S.new.instance_eval{fuga = 1} puts fuga NameError: undefined local variable or method `fuga' for main:Object from (irb):5
3行目のinstance_eval内からは、現在(Objectインスタンスのコンテキスト)のローカル変数(hoge)にアクセス可能。まぁ、じゃないと、使いづらいしね。何かを引数で受けて、それをinstance_eval内で使いたいってことは沢山あるし。
こういうのは当然無理。
z = 1 class Hoge def hoge instance_eval do z end end end Hoge.new.hoge NameError: undefined local variable or method `z' for #<Hoge:0x2e47ef4> from (irb):5:in `hoge' from (irb):4:in `instance_eval' from (irb):4:in `hoge' from (irb):9
今(Objectインスタンス)のコンテキストのローカル変数にアクセスするには、Objectインスタンス下でinstance_evalしないといけないから。