ruby のブロック内の変数とif文とのスコープ的なアレ
ruby のブロック内の変数とメソッド内の
スコープ的なもののメモ (ruby 1.8.7 で実行)
復習
def dummy yield end def func foo = nil dummy{foo = :hoge} foo end func # => :hoge def func dummy{foo = :hoge} foo end func # => NameError: undefined local variable or method `foo' for main:Object
ここまでは問題無いと思う。
で、↓こんなコードがあったとき、
def dummy yield end def func(arg) if arg foo = :foo1 else dummy { foo = :foo2} end foo end
func(nil) だとどうなるか気になったので実行してみた。
func(true) # => :foo1 func(nil) # => :foo2
arg = nil のときのブロックの中の foo は外の foo になるらしい、
多分 if の中を先に評価して名前空間内に foo が出てくるんだと思う。
じゃあこんなの↓ならどうなる?
def func(arg) unless arg dummy{ foo = :foo3} else foo = :foo4 end foo end
func(true) # => :foo4
これは期待通り
func(nil) # => nil
上から見て先に出ないとブロック内の変数になる(その後のelse 内で出てくるから、NameError にはならない)。
この例ぐらい分かりやすい話なら気付くけど、複雑なコードだと面倒なバグの原因になるかもねー
おまけ
def func eval("foo = :foo5") foo end func # => NameError: undefined local variable or method `foo' for main:Object def func foo = nil eval("foo = :foo6") foo end func # => :foo6