Ruby Metaprogramming: nombres de variables de instancia dinámicas


Digamos que tengo el siguiente hash:

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

¿Cómo podría configurar dinámicamente las claves y los valores para que se conviertan en variables de instancia en un objeto?..

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

... así que termino con lo siguiente dentro del modelo...

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

?

Author: Andrew, 2011-07-19

4 answers

El método que está buscando es instance_variable_set. Entonces:

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

O, más brevemente,

hash.each &method(:instance_variable_set)

Si a los nombres de las variables de instancia les falta el " @ " (como en el ejemplo del OP), tendrá que agregarlos, por lo que sería más como:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-19 02:54:49

Haces que queramos llorar:)

En cualquier caso, ver Object#instance_variable_get y Object#instance_variable_set.

Feliz codificación.

 6
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-19 02:20:16

También puede usar send que evita que el usuario establezca variables de instancia inexistentes:

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

Use send cuando en su clase haya un setter como attr_accessor para sus variables de instancia:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 13:11:32