如何在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解释器/编译器的符号表中的条目。这正是方法名的含义。所以,对我来说,它只是在语义上感觉“正确”。这可能更多的是口味的问题。