Rubyでローカル変数を動的に設定することに興味があります。メソッド、定数、またはインスタンス変数を作成しません。
だから次のようなもの:
args[:a] = 1
args.each_pair do |k,v|
Object.make_instance_var k,v
end
puts a
> 1
問題のメソッドがモデル内に存在し、グローバル空間またはオブジェクト空間を汚染したくないため、特にローカル変数が必要です。
Rubyでローカル変数を動的に設定することに興味があります。メソッド、定数、またはインスタンス変数を作成しません。
だから次のようなもの:
args[:a] = 1
args.each_pair do |k,v|
Object.make_instance_var k,v
end
puts a
> 1
問題のメソッドがモデル内に存在し、グローバル空間またはオブジェクト空間を汚染したくないため、特にローカル変数が必要です。
将来の読者のための追加情報として、ruby 2.1.0以降、以下を使用できbinding.local_variable_get
ますbinding.local_variable_set
。
def foo
a = 1
b = binding
b.local_variable_set(:a, 2) # set existing local variable `a'
b.local_variable_set(:c, 3) # create new local variable `c'
# `c' exists only in binding.
b.local_variable_get(:a) #=> 2
b.local_variable_get(:c) #=> 3
p a #=> 2
p c #=> NameError
end
ドキュメントに記載されているように、これは
binding.eval("#{symbol} = #{obj}")
binding.eval("#{symbol}")
ここでの問題は、each_pair内のブロックのスコープが異なることです。そこに割り当てられたローカル変数は、そこにのみアクセスできます。たとえば、これは次のとおりです。
args = {}
args[:a] = 1
args[:b] = 2
args.each_pair do |k,v|
key = k.to_s
eval('key = v')
eval('puts key')
end
puts a
これを生成します:
1
2
undefined local variable or method `a' for main:Object (NameError)
これを回避するには、ローカルハッシュを作成し、このハッシュにキーを割り当てて、次のようにアクセスします。
args = {}
args[:a] = 1
args[:b] = 2
localHash = {}
args.each_pair do |k,v|
key = k.to_s
localHash[key] = v
end
puts localHash['a']
puts localHash['b']
もちろん、この例では、キーの文字列を含む元のハッシュをコピーしているだけです。ただし、実際のユースケースはもっと複雑だと思います。
興味深いことに、ローカル変数を変更することはできますが、設定することはできません。
def test
x=3
eval('x=7;')
puts x
end
テスト=>7
def test
eval('x=7;')
puts x
end
test => NameError:main:Objectの未定義のローカル変数またはメソッド `x'
これが、DorkusPrimeのコードが機能する唯一の理由です。
ハッシュを使用することをお勧めします(ただし、他の選択肢については読み続けてください)。
なんで?
任意の名前付き引数を許可すると、コードが非常に不安定になります。
foo
これらの理論上の名前付き引数を受け入れたいメソッドがあるとしましょう。
シナリオ:
呼び出されたメソッド( )は、引数をとらないfoo
プライベートメソッド(呼び出しましょう)を呼び出す必要があります。ローカル変数に格納したいbar
引数を渡すと、メソッドがマスクされます。回避策は、を呼び出すときに明示的な括弧を使用することです。foo
bar
bar
bar
foo
のコードがローカル変数を割り当てているとしましょう。ただし、呼び出し元は、そのローカル変数と同じ名前の引数を渡すことにします。割り当ては引数を覆い隠します。
基本的に、メソッドの呼び出し元は、メソッドのロジックを変更できないようにする必要があります。
代替案
別の中間点にはが含まれOpenStruct
ます。ハッシュを使用するよりもタイピングが少なくて済みます。
require 'ostruct'
os = OpenStruct.new(:a => 1, :b => 2)
os.a # => 1
os.a = 2 # settable
os.foo # => nil
OpenStruct
存在しないメンバーにアクセスできることに注意してください-が返されますnil
。より厳密なバージョンが必要な場合は、Struct
代わりに使用してください。
これにより、匿名クラスが作成され、クラスがインスタンス化されます。
h = {:a=>1, :b=>2}
obj = Struct.new(* h.keys).new(* h.values)
obj.a # => 1
obj.a = 2 # settable
obj.foo # NoMethodError
定数が必要ないので
args = {}
args[:a] = 1
args[:b] = 2
args.each_pair{|k,v|eval "@#{k}=#{v};"}
puts @b
2
このアプローチは興味深いと思うかもしれません(適切なコンテキストで変数を評価してください)
fn="b*b"
vars=""
args.each_pair{|k,v|vars+="#{k}=#{v};"}
eval vars + fn
4