class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s
attr_reader attr_name
attr_reader attr_name + "_history"
class_eval %Q{
def #{attr_name}=(new_value)
@#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
@#{attr_name}_history << @#{attr_name} = new_value
end
}
end
end
class Example
attr_accessor_with_history :foo
attr_accessor_with_history :bar
end
有Class.attr_accessor_with_history
方法提供相同的方法
功能为attr_accessor
,但也跟踪属性的每个值
曾经有过。
> a = Example.new; a.foo = 2; a.foo = "test"; a.foo_history
=> [nil, 2, "test"]
但是,
> a = Example.new; a.foo_history
=> nil
它应该是[nil
。
如何为initialize
类定义单个Example
方法
…_history
值将初始化为[nil]
?
答案 0 :(得分:10)
我认为,最好的办法是为历史定义一个自定义阅读器(以及自定义编写器)。
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s
attr_reader attr_name
class_eval %Q{
def #{attr_name}_history
@#{attr_name}_history || [nil] # give default value if not assigned
end
def #{attr_name}=(new_value)
@#{attr_name}_history ||= [nil] # shortcut, compare to your line
@#{attr_name}_history << @#{attr_name} = new_value
end
}
end
end
class Example
attr_accessor_with_history :foo
attr_accessor_with_history :bar
end
a = Example.new; a.foo = 2; a.foo = "test";
a.foo_history # => [nil, 2, "test"]
a = Example.new
a.foo_history # => [nil]
这是一个稍微冗长的片段,但它不使用class_eval
(在不必要的情况下使用时不赞成)。
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s
attr_reader attr_name
define_method "#{attr_name}_history" do
instance_variable_get("@#{attr_name}_history") || [nil]
end
define_method "#{attr_name}=" do |new_value|
v = instance_variable_get("@#{attr_name}_history")
v ||= [nil]
v << new_value
instance_variable_set("@#{attr_name}_history", v)
instance_variable_set("@#{attr_name}", new_value)
end
end
end
答案 1 :(得分:0)
一个class_eval中的Sloves
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s
attr_reader attr_name
attr_reader attr_name+"_history"
class_eval %Q{
def #{attr_name}=(val)
if @#{attr_name}_history
@#{attr_name}_history << @#{attr_name}
else
@#{attr_name}_history = [nil]
end
@#{attr_name} = val
end
}
end
end