How do you specify a required switch (not argument) with Ruby OptionParser?

Teflon Ted picture Teflon Ted · Oct 9, 2009 · Viewed 45.4k times · Source

I'm writing a script and I want to require a --host switch with value, but if the --host switch isn't specified, I want the option parsing to fail.

I can't seem to figure out how to do that. The docs seem to only specify how to make the argument value mandatory, not the switch itself.

Answer

volund picture volund · Jan 27, 2010

An approach using optparse that provides friendly output on missing switches:

#!/usr/bin/env ruby
require 'optparse'

options = {}

optparse = OptionParser.new do |opts|
  opts.on('-f', '--from SENDER', 'username of sender') do |sender|
    options[:from] = sender
  end

  opts.on('-t', '--to RECIPIENTS', 'comma separated list of recipients') do |recipients|
    options[:to] = recipients
  end

  options[:number_of_files] = 1
  opts.on('-n', '--num_files NUMBER', Integer, "number of files to send (default #{options[:number_of_files]})") do |number_of_files|
    options[:number_of_files] = number_of_files
  end

  opts.on('-h', '--help', 'Display this screen') do
    puts opts
    exit
  end
end

begin
  optparse.parse!
  mandatory = [:from, :to]                                         # Enforce the presence of
  missing = mandatory.select{ |param| options[param].nil? }        # the -t and -f switches
  unless missing.empty?                                            #
    raise OptionParser::MissingArgument.new(missing.join(', '))    #
  end                                                              #
rescue OptionParser::InvalidOption, OptionParser::MissingArgument      #
  puts $!.to_s                                                           # Friendly output when parsing fails
  puts optparse                                                          #
  exit                                                                   #
end                                                                      #

puts "Performing task with options: #{options.inspect}"

Running without the -t or -f switches shows the following output:

Missing options: from, to
Usage: test_script [options]
    -f, --from SENDER                username of sender
    -t, --to RECIPIENTS              comma separated list of recipients
    -n, --num_files NUMBER           number of files to send (default 1)
    -h, --help

Running the parse method in a begin/rescue clause allows friendly formatting upon other failures such as missing arguments or invalid switch values, for instance, try passing a string for the -n switch.