読者です 読者をやめる 読者になる 読者になる

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 を利用することができます。