【初心者必見!】Ruby evalを理解し活用するための4つのTips

こんにちは! フリーエンジニアの長瀬です。

みなさんはevalを使っていますか?

evalを使えば、evalに渡した文字をRubyプログラムとして実行させることができます。

この記事では、rubyのevalについて

・evalの使い方
・Bidingオブジェクトの指定

という基本的な内容から、

・instance_evalの使い方
・class_evalの使い方
・module_evalの使い方

といった応用的な内容についても解説していきます。

目次

evalとは

evalとは何かを一言で説明すると「引数として与えた文字列をRubyプログラムとして実行するメソッド」です。

引数として与えた文字列を評価することができ、実行する文のエラーチェックに使うことができるので、異常発生を検知するときに使えます。

基本的なevalの使い方

evalの使い方

evalの基本的な使い方としては下記のように評価する式を引数として与えるだけです。

eval("puts 'Hello, everyone !'")

正式な構文は以下のようになっています。

eval(expr [,bindingObj, fname, fileno])

指定が必須なのは第1引数のみです。それ以外の引数指定は任意です。

第3引数fname, 第4引数filenoが与えられた場合、ファイル名fnameの行番号filenoに評価する式exprが書かれているかのように見せることができます。第2引数に指定するBindingオブジェクトは次の章で説明します。

例えば、スタックトレースに表示されるファイル名やソースファイルの行番号を自由に変更できます。

下記はサンプルコードです。sample.rbの10行目に「raise RuntimeError」が書かれているかのように見せることができます

eval('raise RuntimeError', binding, 'sample.rb', 10)
# sample.rb:10: RuntimeError (RuntimeError)

Bindingオブジェクトの指定

evalメソッドの第2引数には「Bindingオブジェクト」を指定することができます。

変数やメソッドにはそれらが有効な範囲(スコープ)があります。その定義されたスコープを表すオブジェクトがBindingオブジェクトです。

例えば、あるメソッド内で定義された変数をそのメソッドの外部から使用したいときに指定します。

下記のサンプルコードを使いながら、Bindingオブジェクトについて説明します。

def bindSample
hoge = 100
binding # Bindingオブジェクトの生成
end

eval("p hoge", bindSample)

[実行結果]

100

bindSampleメソッド内において、ローカル変数hogeを定義しています。

またbindingメソッドを実行することにより、bindSampleメソッドのBindingオブジェクトを生成して返します。

だからこそ、bindSampleメソッドの外部からローカル変数hogeを参照することができるわけです。

なので、たとえば以下のように、eval内でローカル変数を定義した場合evalで参照することができず、エラーを返します。

eval("hogehoge = 'this is hoge'")
eval("p hogehoge")

[実行結果]

# undefined local variable or method `hoge'

ですが、すでに定義されている変数についてはevalから呼び出したり値を代入したりできます。

hogehoge = "this is hogehoge."
eval("p hogehoge")
eval("hogehoge = 'changed'")
eval("p hogehoge")

[実行結果]

"this is hogehoge."
"changed"

eval応用編

instance_evalの使い方

instance_evalメソッドは、渡されたブロックを実行するものです。以下がサンプルコードです。

class InstanceEvalSample
def initialize
@name = "hoge"
end
end

x = InstanceEvalSample.new
p x.instance_eval { @name }

[実行結果]

"hoge"

このように、インスタンス変数nameをブロック内から参照する事ができます

class_evalの使い方

class_evalメソッドを使うと、ブロックをあたかもクラス定義やモジュール定義の中のコードであるかのように実行することができます。ブロックの戻り値がメソッドの戻り値となります。

class ClassEvalSample; end
ClassEvalSample.class_eval { def hello; "Hello, everyone !"; end }

puts ClassEvalSample.new.hello

[実行結果]

 "Hello, everyone !"

helloメソッドは、ClassEvalSampleクラスの中で定義していないにも関わらず、その中で定義しているかのように実行できます

module_evalの使い方

module_evalはclass_evalのエイリアス(名前は違うけど、機能は同じ)です。

なので、class_evalで紹介したサンプルコードをそのままmodule_evalに置き換えることができます。

class ClassEvalSample; end
ClassEvalSample.module_eval { def hello; "Hello, everyone !"; end }

puts ClassEvalSample.new.hello

[実行結果]

 "Hello, everyone !"

まとめ

今回はevalの基本とその使い方について説明したのに加え、Bindingオブジェクトを指定する場合の使い方についても説明しました。

また、応用例としてinstance_evalclass_evalメソッド、module_evalについても紹介しました。evalと類似したメソッドでもありますので、evalの基本を理解した上で、上手く活用していきましょう!

この記事を書いた人

Unityを使ったiOSアプリのリリース、フリマサイト運営の経験があります。

経験した言語はC、C#、Javascript、R、Python、Ruby、PHPなど

言語が好きで、英語や中国、ドイツ語を勉強しました。
将来的には海外で生活したいです。

現在はRuby on Rails5やCocos2dxの勉強を主にしています。

ライターとしては
できるだけ初心者にわかりやすい文章になるように心がけています。

趣味は語学、読書です。

目次