# optparse.rb - command-line option analysis with the OptionParser class.
# Documentation:: Nobu Nakada and Gavin Sinclair.
# See OptionParser for documentation.
# == Developer Documentation (not for RDoc output)
# - OptionParser:: front end
# - OptionParser::Switch:: each switches
# - OptionParser::List:: options list
# - OptionParser::ParseError:: errors on parsing
# - OptionParser::AmbiguousOption
# - OptionParser::NeedlessArgument
# - OptionParser::MissingArgument
# - OptionParser::InvalidOption
# - OptionParser::InvalidArgument
# - OptionParser::AmbiguousArgument
# === Object relationship diagram
# | OptionParser |<>-----+
# +--------------+ | +--------+
# on_head -------->+---------------+ / +--------+
# accept/reject -->| List |<|>-
# on ------------->+---------------+ `-| argument |
# +---------------+ |==========|
# on_tail -------->| | |pattern |
# +---------------+ |----------|
# OptionParser.accept ->| DefaultList | |converter |
# reject |(shared between| +----------+
# OptionParser is a class for command-line option analysis. It is much more
# advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
# 1. The argument specification and the code to handle it are written in the
# 2. It can output an option summary; you don't need to maintain this string
# 3. Optional and mandatory arguments are specified very gracefully.
# 4. Arguments can be automatically converted to a specified class.
# 5. Arguments can be restricted to a certain set.
# All of these features are demonstrated in the examples below. See
# #make_switch for full documentation.
# OptionParser.new do |opts|
# opts.banner = "Usage: example.rb [options]"
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
# OptionParser can be used to automatically generate help for the commands you
# Options = Struct.new(:name)
# def self.parse(options)
# args = Options.new("world")
# opt_parser = OptionParser.new do |opts|
# opts.banner = "Usage: example.rb [options]"
# opts.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
# opts.on("-h", "--help", "Prints this help") do
# opt_parser.parse!(options)
# options = Parser.parse %w[--help]
# # Usage: example.rb [options]
# # -n, --name=NAME Name to say hello to
# # -h, --help Prints this help#
# The following example is a complete Ruby program. You can run it and see the
# effect of specifying various options. This is probably the best way to learn
# the features of +optparse+.
# require 'optparse/time'
# CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
# CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
# # Return a structure describing the options.
# # The options specified on the command line will be collected in *options*.
# # We set default values here.
# options = OpenStruct.new
# options.inplace = false
# options.encoding = "utf8"
# options.transfer_type = :auto
# options.verbose = false
# opt_parser = OptionParser.new do |opts|
# opts.banner = "Usage: example.rb [options]"
# opts.separator "Specific options:"
# opts.on("-r", "--require LIBRARY",
# "Require the LIBRARY before executing your script") do |lib|
# # Optional argument; multi-line description.
# opts.on("-i", "--inplace [EXTENSION]",
# "Edit ARGV files in place",
# " (make backup if EXTENSION supplied)") do |ext|
# options.extension = ext || ''
# options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
# # Cast 'delay' argument to a Float.
# opts.on("--delay N", Float, "Delay N seconds before executing") do |n|
# # Cast 'time' argument to a Time object.
# opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
# # Cast to octal integer.
# opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
# "Specify record separator (default \\0)") do |rs|
# options.record_separator = rs
# opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
# # Keyword completion. We are specifying a specific set of arguments (CODES
# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
# # the shortest unambiguous text.
# code_list = (CODE_ALIASES.keys + CODES).join(',')
# opts.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
# " (#{code_list})") do |encoding|
# options.encoding = encoding
# # Optional argument with keyword completion.
# opts.on("--type [TYPE]", [:text, :binary, :auto],
# "Select transfer type (text, binary, auto)") do |t|
# options.transfer_type = t
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
# opts.separator "Common options:"
# # No argument, shows at tail. This will print an options summary.
# opts.on_tail("-h", "--help", "Show this message") do
# # Another typical switch to print the version.
# opts.on_tail("--version", "Show version") do
# puts ::Version.join('.')
# opt_parser.parse!(args)
# end # class OptparseExample
# options = OptparseExample.parse(ARGV)
# For modern shells (e.g. bash, zsh, etc.), you can use shell
# completion for command line options.
# === Further documentation
# The above examples should be enough to learn how to use this class. If you
# have any questions, file a ticket at http://bugs.ruby-lang.org.
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
# Keyword completion module. This allows partial arguments to be specified
# and resolved against a list of acceptable values.
def self.regexp(key, icase)
Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
def self.candidate(key, icase = false, pat = nil, &block)
pat ||= Completion.regexp(key, icase)
kn = defined?(k.id2name) ? k.id2name : k
def candidate(key, icase = false, pat = nil)
Completion.candidate(key, icase, pat, &method(:each))
def complete(key, icase = false, pat = nil)
candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
canon, sw, * = candidates[0]
elsif candidates.size > 1
canon, sw, cn = candidates.shift
candidates.each do |k, v, kn|
if String === cn and String === kn
block_given? or return key, *sw
def convert(opt = nil, val = nil, *)
# Map from option/keyword string to object with completion.
# Individual switch class. Not important to the user.
# Defined within Switch are several Switch-derived classes: NoArgument,
attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
# Guesses argument style from +arg+. Returns corresponding
# OptionParser::Switch class (OptionalArgument, etc.).
t = Switch::OptionalArgument
t = Switch::PlacedArgument
t = Switch::RequiredArgument
self >= t or incompatible_argument_styles(arg, t)
def self.incompatible_argument_styles(arg, t)
raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
ParseError.filter_backtrace(caller(2)))
def initialize(pattern = nil, conv = nil,
short = nil, long = nil, arg = nil,
desc = ([] if short or long), block = Proc.new)
raise if Array === pattern
@pattern, @conv, @short, @long, @arg, @desc, @block =
pattern, conv, short, long, arg, desc, block
# Parses +arg+ and returns rest of +arg+ and matched portion to the
# argument pattern. Yields when the pattern doesn't match substring.
pattern or return nil, [arg]
unless m = pattern.match(arg)
yield(InvalidArgument, arg)
return nil, m unless String === s
raise InvalidArgument, arg unless arg.rindex(s, 0)
return nil, m if s.length == arg.length
yield(InvalidArgument, arg) # didn't match whole arg
return arg[s.length..-1], m
# Parses argument, converts and returns +arg+, +block+ and result of
# conversion. Yields at semi-error condition instead of raising an
def conv_arg(arg, val = [])
val = proc {|v| v}.call(*val)
# Produces the summary text. Each line of the summary is yielded to the
# block (without newline).
# +sdone+:: Already summarized short style options keyed hash.
# +ldone+:: Already summarized long style options keyed hash.
# +width+:: Width of left side (option part). In other words, the right
# side (description part) starts after +width+ columns.
# +max+:: Maximum width of left side -> the options are filled within
# +indent+:: Prefix string indents all summarized lines.
def summarize(sdone = [], ldone = [], width = 1, max = width - 1, indent = "")
sopts, lopts = [], [], nil
@short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
@long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
return if sopts.empty? and lopts.empty? # completely hidden
left = [sopts.join(', ')]
l = left[-1].length + s.length
l += arg.length if left.size == 1 && arg
l < max or sopts.empty? or left << ''
left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s
left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
mlen = left.collect {|ss| ss.length}.max.to_i
while mlen > width and l = left.shift
mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
if l.length < width and (r = right[0]) and !r.empty?
l = l.to_s.ljust(width) + ' ' + r
while begin l = left.shift; r = right.shift; l or r end
l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
def add_banner(to) # :nodoc:
to << " [" + s + "]..." unless s.empty?
def match_nonswitch?(str) # :nodoc:
@pattern =~ str unless @short or @long
# Main name of the switch.
(long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
def compsys(sdone, ldone) # :nodoc:
@short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
@long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
return if sopts.empty? and lopts.empty? # completely hidden
(sopts+lopts).each do |opt|
# "(-x -c -r)-l[left justify]" \
if /^--\[no-\](.+)$/ =~ opt
yield("--#{o}", desc.join(""))
yield("--no-#{o}", desc.join(""))
yield("#{opt}", desc.join(""))
# Switch that takes no arguments.