• ベストアンサー

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

  • rubyにおける変数と代入のメモリの様子について

    Rubyの変数と代入演算は、メモリについてどのような扱いになっているのでしょうか。2点ほど疑問電があります。 1点目:代入演算は変数にアドレスを渡しているのか RubyLifeのRuby入門のサンプルをみて学習していたところ疑問がわきました。 http://www.rubylife.jp/ini/var/index4.html を参照しながら示します。 str1 = "Tokyo" str2 = str1 str1 << ",Japan" とやるとstr1もstr2も"Tokyo,Japan"となることから、rubyでの代入演算はアドレスを代入してると考えました。 2点目:新しくオブジェクトを代入すると別メモリ領域において、そのアドレスを代入しているのか str1 = "Tokyo" str2 = str1 str1 = "Osaka" とやると、str1は"Osaka"、str2は"Tokyo"となります。 前述の参照渡と考えるとstr2も"Osaka"となっているはずですが違いました。 ここで解説に(引用はじめ) なお2つの変数が同じオブジェクトを指し示した後で、どちらかのオブジェクトに新しいオブジェクトを 代入した場合は、代入された変数が指し示すオブジェクトだけが変更されるだけです。(引用おわり) とあります。 このことをふまえると、新しいオブジェクトを変数に代入するというのは、別のメモリ領域をつくってデータを置いてから、そのアドレスを変数に代入している、と考えました。 これら2つの考えと実際の仕組みは一致しているのでしょうか、と言うのが質問です。 質問点をまとめると、Rubyにおいて変数に対して ・代入演算はアドレスを代入しているのか(Cでいうポインタの扱いなのか) ・新しいオブジェクトを代入するときには、新メモリ領域を作ってデータを入れてそのアドレスを代入しているのか という点です。 ついこの間はじめたばかりの初心者ですが、どうかご教授よろしくお願いいたします。

    • ベストアンサー
    • Ruby
  • rubyのevalのエラーを検知したい

    rubyでevalを実行した時、その文が、構文的に正しくない場合、実行時にエラーになりますが、これを、検知する方法はあるでしょうか。 begin eval("実行対象の文(構文エラーの可能性有り)") resucue ここが実行されることを期待したが、ここに制御が移りませんでした。 end

  • rubyがInternalServerError

    こんばんは。 自鯖にて初めてrubyを動かそうとしたところInternalServerError(500エラー)が帰ってきます。 まず、httpd.confに ---------------------- AddHandler cgi-script .cgi .rb ---------------------- と追加しました(このため.htaccessは作成しなくていいと思う)。 コマンドラインにて[which ruby][whereis ruby]を使い、[/usr/bin/ruby]にrubyがあることはわかるのですが、エラーが出てしまいます。 [test.rb] ---------------------- #!/usr/bin/ruby print "Content-type: text/html\n\n" print "test" ---------------------- 上記プログラムには755のパーミッションを与えています。 上記のフォルダにはCGI実行権が与えられています。 上記のフォルダではCGIはしっかりと動きます。 上記のプログラムはコマンドライン上[ruby test.rb]では動きます。 また、他のサイトもいろいろ調べましたが #!/usr/bin/env ruby #!ruby #!/usr/local/bin/ruby どのいパスでもエラーがでました。 解決方法を教えてください。 サーバ ---------------------- CentOS 5.4Final Apache 2.2.3 Ruby 1.8.5 ----------------------

  • evalの使い方 引数として式を与える

    引数として与えた式を、プログラム中で計算するようにしたいと思っています。 引数に変数を入れることはできないのでしょうか? 将来的には、ファイルを開いてそれぞれの、ファイルごとの定数を式に代入しようと考えています。 よろしくお願いします。 プログラム ################################### my $bb =2; my $str = $ARGV[0]; eval $str; print "$str\n"; 実行文 #################################### perl test.pl 2*3+\$bb 結果 #################################### 2*3+$bb 望んでいる結果 8

    • ベストアンサー
    • Perl
  • グローバル変数を使いたいのですが。【Ruby】

    #!/usr/bin/ruby -Ke (略) $hoge = input["hoge"] def aaa() (略) end def bbb() (略) end if input["hoge"] aaa() end bbb() このように関数bbbでhtmlのフォームの値hogeを利用して 関数aaaを実行させるプログラムですが、 関数bbbで使用した変数の値をaaaでも利用したいのですが、 よい方法はあるのでしょうか? グローバル変数を$hoge = input["hoge"]の後で $hoge=[]と定義すると、初期化されてしまい、 関数bbbの中でグローバル変数を定義しても駄目でした。

  • Ruby インスタンス変数@fooを持つClass Fooの中ので関数fooを呼ぶ

    #!/usr/bin/ruby def foo(arg) arg.upcase end def bar(arg) arg.upcase end class Foo attr_reader :foo def initialize(arg) @foo = foo(arg) #@foo = bar(arg)とすれば期待した結果が得られる end end f=Foo.new("hoge") puts f.foo 上記実行するとエラーになります。 Class Fooの中のでfooといえば、インスタンス変数@fooであって、関数のfooではないって事なのでしょうか。 インスタンス変数@fooを持つClass Fooの中ので関数fooを呼ぶことはできないのでしょうか?

  • rubyのファイルを実行できません。

     Debian(Woody)の環境です。 #find ./ -name ruby ./usr/bin/ruby ./usr/share/doc/ruby ./usr/doc/ruby ./usr/lib/ruby があり、/usr/binにrubyのファイルが確認できます。 $ruby -v ruby 1.6.7 (2002-03-19) [i386-linux] が出ます。pathが通っています。 $ ruby -e 'print "hello World\n"' で hello World もちゃんどでます。 しかし、vi hello.rbで、中には ------------------- #!/usr/bin/ruby print "Hello World!\n" --------------------- と、実行権-rwxr-xr-xにします。 %hello.rb では: bash: hello.rb: command not found が出て,実行できませんでした。 ファイルの中に、#!/usr/lib/rubyに代えてもおなじでした。  因みに %env で ... PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11 ... がでます。  アドバイスをよろしくお願いします。

    • 締切済み
    • CGI
  • /usr/local/bin/rubyを実行するには

    OSはFedora10を使っています。 /usr/local にRubyを展開し、以下のコマンドを入力しインストールしました。 cd /usr/local/ruby ./configure make make test sudo make install /usr/local/bin にrubyの実行ファイルがあるようなのですが、bashは /usr/bin を探索し、rubyが存在しないといいます。 /usr/local/bin/ruby が実行されるようにするにはどうすれば良いか教えて頂けないでしょうか。よろしくお願いします。

  • rubyのunlessで遊んでいたら

    Rubyのunlessで適当にプログラムをつくって遊んでいました。 01:a = 10 #aに10を代入 02:b = 20 #bに20を代入 03: 04:unless a > b 05: puts "aはbより大きくない" 06:else 07: puts "aはbより小さくない" 08:end 09:#unless文にはelsif節等がなく、条件項目を増やせないのでaとbの値が同じ場合は 10:#どうしようかと、これをif文で補おうとしました。 11:if a = b 12: puts "aとbは同じです" 13:end 14: 15:puts "a=#{a} b=#{b}" そもそも、aとbの値が同じでない場合11行目のifが実行されることは無いだろうと思っていたのですが実効結果は ↓ aはbより大きくない aはbと同じ a=20 b=20 という結果がでました。実行結果一行目の「aはbより大きくない」と出力されたのはプログラム4行目のunless文の返した結果だろうと理解できましたが、実行結果2行目のif文の結果である「aはbとおなじ」が出力されたのか、実行結果3行目でaとbの変数内を参照しておりますが、ここでどうしてaの値が20に変更されているのか、わかりません。 詳しい方いらっしゃいましたらご教授願います。

    • ベストアンサー
    • Ruby
  • Ruby

    #!/usr/local/bin/ruby class Foo def []=(x,y) print "Hello,",x,y,"!\n" end end bar = Foo.new bar["wor"] = "ld" 上記実行結果は Hello world! になるのですが、これが理解できません。 上手く説明してくれませんか?

専門家に質問してみよう