我正在尝试编写一个 Ruby 类,它在处理属性的方式上类似于 Rails AactiveRecord 模型:
class Person
attr_accessor :name, :age
# init with Person.new(:name => 'John', :age => 30)
def initialize(attributes={})
attributes.each { |key, val| send("#{key}=", val) if respond_to?("#{key}=") }
@attributes = attributes
end
# read attributes
def attributes
@attributes
end
# update attributes
def attributes=(attributes)
attributes.each do |key, val|
if respond_to?("#{key}=")
send("#{key}=", val)
@attributes[key] = name
end
end
end
end
我的意思是,当我初始化类时,“属性”散列会使用相关属性进行更新:
>>> p = Person.new(:name => 'John', :age => 30)
>>> p.attributes
=> {:age=>30, :name=>"John"}
>>> p.attributes = { :name => 'charles' }
>>> p.attributes
=> {:age=>30, :name=>"charles"}
到目前为止一切顺利。我想要发生的是在设置单个属性时更新属性散列:
>>> p.attributes
=> {:age=>30, :name=>"John"}
>>> p.name
=> "John"
>>> p.name = 'charles' # <--- update an individual property
=> "charles"
>>> p.attributes
=> {:age=>30, :name=>"John"} # <--- should be {:age=>30, :name=>"charles"}
我可以通过为每个属性编写一个 setter 和 getter 而不是使用 attr_accessor
来做到这一点,但这对于一个有很多字段的模型来说会很糟糕。有什么快速方法可以做到这一点?
最佳答案
问题是您将属性作为单独的 ivar 保存在 @attributes
散列中。您应该只选择和使用一种方式。
如果你想使用散列,你应该用自己的方式创建访问器,这会将它们“重新路由”到一个单一的方法,该方法将设置并从散列中获取:
class Class
def my_attr_accessor(*accessors)
accessors.each do |m|
define_method(m) do
@attributes[m]
end
define_method("#{m}=") do |val|
@attributes[m]=val
end
end
end
end
class Foo
my_attr_accessor :foo, :bar
def initialize
@attributes = {}
end
end
foo = Foo.new
foo.foo = 123
foo.bar = 'qwe'
p foo
#=> #<Foo:0x1f855c @attributes={:foo=>123, :bar=>"qwe"}>
如果你想使用 ivars,你应该再次推出你自己的 attr_accessor
方法,此外,它会记住哪些 ivars 应该是“属性”,并在 中使用该列表属性
方法。 attributes
方法会即时创建一个散列,并返回它。
Here您可以找到一篇关于实现访问器的好文章。
关于ruby - 当属性更改时更新 Ruby 类属性散列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3256531/