Ruby の #instance_eval と #instance_exec の違い
#instance_eval
は渡されたブロックをレシーバのインスタンス元で実行するメソッドです。
なので例えば次のようにしてインスタンス変数をブロック内から参照する事ができます。
class X def initialize @name = "homu" end end x = X.new p x.instance_eval { @name } # => "homu"
また、ブロックであればいいので次のようにブロックオブジェクトも渡すことができます。
to_s = proc { "Name is #{@name}" } p x.instance_eval &to_s # => "Name is homu"
#instance_exec
とは
#instance_eval
と似たメソッドに #instance_exec
があります。
これも #instance_eval
と同様にレシーバのインスタンス元でブロックを実行します。
class X def initialize @name = "homu" end end x = X.new p x.instance_exec { @name } # => "homu" to_s = proc { "Name is #{@name}" } p x.instance_exec &to_s # => "Name is homu"
#instance_eval
との違い
#instance_eval
は次のように引数を持つブロックを評価する事ができません。
to_s = proc { |other| "#{@name} x #{other}" } # to_s に対して引数を渡すことができない。 p x.instance_eval &to_s
一方、#instance_exec
は引数を渡すと、それがブロックの引数として渡されます。
to_s = proc { |other| "#{@name} x #{other}" } p x.instance_exec "mado", &to_s # => "homu x mado"
こういう風にブロックに対して引数を渡したい場合は #instance_exec
を利用することができます。