Hash.to_struct

There’s a bit of a gotcha I encountered recently with OpenStruct. If you create a new one from a Hash with the key, uh, “hash” - then try to read the value back out by doing mystruct.hash - you’ll get the object ID instead. No idea why, I’d certainly never realised .hash was a synonym for .object_id before, but it fails in the worst possible way - looks like it works, accepts the information, and then casually hands you back the wrong value when you least expect it:

>> require 'ostruct'
=> true
>> hsh = {:hash => 'hash!'}
=> {:hash=>"hash!"}
>> os = OpenStruct.new(hsh)
=> #
>> os.hash
=> 18782890

Can’t have that. I had already extended Hash to ease OpenStruct creation, so I modified that to check for key/keyword collisions first.

class Hash
  def to_struct
    if self.keys.map {|k| OpenStruct.respond_to?(k)}.include?(true)
      raise 'reserved word as hash key'
    end
    OpenStruct.new(self)
  end
end

Gotta love those Ruby one-liners : )

So why do this kind of thing at all? Well, Rails has spoiled me with all its method_missing sugar. So if I’m doing something like this:

SITE_CONFIG = {:default_language => 'en'}

I don’t want to access it like this:

SITE_CONFIG[:default_language]

OK, pretty silly reason, but it makes a difference to me! Hey, that’s why I use Ruby in the first place.

>> SITE_CONFIG = {:default_language => 'en'}.to_struct
=> #
>> SITE_CONFIG.default_language
=> "en"

It’s the little things.

Of course the real lesson here is not to use common keywords/class methods as hash keys or anywhere else.

Tags:

Leave a Reply