如何在ruby中增强attr_访问器?

如何在ruby中增强attr_访问器?,ruby,attributes,metaprogramming,attr-accessor,Ruby,Attributes,Metaprogramming,Attr Accessor,我想实现一个(类)方法attr\u accessor\u with\u client\u reset,该方法的作用与attr\u accessor相同,但在每个writer上它都会额外执行 @client = nil 那么比如说, attr_accessor_with_client_reset :foo 应产生与相同的结果 attr_reader :foo def foo=(value) @foo = value @client = nil end 如何实现这一点?如果您有rub

我想实现一个(类)方法
attr\u accessor\u with\u client\u reset
,该方法的作用与
attr\u accessor
相同,但在每个writer上它都会额外执行

@client = nil
那么比如说,

attr_accessor_with_client_reset :foo
应产生与相同的结果

attr_reader :foo

def foo=(value)
  @foo = value
  @client = nil
end

如何实现这一点?

如果您有ruby元编程方面的一些经验,这实际上非常简单。看一看:

module Ext
  def self.included base
    base.extend ClassMethods
  end

  module ClassMethods
    def attr_accessor_with_client_reset name
      define_method name do
        instance_variable_get "@#{name}"
      end

      define_method "#{name}=" do |v|
        instance_variable_set "@#{name}", v
        @client = nil
      end
    end
  end

end

class Foo
  include Ext

  attr_reader :client
  def initialize
    @foo = 0
    @client = 'client'
  end

  attr_accessor_with_client_reset :foo
end

f = Foo.new
f.foo # => 0
f.client # => "client"
f.foo = 1
f.foo # => 1
f.client # => nil

如果您对这段代码不完全清楚,那么我强烈推荐这本书:。

塞尔吉奥的解决方案很好,但不必要复杂:不需要复制
attr\u reader
的行为,您只需委托它即可。不需要所有的双模块,包括hook黑客。另外,
attr\u访问器
具有多个名称,因此带有客户机重置的
attr\u访问器
也应该具有多个名称

module AttrAccessorWithClientReset
  def attr_accessor_with_client_reset(*names)
    attr_reader *names

    names.each do |name|
      define_method :"#{name}=" do |v|
        instance_variable_set(:"@#{name}", v)
        @client = nil
      end
    end
  end
end

class Foo
  extend AttrAccessorWithClientReset

  attr_reader :client
  def initialize
    @foo = 0
    @client = 'client'
  end

  attr_accessor_with_client_reset :foo
end

f = Foo.new
f.foo    # => 0
f.client # => "client"
f.foo = 1
f.foo    # => 1
f.client # => nil

是的,我打了,但我想我打错了,因为当我再次尝试时,它现在可以工作了。你说得对,我应该发布它。对不起,
base.extend ClassMethods
将自动发布:)+1'dBTW、
define\u method
和co接受字符串和符号。你为什么在这里用符号?对我来说,这是不必要的视觉噪音。我猜它们只是自动出现:-)
Symbol
s代表名称。实际上,它们表示Ruby解释器/编译器的符号表中的条目。这正是方法名的含义。所以,对我来说,它只是在语义上感觉“正确”。这可能更多的是口味的问题。