DRY способ присвоить хэш-значения объекту
Я ищу элегантный способ присвоить значение, хранящееся внутри Hash, в ранее существовавшем объекте.
Чтобы быть ясным, если у меня есть объект, скажите obj с двумя атрибутами, скажем, именем и возрастом, я хочу присвоить эти значения, исходящие из хэша, без чего-то вроде:
obj.name = hash[:name]
obj.age = hash[:age]
Спасибо за внимание.
Simone
Ответы
Ответ 1
Лучшая ставка - это, вероятно, просто определить метод типа update_attributes
, который принимает хэш и делает это внутри метода экземпляра класса.
Расширяя то, что написано другими, и что вам кажется, я думаю, что ваш лучший выбор был бы следующим:
hash.keys.each do |key|
m = "#{key}="
obj.send( m, hash[key] ) if obj.respond_to?( m )
end
Это будет учитывать:
- не все атрибуты класса в хеше, и
- любое количество ключей в хэше (не только: имя и т.д.)
Ответ 2
Вот довольно простой в использовании шаблон, который я использую в течение многих лет:
{
first_name: "John",
last_name: "Smith",
...
}.each {|k, v| send("#{k}=", v)}
Ответ 3
Не знаю об элегантности, но вы можете сделать:
[:name, :age].each do |att|
obj.send("#{att}=", hash[att])
end
Ответ 4
Использование instance_variable_set
- это еще один вариант. Вот пример:
class Test; attr_accessor :name, :age; end
hash = {name: 'John', age: 52}
obj = Test.new
hash.each do |k,v|
obj.instance_variable_set("@#{k}".to_sym, v) # :name is converted to :@name
end
p obj # => #<Test:0x007fd8cbb75b00 @name="John", @age=52>
Единственный трюк в том, что instance_variable_set ожидает символ, начинающийся с @
, поэтому :@name
действителен, но :name
не является.
Ответ 5
obj.methods.grep(/[^!=]=$/).each {|attr| obj.send(attr, hash[attr]) }
Ответ 6
Вы можете напрямую вызвать метод assign_attributes для объекта.
obj.assign_attributes(hash)