2009-10-15 29 views
35

Si tengo esta clase:¿Hay alguna manera de inicializar un objeto mediante un hash?

class A 
    attr_accessor :b,:c,:d 
end 

y este código:

a = A.new 
h = {"b"=>10,"c"=>20,"d"=>30} 

es posible inicializar el objeto directamente a partir del hash, sin mí tener que pasar sobre cada par y llame instance_variable_set? Algo así como:

a = A.new(h) 

que debería hacer que cada variable de instancia para inicializar a la que tiene el mismo nombre en el hash.

Respuesta

50

Se puede definir una función de inicialización en su clase:

class A 
    attr_accessor :b,:c,:d 
    def initialize(h) 
    h.each {|k,v| public_send("#{k}=",v)} 
    end 
end 

O puede crear un módulo y luego "se mezcla en"

module HashConstructed 
def initialize(h) 
    h.each {|k,v| public_send("#{k}=",v)} 
end 
end 

class Foo 
include HashConstructed 
attr_accessor :foo, :bar 
end 

alternativa, se puede intentar algo así como constructor

+3

+1. Por cierto, es posible que desee considerar el uso de 'public_send' en lugar de' send' para evitar llamar escritores de atributos privados :) – epidemian

+1

+1 para el constructor gem –

8

instance_variable_set es para este tipo de caso de uso:

class A 
    def initialize(h) 
    h.each {|k,v| instance_variable_set("@#{k}",v)} 
    end 
end 

Es un método público, por lo que también podría llamarlo después de la construcción:

a = A.new({}) 
a.instance_variable_set(:@foo,1) 

Pero tenga en cuenta la advertencia implícita en el documentation:

Establece los nombres de las variables de instancia por el símbolo de objeto , frustrando así los esfuerzos del autor de la clase para tratar de proporcionar una encapsulación adecuada. La variable no tenía que existir antes de esta llamada.

+1

Para mí, la comprobación para asegurarse de que solo puede establecer los especificados en la definición es bastante importante, lo que hace que esta sugerencia sea indigna –

10

OpenStruct la pena considerar:

require 'ostruct' # stdlib, no download 
the_hash = {"b"=>10, "c"=>20, "d"=>30} 
there_you_go = OpenStruct.new(the_hash) 
p there_you_go.C#=> 20 
+1

¡Sí! Y también puedes convertir JSON a OpenStruct, lo cual es bueno. 'JSON.parse ({a: 1, b: 2} .to_json, object_class: OpenStruct)' –

Cuestiones relacionadas