¡Declarando variables de instancia iterando sobre un hash!
-
06-07-2019 - |
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!
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.