2009-10-15 4 views
35

Если у меня есть этот класс:Есть ли способ инициализировать объект через хэш?

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

и этот код:

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

является возможность инициализировать объект непосредственно из хэша, без меня необходимости идти по каждой паре и называть instance_variable_set? Что-то вроде:

a = A.new(h) 

, который должен привести к каждой переменной экземпляра для инициализации на тот, который имеет такое же имя в хэш.

ответ

50

Вы можете определить функцию инициализации вашего класса:

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

Или вы можете создать модуль, а затем «смешать его в»

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

class Foo 
include HashConstructed 
attr_accessor :foo, :bar 
end 

В качестве альтернативы вы можете попробовать что-то вроде constructor

+3

+1. BTW, вы можете захотеть использовать 'public_send' вместо' send', чтобы избежать вызова частных писателей атрибутов :) – epidemian

+1

+1 для конструктора gem –

8

instance_variable_set предназначен для такого использования:

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

Это публичный метод, так что вы могли бы также назвать его после окончания строительства:

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

Но обратите внимание на подразумеваемое предупреждение в documentation:

Задает имена переменных экземпляра с помощью символа объекта , тем самым расстраивая попытки автора класса попытаться обеспечить надлежащую инкапсуляцию. Перед этим вызовом переменная не должна существовать.

+1

Для меня проверка на то, что вы можете установить только те, которые указаны в определении, довольно что делает это предложение недостойным –

10

OpenStruct стоит задуматься:

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

Да! И вы также можете конвертировать JSON в OpenStruct, что приятно. 'JSON.parse ({a: 1, b: 2} .to_json, object_class: OpenStruct)' –

Смежные вопросы