Question

I'm running into an issue with OptionParser's make_switch.

My code parses three arguments and runs a test to see if my MANDATORY argument is here:

 #!/usr/bin/env ruby

 require 'optparse'
 require 'ostruct'

options = OpenStruct.new
@argv = ARGV

optparse = OptionParser.new do |opts|

  @opts=opts

  usage = "USAGE: ./#{File.basename($0)} [-v] -p xxxxxx"
  @opts.banner = usage

  @opts.on( '-p', '--pdu [PDU]', 'Specify a PDU to configure') do |res|
    options.pdu = true
    $pdu_name = res
  end

  @opts.on( '-v', '--[no-]verbose', 'Run verbosely') do
    options.verbose = true
  end

  @opts.on( '-?', '-help','Show this message') do
    puts "Help Me!"        
    puts @opts
    exit 1
  end
end

begin
    if not @argv.empty?
      optparse.order!(@argv)
      if !options.pdu
        $stderr.puts "Options -p missing."
        $stderr.puts "#{@opts}\n\n"
        exit 1
      end
    else
      $stderr.puts "ERROR: Arguments Required."
      $stderr.puts "#{@opts}\n\n"
      exit 1
    end
  rescue OptionParser::InvalidOption
    $stderr.puts "ERROR: Invalid option."
    $stderr.puts "#{@opts}\n\n"
    exit 1
end  

Everything works except -?:

xxx$ ./myscript.rb -?
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:451:in 
`parse': missing argument: -? (OptionParser::MissingArgument)
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1295:in `parse_in_order'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1254:in `catch'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1254:in `parse_in_order'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1248:in `order!'
blabla

However -help works perfectly:

xxxx$ ./myscript.rb -help
Help me!
USAGE: ./myscript.rb [-v] -p xxxxxx
    -p, --pdu [PDU]                  Specify a PDU to configure
    -v, --[no-]verbose               Run verbosely
    -?, -help                        Show this message

More surprisingly, -? -v works too:

xxxx$ ./myscript.rb -? -v
Help Me!
USAGE: ./myscript.rb [-v] -p xxxxxx
    -p, --pdu [PDU]                  Specify a PDU to configure
    -v, --[no-]verbose               Run verbosely
    -?, -help                        Show this message

What did I do wrong?

The same issue occurs if I replace -? with -h in the code.

Was it helpful?

Solution

Perhaps a quick look at the (somewhat confusing) documentation would shed some light on the situation. If you look at the docs, you'll end up at OptionParser#make_switch where you'll find an explanation of what the opt.on arguments look like:

Long style switch:
Specifies a long style switch which takes a mandatory, optional or no argument. It’s a string of the following form:

"--switch=MANDATORY" or "--switch MANDATORY"
"--switch[=OPTIONAL]"
"--switch"

Short style switch:
Specifies short style switch which takes a mandatory, optional or no argument. It’s a string of the following form:

"-xMANDATORY"
"-x[OPTIONAL]"
"-x"

Note the -xMANDATORY and then look closer at your @opts.on call:

@opts.on( '-?', '-help','Show this message') do
# ---------------^^^^^

That -help defines a -h option with a required elp argument. Presumably the option parser is interpreting that to mean that -h is an alias for -? and since -h is defined with a required argument, -? also requires an argument. If you use --help (i.e. a long style switch) then you'll probably have a better time:

@opts.on('-?', '--help', 'Show this message') do

I working from the Ruby 2.0 version but I doubt much has changed in the option parser since the older version of Ruby that you appear to be using.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top