Richard Crowley’s blog

Clint, a Ruby command line argument parser

I’m programming in Ruby these days and feel more strongly than ever that DSLs are (usually) evil.  The only DSL I’ve ever met that I liked is Sinatra.  So I arrived to the menagerie of Ruby command line argument parsers ready to be let down.  For the sake of documentation, here’s a list of libraries I rejected:

I won’t insult the authors by debunking their hard work individually.  I prefer to use the language syntax over DSL methods.  I prefer to hand-craft usage and help messages rather than sprinkle partial documentation throughout my code.  Finally, I want some support in implementing subcommand-style interfaces a la git, svn, and apt-get.  With that, here’s Clint.

This example will create a command line tool for this class.

class FooBar
  def initialize(foo)
    @foo = foo
  end
  def foo
    puts "FooBar#foo @foo: #{@foo}"
  end
  def self.bar(options={})
    puts "FooBar.bar options[:thing]: #{options[:thing]}"
  end
end

The command line tool first sets up usage and help messages.  Next, it reacts to the global -h and --help options, which are bundled into options[:help] because of the :h => :help alias.  Finally, it executes subcommands from the FooBar class, declaring the -t and --thing options for the bar subcommand.

require 'clint'
c = Clint.new
c.usage do
  $stderr.puts <<EOF
Usage: #{File.basename(__FILE__)} foo <foo>
       #{File.basename(__FILE__)} bar [-t <thing>] [--thing=<thing>]
       #{File.basename(__FILE__)} [-h|--help]
EOF
end
c.help do
  $stderr.puts <<EOF
  -t <thing>, --thing=<thing>  OH HAI
  -h, --help                   show this help message
EOF
end
c.options :help => false, :h => :help
c.parse ARGV
if c.options[:help]
  c.help
  exit 1
end
c.subcommand FooBar do |subcommand|
  if :bar == subcommand
    c.options :thing => String, :t => :thing
  end
  c.parse
end

The README goes into more detail.  Read the code on GitHub or gem install clint from Gemcutter.