ローカル変数とメソッドと eval
def x :method end def f if false x = :var end x end p f # => nil
f が nil を返すのは何ともかんとも。Python User としてはちょっと気持ち悪いかも知れない。まぁ、ruby はメソッドかローカル変数かをレキシカルな情報を使って判定しているんだろうけど。
で、まあ変なことを思いついたりするわけで。
require 'erb' template = <<'EOD' def x; :method; end def f <%= eval_assign ? "eval #{assign.inspect}" : assign %> <%= eval_exp ? "eval #{exp.inspect}" : exp %> end EOD erb = ERB.new(template, nil, '%<>') assign = 'x = :var' exp = 'x' puts '--------------------' [false, true].each do |eval_assign| [false, true].each do |eval_exp| code = erb.result(binding) puts code eval code puts "f # => #{f.inspect}" puts '--------------------' end end
なんか、1.8.6-p36 と trunk で挙動が違うのは eval(もしくは Binding)の仕様変更ということでいいんだろうか?Mailing List アーカイブを適当に見てみたけどよくわからん。
結果は以下。
ruby 1.8.6 pathlevel 36 の場合。
-------------------- def x; :method; end def f x = :var x end f # => :var -------------------- def x; :method; end def f x = :var eval "x" end f # => :var -------------------- def x; :method; end def f eval "x = :var" x end f # => :method -------------------- def x; :method; end def f eval "x = :var" eval "x" end f # => :var --------------------
ruby 1.9.0 trunk の場合
-------------------- def x; :method; end def f x = :var x end f # => :var -------------------- def x; :method; end def f x = :var eval "x" end f # => :var -------------------- def x; :method; end def f eval "x = :var" x end f # => :method -------------------- def x; :method; end def f eval "x = :var" eval "x" end f # => :method --------------------