当属性更改时更新 Ruby 类属性哈希

发布于 2024-09-10 15:58:32 字数 1403 浏览 9 评论 0原文

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

I'm trying to write a Ruby class that works similarly to Rails AactiveRecord model in the way that attributes are handled:

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

What I mean is that when I init the class, an "attributes" hash is updated with the relevant attributes:

>>> p = Person.new(:name => 'John', :age => 30)
>>> p.attributes
 => {:age=>30, :name=>"John"}
>>> p.attributes = { :name => 'charles' }
>>> p.attributes
 => {:age=>30, :name=>"charles"}

So far so good. What I want to happen is for the attributes hash to update when I set an individual property:

>>> 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"}

I could do that by writing a setter and getter for every attribute instead of using attr_accessor, but that'll suck for a model that has a lot of fields. Any quick way to accomplish this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦境 2024-09-17 15:58:32

问题是您将属性保存为单独的 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 应该是“属性”,并在 attribute 方法中使用该列表。 attributes 方法会动态创建它们的哈希值,然后返回它。

在这里您可以找到一篇关于实现访问器的好文章。

The problem is that you keep your attributes both as separate ivars, and within a @attributes hash. You should choose and use only one way.

If you want to use a hash, you should make your own way of creating accessors, which would "reroute" them to a single method which would set and get from a hash:

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"}>

If you want to use ivars, you should, again, roll your own attr_accessor method which would, in addition, remember which ivars should be "attributes", and use that list in attributes method. And attributes method would create a hash out of them on-the-fly, and return it.

Here you can find a nice article about implementing accessors.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文