【问题标题】:Update Ruby class attributes hash when a property changes属性更改时更新 Ruby 类属性哈希
【发布时间】:2011-03-16 10:51:56
【问题描述】:

我正在尝试编写一个 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 来做到这一点,但这对于一个有很多字段的模型来说会很糟糕。有什么快速的方法可以做到这一点?

【问题讨论】:

  • 在您的initialize 方法中,您不需要使用send 设置属性。只需更新 @attributes 哈希即可。 attributes= 方法也是如此。
  • 我觉得这很常见,有人可以把它变成一个简单的宝石。

标签: ruby metaprogramming abstract-class class-attributes


【解决方案1】:

问题是您将属性作为单独的 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 你可以找到一篇关于实现访问器的好文章。

【讨论】:

  • 听起来很酷。你介意写一些关于我如何做这一切的代码建议吗?谢谢
  • 我说明了第一种方法,剩下的留给你练习……;)
  • 太棒了,这正是我需要的。
猜你喜欢
  • 2021-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 2013-08-18
  • 1970-01-01
  • 2020-02-11
相关资源
最近更新 更多