質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.62%

  • Ruby

    7302questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

requireで読んだスクリプトをevalで評価することはできますか?

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,028

jun68ykt

score 2956

こんにちは。いつもお世話になっております。

 目下、「パーフェクトRuby」を読んでいるのですが、同著の中の
サンプルコードで、動作を確認できないものがあったので、それについて、
質問させてください。
 ついては、少し長いのですが、以下、同著第3章「制御構造/メソッド/組み込み関数」
P.114からの引用です。

▼===引用、ここから=============
eval とrequire_relative
 
Ruby には、文字列をRubyの式として評価する組み込み関数Kernel.#evalがあります
(詳しくは 7-3 eval を参照してください)。
eval "puts 1+2" # "3"と表示
 Kernel.#require_relative は実行中のファイルパスを基準にrequireするのに便利ですが、
このKernel.#evalと組み合わせることはできません。
 evalが評価する文字列の中でrequire_relativeを呼び出すと以下のような例外が発生し、
必ず失敗します。
eval <<EOS
  require_relative 'foo' # LoadError: cannot infer basepath
EOS
 require_relative相当のことをしたい場合には、_FILE_ と組み合わせて以下の
ような方法でrequireすることができます。
 このとき、_FILE_は eval の第3引数に渡したファイルパスを返します。
eval <<EOS, nil, '/path/to/fname.rb'
  require File.expand_path('foo', File,dirname(_FILE_))
EOS
 標準添付ライブラリのirbやerbも内部的にevalを使用しているため、require_relativeを
呼び出すことはできません。

▲===引用、ここまで=============

 上記の説明で、例外「 LoadError: cannot infer basepath」を発生させて失敗する
サンプルコードは、自分の手元で再現できました。
 再現できていないのは、後に出てくる
require_relative相当のことをしたい場合には、_FILE_ と組み合わせて以下の
ような方法でrequireすることができます。
のほうです。

まず、文中の「・・・requireすることができます。」というのは、
  • evalで評価したい文字列となる、Rubyスクリプトを書く。
  • それを別のrubyスクリプトから require で読み込んでevalに渡す。
  • evalによって、requireで読み込まれたrubyスクリプトを評価する。
ということが出来るという意味と解釈しました。
(そもそも、この解釈が間違っているということでしたら、ぜひご指摘ください。)

これを検証するために以下のような、3行のinc.rb を作成しました。
(以降、[ykt68@sakura-vps]は自分の環境のプロンプトです。)

[ykt68@sakura-vps] pwd
/home/ykt68/perfectruby/ch03
[ykt68@sakura-vps] cat inc.rb
p = 10
q = 20
p + q*2
[ykt68@sakura-vps] 

さらに、同じディレクトリ /home/ykt68/perfectruby/ch03 に、書籍の説明にある
コードに若干追加した、以下のような require_eval_test.rb を作成しました。
x = eval <<EOS, nil, '/home/ykt68/perfectruby/ch03/require_eval_test.rb'
  require File.expand_path('inc', File.dirname(__FILE__))
EOS

puts x

これを実行したときに、inc.rb の最後の式の評価結果である、50 と表示
されるものと思ったのですが、以下のように true と表示されました。

[ykt68@sakura-vps] cat require_eval_test.rb
x = eval <<EOS, nil, '/home/ykt68/perfectruby/ch03/require_eval_test.rb'
  require File.expand_path('inc', File.dirname(_FILE_))
EOS
 
puts x
  
[ykt68@sakura-vps] ruby require_eval_test.rb
true

そこで質問なのですが、

(1) 上記で表示された true は、require関数の戻り値と考えていますが、それで正しいでしょうか?

(2) 上記のrequire_eval_test.rbのどこかを若干修正すれば、inc.rb の最後の行の評価結果である、
   50 が表示されるようにできますでしょうか?
  もし出来るのでしたら、修正箇所を教えて頂けますと幸いです。

  それとも、そもそも、元の書籍での説明が、この例で50と表示させるための
  説明ではないのでしょうか?

質問は以上です。
よろしくお願い致します。

※1:使用しているrubyのバージョンは、以下です。

[ykt68@sakura-vps] ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]

※2:なお引用文中、_FILE_の_は、記法の都合で全角アンダーバー1個で書いていますが、
 本当は半角アンダーバー2個です。

ykt68拝
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

まず、文中の「・・・requireすることができます。」というのは、
 
・ evalで評価したい文字列となる、Rubyスクリプトを書く。
・ それを別のrubyスクリプトから require で読み込んでevalに渡す。
・ evalによって、requireで読み込まれたrubyスクリプトを評価する。
 
ということが出来るという意味と解釈しました。
(そもそも、この解釈が間違っているということでしたら、ぜひご指摘ください。) 

はい。間違っています。
evalrequireを実行できる」(evalrequire_relative相当を実行できる)
というだけです。
eval <<EOS, nil, '/path/to/fname.rb'
  require File.expand_path('foo', File,dirname(_FILE_))
EOS
は、
  require File.expand_path('foo', File,dirname(_FILE_))
と同じです。

inc.rbの中身を実行して値を得たいのなら、
x = eval IO.read("inc.rb")
puts x

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/25 17:52

    ご回答、ありがとうございました。どうやら、
    「パーフェクトRuby」に書いてあるコードなんだから、スゴイことが出来るハズ!
    といったような思い込みがあったかもしれません。
    ご回答の、「・・・は、・・・と同じです。」との件、まだまだ自分の理解が浅いと思った次第です。ありがとうございました。

    キャンセル

+1

Kernel#requireの返り値は、読み込んだかどうかを表すbool値で、またrequire内のローカル変数は外とは無関係となっています。

つまり、
  1.  requireがtrueを返している。
  2.  そもそもrequire自体がそういうことをする目的の機能でない。

という結論です。なお、設定ファイルを書いておいて読み込む、というような目的には、RubyだとYAMLを使うのが一般的です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/25 17:50

    ご回答、ありがとうございました。どうやら、
    「パーフェクトRuby」に書いてあるコードなんだから、スゴイことが出来るハズ!
    といったような思い込みがあったかもしれません。
    YAMLについても、予備知識になりました。ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    7302questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。