我正在尝试编写一个类似于Rails AactiveRecord模型的
Ruby类,其处理方式是:
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来做到这一点,但这会让一个有很多字段的模型很糟糕.有什么快速的方法来完成这个
解决方法
问题是您将属性保存为单独的ivars,并保存在@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”,并在attributes方法中使用该列表.而属性方法会在运行中创建一个哈希值并返回它.
Here你可以找到一篇关于实现访问器的好文章.