Using ruby's OptionParser to parse sub-commands

I'd like to be able to use ruby's OptionParser to parse sub-commands of the form

COMMAND [GLOBAL FLAGS] [SUB-COMMAND [SUB-COMMAND FLAGS]]

like:

git branch -a
gem list foo

I know I could switch to a different option parser library (like Trollop), but I'm interested in learning how to do this from within OptionParser, since I'd like to learn the library better.

Any tips?

Answers


Figured it out. I need to use OptionParser#order!. It will parse all the options from the start of ARGV until it finds a non-option (that isn't an option argument), removing everything it processes from ARGV, and then it will quit.

So I just need to do something like:

global = OptionParser.new do |opts|
  # ...
end
subcommands = { 
  'foo' => OptionParser.new do |opts|
     # ...
   end,
   # ...
   'baz' => OptionParser.new do |opts|
     # ...
   end
 }

 global.order!
 subcommands[ARGV.shift].order!

It looks like the OptionParser syntax has changed some. I had to use the following so that the arguments array had all of the options not parsed by the opts object.

begin
  opts.order!(arguments)
rescue OptionParser::InvalidOption => io
  # Prepend the invalid option onto the arguments array
  arguments = io.recover(arguments)
rescue => e
  raise "Argument parsing failed: #{e.to_s()}"
end

There are also other gems you can look at such as main.


GLI is the way to go, https://github.com/davetron5000/gli. An excerpt from a tutorial:

#!/usr/bin/env ruby
require 'gli'
require 'hacer'

include GLI::App

program_desc 'A simple todo list'

flag [:t,:tasklist], :default_value => File.join(ENV['HOME'],'.todolist')

pre do |global_options,command,options,args|
  $todo_list = Hacer::Todolist.new(global_options[:tasklist])
end

command :add do |c|
  c.action do |global_options,options,args|
    $todo_list.create(args)
  end
end

command :list do |c|
  c.action do
    $todo_list.list.each do |todo|
      printf("%5d - %s\n",todo.todo_id,todo.text)
    end
  end
end

command :done do |c|
  c.action do |global_options,options,args|
    id = args.shift.to_i
    $todo_list.list.each do |todo|
      $todo_list.complete(todo) if todo.todo_id == id
    end
  end
end

exit run(ARGV)

You can find the tutorial at http://davetron5000.github.io/gli/.


Need Your Help

Get width height of remote image from url

javascript image height width

So the alert gives undefined values for the width and height. I think the w and h values of the image from the img.onload calculation is not being passed to the values to return, or it may be retur...

iPhone Obj C -- Sorting a Mutable Array of dictionaries -- display a string but sort by value

objective-c iphone-sdk-3.0 sorting nsmutablearray nsdictionary

I have a NSMutableArray with 30 dictionaries inside of it. Each contains a name and a value. I currently have the names sorted so that the show in a table view alphabetically. However, I'd like to...