Question
Define a method attr_accessor_with_history thatprovides the same functionality as attr accessor but also tracksevery value the attribute has ever had: class Foo attr_accessor_with_history :barendf =
Define a method attr_accessor_with_history thatprovides the same functionality as attr accessor but also tracksevery value the attribute has ever had:
class Foo attr_accessor_with_history :barendf = Foo.new # => #f.bar = 3 # => 3f.bar = :wowzo # => :wowzof.bar = 'boo!' # => 'boo!'f.bar_history # => [nil, 3, :wowzo]
(Calling bar_history before bar's setter is evercalled should return nil.)
History of instance variables should be maintained separatelyfor each object instance. that is:
f = Foo.newf.bar = 1 ; f.bar = 2g = Foo.newg.bar = 3 ; g.bar = 4g.bar_history
then the last line should just return [nil,3], ratherthan [nil,1,2,3].
If you're interested in how the template works, the first thingto notice is that if wedefine attr_accessor_with_history in class Class, wecan use it as in the snippet above. This is because a Ruby classlike Foo or String is actually just an objectof class Class. (If that makes your brain hurt, just don'tworry about it for now. It'll come.)
The second thing to notice is that Ruby provides amethod class_eval that takes a string and evaluates it inthe context of the current class, that is, the class from whichyou're calling attr_accessor_with_history. This string willneed to contain a method definition that implements asetter-with-history for the desired attribute attr_name.
HINTS:
Don't forget that the very first time the attribute receives avalue, its history array will have to be initialized.
An attribute's initial value is always nil by default,so if foo_history is referenced before foo hasever been assigned, the correct answer is nil, but after thefirst assignment to foo, the correct valuefor foo_history would be [nil].
Don't forget that instance variables are referred toas @bar within getters and setters, as Section 3.4 ofELLS explains.
Although the existing attr_accessor can handlemultiple arguments (e.g. attr_accessor :foo, :bar), yourversion just needs to handle a single argument.
Your implementation should be general enough to work in thecontext of any class and for attributes of any (legal) variablename.
Note that one powerful metaprogramming feature in Rubyis class_eval that can be called in themeta-class Class.class_eval can interpret a string on thefly to create some new code. In the example below, wedefine add_method() in the meta-class (and, throughinheritance, available to any class). When called, this methoddefines a new method that returns 42 (noticehow #{name} gets replaced with the parameter passedto add_method).
class Class def add_method (name) class_eval %Q{ def #{name}() 42 end } end end class MyClass add_method :my_method end mc = MyClass.new puts mc.my_method # => 42
class Class | |
defattr_accessor_with_history(attr_name) | |
attr_name = attr_name.to_s # makesure it's a string | |
attr_reader attr_name # create theattribute's getter | |
attr_reader attr_name+"_history" #create bar_history getter | |
class_eval %Q{ | |
# YOUR CODE HERE | |
} | |
end | |
end |
Please help with this Cloud9 Ruby programming project.
In lecture we saw how attr_accessor usesmetaprogramming to create getters and setters for object attributeson the fly.
Step by Step Solution
3.44 Rating (160 Votes )
There are 3 Steps involved in it
Step: 1
To implement the attraccessorwithhistory method as described you can modify the given template code ...Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started