2011-07-19 21 views
77

Powiedzmy mam następujący skrót:Ruby metaprogramowanie: dynamiczna instancji nazwy zmiennych

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

Jak mogę dynamicznie zestaw kluczy i wartości stają się zmienne instancji w obiekcie ...

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

... tak, że kończę w następujący sposób wewnątrz modelu ...

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

?

Odpowiedz

145

Metoda, której szukasz, to instance_variable_set. Więc:

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

Albo, bardziej krótko

hash.each &method(:instance_variable_set) 

Jeśli instancji nazwy zmiennych brakuje „@” (ponieważ są one w przykładzie PO jest), musisz je dodawać, więc byłoby więcej takich jak:

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

Doskonały, dzięki! – Andrew

+15

Nie działa dla mnie dla 1.9.3. Użyłem tego zamiast 'hash.each {| k, v | instance_variable_set ("@ # {k}", v)} ' – Andrei

+0

Sooo, to świetnie! –

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

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

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

To jest całkiem interesujące ... co dokładnie robi drugi łańcuch ".new()"? – Andrew

+2

@Andrew: 'Struct.new' tworzy nową klasę na podstawie kluczy skrótu, a następnie drugi' nowy' tworzy pierwszy obiekt właśnie stworzonej klasy, inicjalizując ją wartościami skrótu. Zobacz http://www.ruby-doc.org/core-1.8.7/classes/Struct.html – DigitalRoss

+2

Jest to naprawdę świetny sposób na zrobienie tego, ponieważ jest to właściwie to, do czego służy Struct. – Chuck

4

można również użyć send który zapobiega użytkownikowi ustawienie nieistniejącego instancji zmienne:

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

Stosować send gdy w klasie jest seter jak attr_accessor dla zmiennych instancji:

class Example 
    attr_accessor :foo, :baz 
    def initialize(hash) 
    hash.each { |key, value| send("#{key}=", value) } 
    end 
end 
Powiązane problemy