Metaprogramowanie Ruby: dynamiczne nazwy zmiennych instancji

Powiedzmy, że mam następujący hash:

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

Jak mogę dynamicznie ustawić klucze i wartości, aby stały się zmiennymi instancji w obiekcie...

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

... tak, że kończy się z następujących wewnątrz modelu...

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

?

Author: Andrew, 2011-07-19

4 answers

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

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

Lub, w skrócie,

hash.each &method(:instance_variable_set)

Jeśli w nazwach zmiennych instancji brakuje " @ " (tak jak w przykładzie OP), musisz je dodać, więc byłoby to bardziej jak:

hash.each { |name, value| instance_variable_set("@#{name}", value) }
 153
Author: Chuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-06 04:22:26
h = { :foo => 'bar', :baz => 'qux' }

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

o.baz
 => "qux" 
o.foo
 => "bar" 
 12
Author: DigitalRoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-19 02:54:49

You make we want to cry:)

W każdym razie patrz Object#instance_variable_get oraz Object#instance_variable_set.

Szczęśliwego kodowania.
 6
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-19 02:20:16

Możesz również użyć send, co uniemożliwia użytkownikowi ustawienie nieistniejących zmiennych instancji:

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

Użyj send, gdy w twojej klasie znajduje się setter attr_accessor dla zmiennych instancji:

class Example
  attr_accessor :foo, :baz
  def initialize(hash)
    hash.each { |key, value| send("#{key}=", value) }
  end
end
 5
Author: Asarluhi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-20 13:11:32