• ベストアンサー

Ruby evalで代入

#!/usr/bin/ruby str='hoge="abc"' eval(str) puts hoge 上記実行の結果エラーになってしまいますが、 evalを使って変数に代入するの方法ってあるのですか?

質問者が選んだベストアンサー

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

結論から言うと、#1の回答にあるようにevalの前に代入を行うという 手段をとりたくないというのであれば、方法はありません。 なぜなら、eval の引数はその中で閉じた世界になっているので、 そこで初めて出現した変数(質問の例で言えば hoge)は、evalを終えたところで その寿命が尽きて消えてなくなるので、eval後に参照してもすでに存在していないので エラーになるというわけです。 irb でエラーにならないのは、irb自体がRubyスクリプトであり 通常の解釈とは微妙に異なる点があるためです。 Ruby認定試験対策問題 http://projects.netlab.jp/ruby-test/index.html Ruby認定試験対策問題 解答 http://projects.netlab.jp/ruby-test/answers.html の、1.4.3の解説を参照してください。 何のためにそういうことをしたいのかを説明してもらえれば、代替策を 提示できるかもしれません。

kingfruits
質問者

補足

ご回答ありがとうございます。 >何のためにそういうことをしたいのかを説明してもらえれば、代替策を >提示できるかもしれません。 #!/usr/bin/ruby class Foo def g "g" end def p "p" end end f=Foo.new str="g" eval("ret=f.#{str}") puts ret 上記の様に、変数strの内容によってメソッドを変える式を条件分岐文を使わずに書きたかったのですが、以下の様に書けばよいのかと。 ret=eval("f.#{str}") ただ、この例だと、strに"g","p"以外を代入した際のキレイなエラー処理が知らなずでして。。

その他の回答 (5)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.6

ちょっとだけ改良 class Quux def g "g" end def p "p" end def call(fname) begin method(fname).call rescue NameError "#{fname}なんてメソッドないじゃないですか" end end end f = Quux.new puts "test #{f.class}" for fnc in %w[g n p] ret = f.call(fnc) puts ret end 実行例: test Quux g nなんてメソッドないじゃないですか p

kingfruits
質問者

お礼

大変参考になりました。ありがとうございます。

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.5

きれいなエラー処理ってのが具体的にどういうものなのか 思い浮かびませんが、こんなのではどうですか? #!/usr/bin/ruby -Ks class Foo def g "g" end def p "p" end def method_missing(arg) "#{arg} なんて呼んでんじゃねえぞゴルァ" end end class Bar def g "g" end def p "p" end def call(fname) if (@fnctable.has_key?(fname)) @fnctable[fname].call else "#{fname}なんてメソッドないよ" end end def initialize @fnctable = { 'p' => method(p), 'g' => method(g) } end end f = Foo.new puts "test #{f.class}" for fnc in %w[g n p] ret = eval("ret=f.#{fnc}") puts ret end f = Bar.new puts "test #{f.class}" for fnc in %w[g n p] ret = f.call(fnc) puts ret end 話すと長くなりますので書きませんが、evalは乱用しない方が いろいろ都合が良いので、できるだけ使わない方向で 考えてみるのも良いと思います。 上の、後のほうの例だと呼び出しが美しくないですけどね。 PerlとかPythonだと .call() とかつけんでもよいのですが。

回答No.3

>koko_u_さん 当方の検証でも,irbではエラーが出ません。

kingfruits
質問者

お礼

検証ありがとうございます。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.2

やってみたけど、エラーにならんかったよ。 irb>str='hoge="abc"' => "hoge=\"abc\"" irb>eval str => "abc" irb>puts hoge => "abc" とりあえず、環境と Ruby のバージョンを補足にどうぞ。 ちなみに上の結果は windowsXP Professional で Ruby のバージョンは 1.8.6 patchlevel 0

kingfruits
質問者

お礼

検証ありがとうございます。 irbでの検証は試してみませんでした。 irbでは動作が異なる事があるんですね。

回答No.1

http://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view;name=%A5%B9%A5%AF%A5%EA%A5%D7%A5%C8%B8%C0%B8%EC%A4%CE%C8%E6%B3%D3%3A%3Aeval 読んでも俺には良く解らなかったけど ruby 1.9.0 (2006-04-15)では hoge = ''; str = 'fuga'; str='hoge="abc";'; eval(str); puts hoge; という風に事前に一行加えたら代入されていることが確認できた。

kingfruits
質問者

お礼

ありがとうございます。 スコープの特性ってことなんですね。

関連するQ&A

専門家に質問してみよう