2019-08-03
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 の方が柔軟性が高そうだな?
とりあえずここまで。