evalことはじめ

eval

osamu = 'tezuka osamu'  # => "tezuka osamu"
eval('osamu')  # => "tezuka osamu"

#  Bindingインスタンスを渡すことでコンテクストを指定できる
def context_literature
  osamu = 'dazai osamu'
  binding
end
eval('osamu', context_literature)  # => "dazai osamu"

instance_eval

文字列やブロックを渡すと、それを「レシーバの特異クラス定義の中に近いコンテクスト」で評価してくれる。

# 準備
class Novelist
  attr_reader :works
  def initialize(*works)
    @works = works
  end
end

dazai = Novelist.new("ningen sikkaku", "syayo")
akutagawa = Novelist.new("rashomon", "hana")

# usage1: 文字列を渡す
dazai.instance_eval('def representative_work; @works[0]; end')
dazai.singleton_methods  # => [:representative_work]
dazai.representative_work  # => "ningen sikkaku"

# usage2: ブロックを渡す
akutagawa.instance_eval {def representative_work; @works[0]; end}
akutagawa.singleton_methods  # => [:representative_work]
akutagawa.representative_work  # => "rashomon"

instance_exec

概ねinstance_evalと同じだが、以下の点で異なる。

instance_execだとできないこと

文字列を渡せない

dazai.instance_exec('@works << "otogi zoushi"')  # LocalJumpError: no block given
instance_execでのみできること

引数をブロック引数として渡せる

# usage1: 引数なしのブロック(これはinstance_evalでもできる)
dazai.instance_exec{@works << 'otogi zoushi'}
dazai.works  # => ["ningen sikkaku", "syayo", "otogi zoushi"]

# usage2: 引数ありのブロック(これはinstance_evalではできない)
dazai.instance_exec('good bye'){ |work| @works << work }
dazai.works  # => ["ningen sikkaku", "syayo", "otogi zoushi", "good bye"]

こういうときにつかえるな!とはまだ想像できないが、instance_execの方が柔軟性が高そうだな?

とりあえずここまで。