我想实现一个(类)方法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
我如何实现这一目标?
答案 0 :(得分:8)
塞尔吉奥的解决方案很好,但是不必要地复杂:没有必要复制attr_reader
的行为,你可以委托给它。并且所有这些双模块都不需要包括钩子hackery。另外,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
答案 1 :(得分:1)
如果你有一些红宝石元编程经验,那实际上非常简单。看看:
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。