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: 535
Developer Tools
|ruby
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