4

我想实现一个(类)方法attr_accessor_with_client_reset,它做同样的事情attr_accessor,但在每个作家上它额外执行

@client = nil

所以,例如,

attr_accessor_with_client_reset :foo

应该产生相同的结果

attr_reader :foo

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

我如何实现这一目标?

4

2 回答 2

10

Sergio 的解决方案很好,但不必要的复杂:不需要复制 的行为attr_reader,您可以委托给它。并且不需要所有这个双模块包括钩子黑客。另外,attr_accessor需要多个名称,attr_accessor_with_client_reset也应该如此。

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
于 2012-05-02T12:18:49.263 回答
1

如果您有 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

如果这段代码对你来说不是很清楚,那么我强烈推荐这本书:Metaprogramming Ruby

于 2012-05-02T08:52:50.157 回答