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

1 Expert Approved Answer
Step: 1 Unlock

To implement the attraccessorwithhistory method as described you can modify the given template code ... View full answer

blur-text-image
Question Has Been Solved by an Expert!

Get step-by-step solutions from verified subject matter experts

Step: 2 Unlock
Step: 3 Unlock

Students Have Also Explored These Related Programming Questions!