evalメソッドとは
文字列 expr を Ruby プログラムとして評価してその結果を返します
Ruby 3.0.1 リファレンスマニュアル
第1引数に渡された文字列をrubyプログラムとして実行する。第1引数は必須。
eval(expr, bind, fname = “(eval)”, lineno = 1) -> object
- expr・・評価する文字列
- bind・・評価するコンテキスト(スコープを付与する時に使う)
- fname・・スタックトレースに表示するファイル名
- lineno・・exprが書かれていると想定した時の行番号の整数
どう省略されるか
evalを使わない場合
def a
p "hello"
end
a #=> "hello"
evalを使った場合
eval('def a; p "hello" end')
a #=> "hello"
第3、第4引数
第3、第4引数使ってeval.rbファイルの4行目でエラーが起きたことにできる
eval('raise RuntimeError', binding, 'eval.rb', 4)
#=> eval.rb:4:in `<main>': RuntimeError (RuntimeError)
#=> from eval.rb:4:in `eval'
#=> from eval.rb:4:in `<main>'
bindingの使い方
変数やメソッドのスコープを付与する時に使う。
bindingの記載位置は意識したほうがよさそう。
- メソッドの最後に記載する
- 複数記載しても実行されるのは最後のみ
# aメソッドのhiのスコープを使えるようになる(スコープが付与された)
def a
hi = "こんにちは"
binding
end
eval('p hi', a)
#=> "こんにちは"
# bメソッドにはhiはないのでエラーになる(スコープがずれてる)
def b
bye = "バイバイ"
binding
end
eval('p hi', b)
#=> `b': undefined local variable or method `hi' for main:Object (NameError)
まとめ
evalを使うことで文字列をrubyプログラムとして扱えるようになる。またbindingを使うことでスコープを付与することができる。
rubyプログラムを文字列で渡したい場合に使える。メソッド化したくない処理とか?
※追記
evalメソッドは極力使わない方が良い。脆弱性が高まる。effective rubyにも『これは非常に危険なことだ』と書かれてた。