Rubyメタプログラミング:動的インスタンス変数名


94

次のハッシュがあるとしましょう:

{ :foo => 'bar', :baz => 'qux' }

オブジェクトのインスタンス変数になるようにキーと値を動的に設定するにはどうすればよいですか...

class Example
  def initialize( hash )
    ... magic happens here...
  end
end

...モデル内で次のようになる...

@foo = 'bar'
@baz = 'qux'

回答:


168

あなたが探している方法はinstance_variable_setです。そう:

hash.each { |name, value| instance_variable_set(name, value) }

または、もっと簡単に言えば、

hash.each &method(:instance_variable_set)

(OPの例にあるように)インスタンス変数名に「@」がない場合は、それらを追加する必要があるため、次のようになります。

hash.each { |name, value| instance_variable_set("@#{name}", value) }

18
1.9.3では動作しませんでした。私はこれを代わりに使用しましたhash.each {|k,v| instance_variable_set("@#{k}",v)}
Andrei

3
Rubyを愛するもう1つの理由
jschorr 2013年

hash.each &method(:instance_variable_set)では、メソッドinstance_variable_setが必要な2つのパラメータをどのように受け取るかを説明できますか?
Arnold Roa

これを再帰的に行う方法はありますか?(入力ハッシュに複数のレベルがある場合)
nemenems

13
h = { :foo => 'bar', :baz => 'qux' }

o = Struct.new(*h.keys).new(*h.values)

o.baz
 => "qux" 
o.foo
 => "bar" 

1
それはかなり興味深いです... 2番目のチェーンが正確に何をし.new()ているのですか?
Andrew

3
@Andrew:Struct.newハッシュキーに基づいて新しいクラスを作成し、次に2番目のnewクラスは、作成されたばかりのクラスの最初のオブジェクトを作成し、それをハッシュの値に初期化します。ruby-doc.org/core-1.8.7/classes/Struct.htmlを
DigitalRoss

2
これはStructの目的のために行われるものであるため、実際には非常に優れた方法です。
Chuck

2
またはOpenStructを使用しますrequire 'ostruct'; h = {:foo => 'foo'}; o = OpenStruct.new(h); o.foo == 'foo'
ジャスティンフォース

私はキーを記号にマッピングする必要がありました:Struct.new(*hash.keys.map { |str| str.to_sym }).new(*hash.values)
erran

7

あなたは私たちを泣かせたいと思っています:)

いずれの場合でも、Object#instance_variable_getおよびを参照してくださいObject#instance_variable_set

ハッピーコーディング。


ええ、私は疑問に思わずにはいられませんでした...なぜですか?これを使用する良いタイミングはいつですか?
ザック・スミス

たとえば、set_entityすべてのコントローラーにジェネリックコールバックを設定し、既存のインスタンス変数に干渉したくない場合がありますdef set_entity(name, model); instance_variable_set(name, model.find_by(params[:id])); end;
user1201917

5

を使用しsendて、ユーザーが存在しないインスタンス変数を設定できないようにすることもできます。

def initialize(hash)
  hash.each { |key, value| send("#{key}=", value) }
end

sendクラスにattr_accessorインスタンス変数のようなセッターがある場合に使用します。

class Example
  attr_accessor :foo, :baz
  def initialize(hash)
    hash.each { |key, value| send("#{key}=", value) }
  end
end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.