На самом деле severin
есть лучшая идея, просто потому, что использование method_missing - плохая практика, не всегда, но в большинстве случаев.
Одна проблема с этим кодом, предоставленным severin
: он возвращает значение, которое было передано инициализатору, поэтому вы не можете его изменить. Я предлагаю вам немного другой подход:
class User < Hash
def initialize(attrs)
attrs.each do |k, v|
self[k] = v
end
end
def []=(k, v)
unless respond_to?(k)
self.class.send :define_method, k do
self[k]
end
end
super
end
end
Давайте проверим:
u = User.new(:name => 'John')
p u.name
u[:name] = 'Maria'
p u.name
А также вы можете сделать это с помощью Struct:
attrs = {:name => 'John', :age => 22, :position => 'developer'}
keys = attrs.keys
user = Struct.new(*keys).new(*keys.map { |k| attrs[k] })
Давайте проверим это:
p user
p user.name
user[:name] = 'Maria'
p user.name
user.name = 'Vlad'
p user[:name]
Или даже OpenStruct, но будьте осторожны, он не создаст метод, если он уже есть в методах экземпляра, вы можете найти это с помощью OpenStruct.instance_methods
(из-за типа используется, я сейчас использую второй подход):
attrs = {:name => 'John', :age => 22, :position => 'developer'}
user = OpenStruct.new(attrs)
Да, так просто:
user.name
user[:name] # will give you an error, because OpenStruct isn't a Enumerable or Hash