- 更新日: 2014年4月18日
- Ruby
Rubyで連番の変数を動的に作成
Rubyで(というかRailsのRSpecテストで)、連番を振った変数を動的に作成したい機会があったのですけど、Rubyの知識不足でちょっとはまったので備忘録。
eval 内の評価によるローカル変数のスコープはブロックの場合と同じ
原因は以下の引用による部分。
expr の中のローカル変数の扱いはブロックの場合と同じです。すなわち、eval 実行前に補足されていた変数は eval 実行後にブロック外に持ち出せます。
いきなり動的に変数を宣言して代入する場合。ここでは、eval で動的に name という変数を宣言し “taka” という値を代入しています。
1 2 3 4 5 6 7 8 9 |
pry(main)> var = "name" => "name" pry(main)> value = "taka" => "taka" pry(main)> eval("#{var} = value") => "taka" pry(main)> name NameError: undefined local variable or method `name' for main:Object from (pry):4:in `__pry__' |
eval を抜けた後に、name を参照しようとするとエラーになる。
name という変数を先に宣言しておき、その後 eval で動的に代入する場合。
1 2 3 4 5 6 7 8 9 10 |
pry(main)> name = nil => nil pry(main)> var = "name" => "name" pry(main)> value = "taka" => "taka" pry(main)> eval("#{var} = value") => "taka" pry(main)> name => "taka" |
こうすると、eval を抜けた後に name を参照できます。引用したドキュメントの通りの挙動です。しかし、この方法は動的に代入するための変数を先に宣言しなきゃならないので、連番の変数をたくさん作る場合はあまり旨みがない…。
インスタンス変数を動的に作成する
ということで、インスタンス変数を使いました。
1 2 3 4 5 6 7 8 |
pry(main)> var = "@name" => "@name" pry(main)> value = "taka" => "taka" pry(main)> eval("#{var} = value") => "taka" pry(main)> @name => "taka" |
変数名に @ を付けてインスタンス変数を動的に作成すると、先に宣言しなくても変数のスコープが広がり eval を抜けた後も参照できます。ただし、利用するコンテキストで他のインスタンス変数と被らないようになど配慮が必要になる。
以下、pry で0〜9まで連番を振ったインスタンス変数を動的に作成する例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
pry(main)> 10.times do |i| pry(main)* var = "@name#{i}" pry(main)* value = "no#{i}" pry(main)* eval("#{var} = value") pry(main)* end => 10 pry(main)> @name1 => "no1" pry(main)> @name5 => "no5" pry(main)> 10.times do |i| pry(main)* puts eval("@name#{i}") pry(main)* end no0 no1 no2 no3 no4 no5 no6 no7 no8 no9 => 10 |
以上です。if, while, for などと同様に、Rubyで変数のスコープにちょっと注意しないといけないケースですね。
- – 参考リンク –
- 無題メモランダム: Rubyで変数を動的に取得/設定する方法
- 備忘録的なblog: rubyのリフレクション
- Rubyの動かないコード (中級編) ローカル変数の「暗黙の初期化」に関するエラー(ローカル変数のスコープが事前コンパイルで決まる) – 主に言語とシステム開発に関して
- Ruby の関連記事
- Gemの作り方(Ruby Gem)
- ローカル開発中のgemをGemfileに書いてインストール
- 熊本地震の余震が夜に多いのは本当か?Rubyプログラムで検証してみた
- El Capitanでgemのnative extensionビルド失敗に対応
- Rubyで親クラスから子クラスの定数を参照
- MacabをRubyで使う
- rbenv/ruby-buildでRuby最新バージョンをインストール
- Rubyでクラスインスタンス変数にインスタンスメソッドからアクセス
- 距離1kmあたりの緯度・経度の度数を計算(日本・北緯35度)
- Google Maps Geocoding APIで住所から緯度・経度を取得するRubyコード
Leave Your Message!