Webサイト制作コースのお申し込みはこちら Webサイト制作コースのお申し込みはこちら

Rubyでプログラム開発に取り組んだことがある方は「eval」というメソッドが利用されているコードを見掛けたことがあるのではないでしょうか。

本記事では、Ruby開発初心者の方にも分かりやすく、evalメソッドの役割と使い方をサンプルコードを掲載しながらご紹介していきます。

Rubyのevalメソッドとは


Rubyのevalメソッドとは、引数に設定した文字列をRubyのプログラムとして実行するメソッドです。

evalはメタプログラミングで使用

evalメソッドは少し専門的な言葉で表すと、メタプログラミングで利用するメソッドです。

メタプログラミングとは、Wikipediaによると下記のように記述されています。

プログラミング技法の一種で、ロジックを直接コーディングするのではなく、あるパターンをもったロジックを生成する高位ロジックによってプログラミングを行う方法、またその高位ロジックを定義する方法のこと。

参考: メタプログラミング

evalメソッドを使うメリットは?

evalメソッドを使うメリットは、簡単に言ってしまうと何でも出来る点にあります。

与えられた文字列をRubyのプログラムとして解析してくれるため、言ってしまえばRubyで出来ることは全て実現出来ることになります。

またevalメソッドでは、指定した文字列がプログラムコードとして正しいかどうかを評価するため、実行するプログラムのエラーチェックとして利用することが可能です。

evalメソッドを使う危険性も理解しよう

evalメソッドは何でも出来る反面、危険性の高いメソッドとしても知られています。

最も危険視すべき点は、開発者が予測出来ていないバグを生み出す可能性が非常に高いということです。

プログラムコードとして成立している文字列であれば何でも実行出来てしまうため、例えばユーザーが入力した文字列をプログラムとして解析するような実装をしている場合、悪意のあるユーザーによってシステムが破壊されてしまう可能性も十分に考えられます。

他にもevalを利用することによって、パフォーマンスの低下や可読性の低下を招く危険もあるため、使い所を慎重に見極めた上で利用する必要があります。

Rubyでのevalメソッドの使い方


では実際にRubyのevalメソッドはどのように記述して利用出来るのか確認していきましょう。

基本構文

Rubyのevalでは、下記の構文に沿って記述します。

eval(expr [, bind, fname, lineno])

第1引数の「expr」は必須項目で、第2引数以降の値は任意で設定可能です。

ポテパンダの一言メモ

第3引数のfnameを省略した場合にはデフォルト値して「(eval)」、第4引数のlinenoを省略した場合にはデフォルト値として「1」が設定されます。

第1引数: expr

Rubyプログラムとして評価したい文字列を第1引数のexprに設定します。

「サンプルを出力しています。」とコンソール出力したい場合には、下記のように記述します。

eval('puts "サンプルを出力しています。"')

実行結果

$ ruby sample.rb
サンプルを出力しています。

第2引数: bind

bindはBindingオブジェクトの略称で、変数やメソッドなどの環境情報を表すオブジェクトです。

あるメソッド内のローカル変数を、evalで参照したい場合などに利用出来ます。

エラーケース

例えば下記の記述はエラーとなってしまいます。

eval('text="サンプルを出力しています。"')
eval('puts text')

実行結果

$ ruby sample.rb
Traceback (most recent call last):
	2: from sample.rb:2:in `'
	1: from sample.rb:2:in `eval'
(eval):1:in `': undefined local variable or method `text' for main:Object (NameError)

最初のeval内で設定した変数を保持したまま、別のeval処理で利用することは出来ないようです。

Bindingオブジェクトを活用した記述方法

上記のエラーをBindingオブジェクトを利用して記述し直すと、下記のように修正することが出来ます。

def local_variable
  text="サンプルを出力しています。"
  binding
end

eval('puts text', local_variable)

実行結果

$ ruby sample.rb
サンプルを出力しています。

今回の場合、local_variableというメソッドを作成しbindingオブジェクトを返却するように記述したことで、ローカル変数として定義されたtextにevalからアクセスすることが出来るようになりました。

第3引数: fname

fnameにファイル名を指定することで、exprに記述された文字列を指定したファイル名で実行されているかのように見せかけることが出来ます。

例えば、実際にはsample.rbに記述されていた上記のRubyプログラムを、test.rbから実行されているかのように見せかけてみましょう。

def local_variable
  text="サンプルを出力しています。"
  binding
end

eval('put text', local_variable, 'test.rb')

実行結果

$ ruby sample.rb
test.rb:1:in `local_variable': undefined method `put' for main:Object (NoMethodError)

今回のサンプルでは、本来putsと記述しなければいけない箇所をputと記述し、わざとエラーを発生させています。

実行結果にはtest.rbファイルの1行目でエラーが発生したかのように表示されています。

第4引数: lineno

linenoは第3引数と関連して、exprに記述された文字列をどのファイルの何行目かを指定して実行されているかのように見せかけることが出来ます。

例えば第3引数の記述方法では、エラー発生箇所が1行目と表示されていましたが、第4引数に5と設定して改めて実行してみましょう。

def local_variable
  text="サンプルを出力しています。"
  binding
end

eval('put text', local_variable, 'test.rb', 5)

実行結果

$ ruby sample.rb
test.rb:5:in `local_variable': undefined method `put' for main:Object (NoMethodError)

実行結果のエラー発生箇所が5行目と表示されていることをご確認頂けます。

さいごに:Rubyのevalメソッドは安易に使わないように!


本記事では、Rubyのevalメソッドについて、メソッドの役割から簡単な使い方をサンプルを交えてご紹介してきました。

evalは非常に強力なメソッドであるため、使い方によっては深刻なバグに繋がる可能性も常に意識しておかなければいけません。

evalを利用しなくても任意のプログラムを実現出来る方法が存在するケースは多く、まずはRubyのデフォルトやフレームワークで置き換えられるメソッドが提供されていないかを確認してみましょう。

もしevalを利用しないと実現することが難しい場合には、思わぬバグを紛れ込ませないように入念に正当性チェックを行った上で利用するようにしてください。

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。