Reputation: 34869
I'm doing a bit of recursion through hashes to build attr_accessor and class instances. I get all of the value from a main hash. I use it to describe an event (dance class and club) and I'd like to be able to store the info like this:
data = {:datetime => '2011-11-23', :duration => '90', :lesson => {:price => '£7', :level => 'all'}, :club => {:price => "4"}
so that I can easily retrieve lesson[:price]
and club[:price]
.
With the recursion that I have in place, I check every item of the main hash to see if the value is a hash. If it is I restart the recursion and populate all of the values.
The problem is that I can't have 2 variables of the same name as lesson[:price]
collides with club[:price]
.
This is the recursion:
class Event
#attr_reader :datetime, :duration, :class, :price, :level
def init(data, recursion)
data.each do |name, value|
if value.is_a? Hash
init(value, recursion+1)
else
instance_variable_set("@#{name}", value)
self.class.send(:attr_accessor, name)
end
end
end
It skip the lesson and club level and add all of their inner values to the instance list.
Is it possible to actually append the name of skipped level so that I can access it through my_class.lesson.price
, myclass.club.price
instead of myclass.price
Upvotes: 2
Views: 311
Reputation: 15525
You will have to change the API you use currently. Here is the corrected code:
class Event
#attr_reader :datetime, :duration, :class, :price, :level
def init(data, stack = [])
data.each do |name, value|
if value.is_a? Hash
init(value, stack << name.to_s)
stack.pop
else
new_name = stack.empty? ? name : stack.join("_") + "_" + name.to_s
instance_variable_set("@#{new_name}", value)
self.class.send(:attr_accessor, new_name)
end
end
end
end
It is the following idea:
recursion
it is not used anyway with a stack for the keys used.pop
).The code for appending the things together is ugly, but it works. The output after using your example data:
irb(main):042:0> e.init(data)
=> {:datetime=>"2011-11-23", :duration=>"90", :lesson=>{:price=>"7", :level=>"all"}, :club=>{:price=>"4"}}
irb(main):043:0> e
=> #<Event:0x2628360 @datetime="2011-11-23", @duration="90", @lesson_price="7", @lesson_level="all", @club_price="4">
Upvotes: 3