Pregunta

quiero hacer lo siguiente:

Quiero declarar las variables de instancia de una clase en iteración sobre un diccionario.

Supongamos que tengo este hash

hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}

y quiero tener cada clave como variable de instancia de una clase. Quiero saber si puedo declarar las variables iterando sobre ese hash. Algo como esto:

class MyClass
  def initialize()
    hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
    hash.each do |k,v|
      @k = v
    end
  end
end

¡Sé que esto no funciona! Solo coloco este fragmento de código para ver si puedes entender lo que quiero más claramente.

¡Gracias!

¿Fue útil?

Solución

class MyClass
  def initialize()
    hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
    hash.each do |k,v|
      instance_variable_set("@#{k}",v)
      # if you want accessors:
      eigenclass = class<<self; self; end
      eigenclass.class_eval do
        attr_accessor k
      end
    end
  end
end

El eigenclass es una clase especial que pertenece a un solo objeto, por lo que los métodos definidos serán métodos de instancia de ese objeto, pero no pertenecerán a otras instancias de la clase normal del objeto.

Otros consejos

class MyClass
  def initialize
    # define a hash and then
    hash.each do |k,v|
      # attr_accessor k # optional
      instance_variable_set(:"@#{k}", v)
    end
  end
end

La respuesta de Chuck es mejor que mis dos últimos intentos. El eigenclass no es self.class como lo había pensado; Me tomó una mejor prueba de la que había escrito para darme cuenta de esto.

Usando mi código anterior, probé de la siguiente manera y descubrí que la clase fue manipulada y no la instancia:

a = MyClass.new :my_attr => 3
b = MyClass.new :my_other_attr => 4

puts "Common methods between a & b:"
c = (a.public_methods | b.public_methods).select { |v| a.respond_to?(v) && b.respond_to?(v) && !Object.respond_to?(v) }
c.each { |v| puts "    #{v}" }

La salida fue:

Common methods between a & b:
    my_other_attr=
    my_attr
    my_attr=
    my_other_attr

Esto claramente refuta mi presuposición. Mis disculpas, Chuck, todos ustedes estaban en todo momento.

Respuesta anterior:

attr_accessor solo funciona cuando se evalúa en una definición de clase, no la inicialización de una instancia. Por lo tanto, el único método para hacer directamente lo que quiere es usar instance_eval con una cadena:

class MyClass
  def initialize(params)
    #hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
    params.each do |k,v|
      instance_variable_set("@#{k}", v)
      instance_eval %{
        def #{k}
          instance_variable_get("@#{k}")
        end
        def #{k}= (new_val)
          instance_variable_set("@#{k}", new_val)
        end
      }
    end
  end
end

Para probar este intento:

c = MyClass.new :my_var => 1
puts c.my_var

http://facets.rubyforge.org/apidoc/api /more/classes/OpenStructable.html

  

OpensStructable es un módulo mixin   que puede proporcionar comportamiento OpenStruct   a cualquier clase u objeto. OpenStructable   Permite la extensión de objetos de datos con   Atributos arbitrarios.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top