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
There is Class.attr_accessor_with_history method that provides the same
functionality as attr_accessor but also tracks every value the attribute has
ever had.
> a = Example.new; a.foo = 2; a.foo = "test"; a.foo_history
=> [nil, 2, "test"]
But,
> a = Example.new; a.foo_history
=> nil
and it should be [nil.
How can I define single initialize method for Example class where each
…_history value will be initialize as [nil]?
I think, your best bet is to define a custom reader for history (along with your custom writer).
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]
Here's a slightly more verbose snippet, but it doesn't use class_eval (which is frowned upon, when used without necessity).
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With