SymbolicKeyHash
Symbols aren't strings. They aren't even immutable strings. They are symbols. They are also very good keys for hashes, assuming the code building the hash thought so also. It is often the case, however, that hashes received by your code may be keyed by either strings or symbols, or a mixture thereof, and you'd like to be able to handle either case simply and elegantly. The simplest thing to do is to call #extend on the offending hash with the following module:
module SymbolicKeyHash def [](key) case key when Symbol include?(key) ? super(key) : super(key.to_s) when String include?(key) ? super(key) : super(key.to_sym) else super(key) end end end
That's good as far as it goes, but it really isn't nice to mess with the interface of an argument you've been passed. Instead, we rely on a Proxy to wrap it:
def bar(hash) hash = Proxy.new(hash) hash.extend SymbolicKeyHash do_something(hash[:first_thing], hash[:second_thing]) endEnjoy!
3 Comments:
At 7/20/2006 12:46:00 PM, Anonymous said…
There's also the HashWithIndifferentAccess class you can find in Rails which does this.
http://api.rubyonrails.org/classes/HashWithIndifferentAccess.html
At 12/31/2006 12:15:00 AM, tea42 said…
But,
h[:x]=1
h['x']=2
Who's right?
At 12/31/2006 03:36:00 AM, Gregory said…
That depends very much on your perspective. In the use case I give, it would be the latter because the code doing the looking up is using symbols for keys. If you were actually intending to write to the hash, you might want the following as part of the SymbolicKeyHash module:
def []=(k, v)
if String === k
super(k.to_sym, v)
else
super(k, v)
end
end
And if you wanted to be really pedantic about it, you could set up your code to raise an exception if there were any keys that were present as both symbols and hashes (left as an exercise for the reader). This, though, is really about convenience in passing and retrieving named parameters.
Post a Comment
<< Home