Convert your Hash keys to object properties in Ruby

Posted by kerry on Gooder Code See other posts from Gooder Code or by kerry
Published on Sun, 07 Feb 2010 21:51:17 +0000 Indexed on 2010/03/18 23:21 UTC
Read the original article Hit count: 512

Filed under:
|

Being a Ruby noob (and having a background in Groovy), I was a little surprised that you can not access hash objects using the dot notation.  I am writing an application that relies heavily on XML and JSON data.  This data will need to be displayed and I would rather use book.author.first_name over book[‘author’][‘first_name’].  A quick search on google yielded this post on the subject.

So, taking the DRYOO (Don’t Repeat Yourself Or Others) concept.  I came up with this:

   1: class ::Hash

   2:  

   3:   # add keys to hash

   4:   def to_obj

   5:     self.each do |k,v|

   6:       if v.kind_of? Hash

   7:         v.to_obj

   8:       end

   9:       k=k.gsub(/\.|\s|-|\/|\'/, '_').downcase.to_sym

  10:       self.instance_variable_set("@#{k}", v)  ## create and initialize an instance variable for this key/value pair

  11:       self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})  ## create the getter that returns the instance variable

  12:       self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})  ## create the setter that sets the instance variable

  13:     end

  14:     return self

  15:   end

  16: end

This works pretty well.  It converts each of your keys to properties of the Hash. 

However, it doesn’t sit very well with me because I probably will not use 90% of the properties most of the time.  Why should I go through the performance overhead of creating instance variables for all of the unused ones?

Enter the ‘magic method’ #missing_method:

   1: class ::Hash

   2:   def method_missing(name)

   3:     return self[name] if key? name

   4:     self.each { |k,v| return v if k.to_s.to_sym == name }

   5:     super.method_missing name

   6:   end

   7: end

This is a much cleaner method for my purposes.  Quite simply, it checks to see if there is a key with the given symbol, and if not, loop through the keys and attempt to find one.

I am a Ruby noob, so if there is something I am overlooking, please let me know.

© Gooder Code or respective owner

Related posts about Developer Tools

Related posts about ruby