Created
March 5, 2012 17:00
-
-
Save anonymous/1979278 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Define a method attr_accessor_with_history that provides the same functionality as | |
attr accessor but also tracks every value the attribute has ever had: | |
class Foo | |
attr_accessor_with_history :bar | |
end | |
f = Foo.new # => #<Foo:0x127e678> | |
f.bar = 3 # => 3 | |
f.bar = :wowzo # => :wowzo | |
f.bar = 'boo!' # => 'boo!' | |
f.bar_history # => [nil, 3, :wowzo, 'boo!'] | |
We'll start you off. The first thing to notice is that if we define | |
attr_accessor_with_history in class Class, we can use it as in the snippet | |
above. This is because, as ELLS mentions, in Ruby a class is simply an object of | |
class Class. (If that makes your brain hurt, just don't worry about it for now. It'll | |
come.) The second thing to notice is that Ruby provides a method class_eval | |
that takes a string and evaluates it in the context of the current class, that is, the | |
class from which you're calling attr_accessor_with_history. This string will | |
need to contain a method definition that implements a setter-with-history for the | |
desired attribute attr_name. | |
Don't forget that the very first time the attribute receives a value, its history | |
• | |
array will have to be initialized. | |
Don't forget that instance variables are referred to as @bar within getters and | |
• | |
setters, as Section 3.4 of ELLS explains. | |
Although the existing attr_accessor can handle multiple arguments (e.g. | |
• | |
attr_accessor :foo, :bar), your version just needs to handle a single | |
argument. | |
Your implementation should be genreal enough to work in the context of any | |
• | |
class and for attributes of any (legal) variable name | |
History of instance variables should be maintained separately for each object | |
• | |
instance. that is, if you do | |
f = Foo.new | |
f.bar = 1 | |
f.bar = 2 | |
f = Foo.new | |
f. bar = 4 | |
f.bar_history | |
then the last line should just return [nil,4], rather than [nil,1,2,4] | |
Here is the skeleton to get you started: | |
class Class | |
def attr_accessor_with_history(attr_name) | |
attr_name = attr_name.to_s # make sure it's a string | |
attr_reader attr_name # create the attribute's | |
getter | |
attr_reader attr_name+"_history" # create bar_history | |
getter | |
class_eval "your code here, use %Q for multiline strings" | |
end | |
end | |
class Foo | |
attr_accessor_with_history :bar | |
end | |
f = Foo.new | |
f.bar = 1 | |
f.bar = 2 | |
f.bar_history # => if your code works, should be [nil,1,2] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment