我想实现一个(类)方法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
我如何实现这一目标?
我想实现一个(类)方法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
我如何实现这一目标?
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
如果您有 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。