Enumerable#to_hash for Unix-style flags in Ruby methods

A question came up on the Ruby mailing list today about how one might pass boolean flags in an option hash to a Ruby method, without having to explicitly declare them as true. To clarify, here’s the original question from Woody Peterson:

I have a unix-inspired desire to pass arguments to a method where some are toggle flags and some are values, aka "bash$ method --flag --config=/etc/method". I can think of a few ways to do it that are close, but if I had a hash that initiated value-less keys to true, I would have it.

Example:

method(:flag, :another, :config => "/etc/whatever")

For some of the functionality I colud use *args and check args.include?(:foo), but then I couldn’t pass in key-value pairs easily.

I came up with a solution that I thought might prove useful, so I’m posting it here. Essentially we add a method to convert any Enumerable object to a Hash. The method builds a new hash by looping over the object; if the item is a hash it is merged into the result, otherwise it is used as a key to which a value is assigned (true by default). Here goes:

module Enumerable
  def to_hash(value = true)
    inject({}) do |hash, item|
      item.is_a?(Hash) ?
          hash.update(item) :
          hash[item] = value
      hash
    end
  end
end

You can then convert a splat-args style argument to a hash easily:

def my_method(foo, bar, *args)
  options = args.to_hash
  if options[:flag] #...
end

# Call using explicit or implicit booleans

my_method('one', 'two', :flag => true, :val => 94)

my_method('one', 'two', :flag, :val => 94)

Note that the boolean flags must be given first if you want to omit the curly braces on the option hash; Ruby does not allow further non-hash arguments after you begin a braceless hash.

If you’ve enjoyed this article, you might enjoy my recently published book JavaScript Testing Recipes. It’s full of simple techniques for writing modular, maintainable JavaScript apps in the browser and on the server.