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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

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

Q&A

解決済

2回答

3030閲覧

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

jun68ykt

総合スコア9058

Ruby

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

0グッド

0クリップ

投稿2015/04/23 07:39

編集2015/04/23 08:26

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

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

▼===引用、ここから=============

eval とrequire_relative

Ruby には、文字列をRubyの式として評価する組み込み関数Kernel.#evalがあります
(詳しくは 7-3 eval を参照してください)。

lang

1eval "puts 1+2" # "3"と表示

Kernel.#require_relative は実行中のファイルパスを基準にrequireするのに便利ですが、
このKernel.#evalと組み合わせることはできません。
evalが評価する文字列の中でrequire_relativeを呼び出すと以下のような例外が発生し、
必ず失敗します。

lang

1eval <<EOS 2 require_relative 'foo' # LoadError: cannot infer basepath 3EOS

require_relative相当のことをしたい場合には、_FILE_ と組み合わせて以下の
ような方法でrequireすることができます。
このとき、_FILE_は eval の第3引数に渡したファイルパスを返します。

lang

1eval <<EOS, nil, '/path/to/fname.rb' 2 require File.expand_path('foo', File,dirname(_FILE_)) 3EOS

標準添付ライブラリの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 を作成しました。

lang

1x = eval <<EOS, nil, '/home/ykt68/perfectruby/ch03/require_eval_test.rb' 2 require File.expand_path('inc', File.dirname(__FILE__)) 3EOS 4 5puts 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拝

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

まず、文中の「・・・requireすることができます。」というのは、

・ evalで評価したい文字列となる、Rubyスクリプトを書く。
・ それを別のrubyスクリプトから require で読み込んでevalに渡す。
・ evalによって、requireで読み込まれたrubyスクリプトを評価する。

ということが出来るという意味と解釈しました。
(そもそも、この解釈が間違っているということでしたら、ぜひご指摘ください。)

はい。間違っています。
evalrequireを実行できる」(evalrequire_relative相当を実行できる)
というだけです。

lang

1eval <<EOS, nil, '/path/to/fname.rb' 2 require File.expand_path('foo', File,dirname(_FILE_)) 3EOS

は、

lang

1 require File.expand_path('foo', File,dirname(_FILE_))

と同じです。

inc.rbの中身を実行して値を得たいのなら、

lang

1x = eval IO.read("inc.rb") 2puts x

投稿2015/04/23 12:36

otn

総合スコア84551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun68ykt

2015/04/25 08:52

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

0

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

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

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

投稿2015/04/23 09:02

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun68ykt

2015/04/25 08:50

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問