5707


eachを使ってerb側で作成したパラメータ"car1", "car2",
...に対応する変数を、同じくeachを使ってRuby側で作成して代入したい場合には、どうすればよいでしょうか。  
最終的には、

[code]

    varcar1 = params[:car1]
    varcar2 = params[:car2]...
    
[/code]

と続く形にしたいです。

[code]

    (1..cars).each do |i|
      "varcar#{i} = params[:car#{i}]"
    end
    
[/code]

としてみたところ、変数varcarを作る段階ではエラーになりませんが、変数を使おうとするとエラーになります。

[code]

    undefined method `join' for #<String:0x53925f0> 
    
[/code]

全体を文字列にしているところが問題なのだと思いますが、"#{i}"とすると作成段階のエラーになります。

[code]

     syntax error, unexpected tSTRING_BEG, expecting keyword_end
     syntax error, unexpected '=', expecting keyword_end
     syntax error, unexpected tSTRING_BEG, expecting ']'
    
[/code]

この場合、どのようにすればよいでしょうか。  
よろしくお願いします。


CC BY-SA 3.0
2015-02-01T12:38:46.830
5702
2015-02-02T02:39:29.450
7870
question
ruby sinatra
eachで作成したパラメーターをそれぞれの変数に代入する方法


個人的には先に配列 `varcar = []` を作って

[code]

    varcar[1] = params[:car1]
    varcar[2] = params[:car2]...
    
[/code]

とすると思いますが、それはともかくとして。

# 前提条件1：スコープ

まず、（ `Enumerable#each`
に続く）ブロック内で初めて出てきた（生成された）ローカル変数をブロック外で使うことは出来ません。ローカル変数のスコープがブロック内に限られるためです。

# 前提条件2：`Kernel#eval`

ブロック内に書かれた

[code]

    "varcar#{i} = params[:car#{i}]"
    
[/code]

では単なる文字列ですので、文字列として扱われるだけです。文字列の内容を実行するには `Kernel#eval` などのいわゆる eval
族を使う必要があります。つまり

[code]

    (1..cars).each do |i|
      eval("varcar#{i} = params[:car#{i}]")
    end
    
[/code]

とすれば（ブロック内の）ローカル変数が生成できます。

# 本編：ご希望の内容の実現は不可能

前提条件2の `Kernel#eval` を用いてブロック内に `varcar1, varcar2`
を作れたとしても、残念ながらそのローカル変数は前提条件1によりブロックのスコープを越えることが出来ません。  
なお、以下の参考のところに記載されているように、インスタンス変数 `@varcar1, @varcar2` であれば `eval` を使ったり
`instance_variable_set` メソッドを使ったりして作成できます。  
参考：

  * [Rubyで連番の変数を動的に作成 | EasyRamble](http://easyramble.com/ruby-dynamic-variables.html)
  * [無題メモランダム: Rubyで変数を動的に取得/設定する方法](http://blog.mudaimemo.com/2009/12/ruby.html)
  * [備忘録的なblog: rubyのリフレクション](http://se-bikou.blogspot.jp/2011/08/rubyeval.html)

また、

> ローカル変数はスクリプトコンパイル時に静的に決まるので、evalでローカル変数を設定することは出来ません。

（[Ruby 逆引きハンドブック](http://www.c-r.com/book/detail/705) るびきち著
p.653。なお、書籍としての対応バージョンは 1.9 までです）

という記載も見かけました。

# おまけ：`for` や `while` では？

`for` はブロックスコープを作らないので、内外の問題が生じない、とよく言われます（例えば [Rubyではfor
whileなどで新たなスコープは生成されない -
プログラマ憧れプログラマ日記](http://nobyu.hatenadiary.jp/entry/20090104/1231081726) ）。  
ので私も `for` や `while` で解決できるのではないかと思ったのですが、残念ながらダメでした。

[code]

    for i in [*1..3]
      eval("a#{i} = i; print a#{i}")  
    end  
    #=> 123
    
    a1
    #=> NameError: undefined local variable or method `a1' for main:Object
    
    i = 0
    while i <= 3
      eval("a#{i} = i; print a#{i}")  
      i += 1  
    end  
    #=> 123
    
    a1
    #=> NameError: undefined local variable or method `a1' for main:Object
    
[/code]

ブロック内で `print` すれば出力できることから、ブロック内でローカル変数が生成出来ていることが分かります。  
しかしブロック外でローカル変数を呼び出すと、 Ruby 1.9.3でも2.2.0でも NameError
でした。つまり「そんな変数/メソッドは知らん」。スコープ外であることが分かります。


CC BY-SA 3.0
2015-02-01T13:21:25.340
5707
2015-02-02T02:39:29.450
2020-06-17T08:14:45.997
-1
4114
5702
answer