Ruby, iOS, and Other Development

A place to share useful code snippets, ideas, and techniques

All code in posted articles shall be considered public domain unless otherwise noted.
Comments remain the property of their authors.

2006-07-20

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])
end
Enjoy!

Labels: ,

3 Comments:

  • At 7/20/2006 12:46:00 PM, Anonymous 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, Blogger tea42 said…

    But,
    h[:x]=1
    h['x']=2
    Who's right?

     
  • At 12/31/2006 03:36:00 AM, Blogger 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