开发者

recursion through hashes in ruby

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 my开发者_运维技巧class.price


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:

  • Replace recursion it is not used anyway with a stack for the keys used.
  • Every time, you go into the recursion, the stack is appended the new key.
  • Every time, the recursion is left, the stack is reduced (by using 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">
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜