Convert your Hash keys to object properties in Ruby
- by kerry
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.