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: ruby