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.