summaryrefslogtreecommitdiff
path: root/lib/optparse.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/optparse.rb')
-rw-r--r--lib/optparse.rb2585
1 files changed, 1626 insertions, 959 deletions
diff --git a/lib/optparse.rb b/lib/optparse.rb
index 1b083b8e6e..97178e284b 100644
--- a/lib/optparse.rb
+++ b/lib/optparse.rb
@@ -1,15 +1,17 @@
+# frozen_string_literal: true
#
# optparse.rb - command-line option analysis with the OptionParser class.
-#
+#
# Author:: Nobu Nakada
# Documentation:: Nobu Nakada and Gavin Sinclair.
#
-# See OptionParser for documentation.
+# See OptionParser for documentation.
#
+require 'set' unless defined?(Set)
-
-# == Developer Documentation (not for RDoc output)
-#
+#--
+# == Developer Documentation (not for RDoc output)
+#
# === Class tree
#
# - OptionParser:: front end
@@ -25,27 +27,31 @@
#
# === Object relationship diagram
#
-# +--------------+
-# | OptionParser |<>-----+
-# +--------------+ | +--------+
-# | ,-| Switch |
-# on_head -------->+---------------+ / +--------+
-# accept/reject -->| List |<|>-
-# | |<|>- +----------+
-# on ------------->+---------------+ `-| argument |
-# : : | class |
-# +---------------+ |==========|
-# on_tail -------->| | |pattern |
-# +---------------+ |----------|
-# OptionParser.accept ->| DefaultList | |converter |
-# reject |(shared between| +----------+
-# | all instances)|
-# +---------------+
-
-
+# +--------------+
+# | OptionParser |<>-----+
+# +--------------+ | +--------+
+# | ,-| Switch |
+# on_head -------->+---------------+ / +--------+
+# accept/reject -->| List |<|>-
+# | |<|>- +----------+
+# on ------------->+---------------+ `-| argument |
+# : : | class |
+# +---------------+ |==========|
+# on_tail -------->| | |pattern |
+# +---------------+ |----------|
+# OptionParser.accept ->| DefaultList | |converter |
+# reject |(shared between| +----------+
+# | all instances)|
+# +---------------+
+#
+#++
#
# == OptionParser
#
+# === New to +OptionParser+?
+#
+# See the {Tutorial}[optparse/tutorial.rdoc].
+#
# === Introduction
#
# OptionParser is a class for command-line option analysis. It is much more
@@ -53,18 +59,210 @@
# solution.
#
# === Features
-#
-# 1. The argument specification and the code to handle it are written in the same
-# place.
+#
+# 1. The argument specification and the code to handle it are written in the
+# same place.
# 2. It can output an option summary; you don't need to maintain this string
# separately.
# 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 example below.
+# All of these features are demonstrated in the examples below. See
+# #make_switch for full documentation.
+#
+# === Minimal example
+#
+# require 'optparse'
+#
+# options = {}
+# OptionParser.new do |parser|
+# parser.banner = "Usage: example.rb [options]"
+#
+# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
+# options[:verbose] = v
+# end
+# end.parse!
+#
+# p options
+# p ARGV
+#
+# === Generating Help
+#
+# OptionParser can be used to automatically generate help for the commands you
+# write:
+#
+# require 'optparse'
+#
+# Options = Struct.new(:name)
+#
+# class Parser
+# def self.parse(options)
+# args = Options.new("world")
+#
+# opt_parser = OptionParser.new do |parser|
+# parser.banner = "Usage: example.rb [options]"
+#
+# parser.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
+# args.name = n
+# end
+#
+# parser.on("-h", "--help", "Prints this help") do
+# puts parser
+# exit
+# end
+# end
+#
+# opt_parser.parse!(options)
+# return args
+# end
+# end
+# options = Parser.parse %w[--help]
+#
+# #=>
+# # Usage: example.rb [options]
+# # -n, --name=NAME Name to say hello to
+# # -h, --help Prints this help
+#
+# === Required Arguments
+#
+# For options that require an argument, option specification strings may include an
+# option name in all caps. If an option is used without the required argument,
+# an exception will be raised.
+#
+# require 'optparse'
+#
+# options = {}
+# OptionParser.new do |parser|
+# parser.on("-r", "--require LIBRARY",
+# "Require the LIBRARY before executing your script") do |lib|
+# puts "You required #{lib}!"
+# end
+# end.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb -r
+# optparse-test.rb:9:in '<main>': missing argument: -r (OptionParser::MissingArgument)
+# $ ruby optparse-test.rb -r my-library
+# You required my-library!
+#
+# === Type Coercion
#
-# === Example
+# OptionParser supports the ability to coerce command line arguments
+# into objects for us.
+#
+# OptionParser comes with a few ready-to-use kinds of type
+# coercion. They are:
+#
+# - Date -- Anything accepted by +Date.parse+ (need to require +optparse/date+)
+# - DateTime -- Anything accepted by +DateTime.parse+ (need to require +optparse/date+)
+# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+ (need to require +optparse/time+)
+# - URI -- Anything accepted by +URI.parse+ (need to require +optparse/uri+)
+# - Shellwords -- Anything accepted by +Shellwords.shellwords+ (need to require +optparse/shellwords+)
+# - String -- Any non-empty string
+# - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040)
+# - Float -- Any float. (e.g. 10, 3.14, -100E+13)
+# - Numeric -- Any integer, float, or rational (1, 3.4, 1/3)
+# - DecimalInteger -- Like +Integer+, but no octal format.
+# - OctalInteger -- Like +Integer+, but no decimal format.
+# - DecimalNumeric -- Decimal integer or float.
+# - TrueClass -- Accepts '+, yes, true, -, no, false' and
+# defaults as +true+
+# - FalseClass -- Same as +TrueClass+, but defaults to +false+
+# - Array -- Strings separated by ',' (e.g. 1,2,3)
+# - Regexp -- Regular expressions. Also includes options.
+#
+# We can also add our own coercions, which we will cover below.
+#
+# ==== Using Built-in Conversions
+#
+# As an example, the built-in +Time+ conversion is used. The other built-in
+# conversions behave in the same way.
+# OptionParser will attempt to parse the argument
+# as a +Time+. If it succeeds, that time will be passed to the
+# handler block. Otherwise, an exception will be raised.
+#
+# require 'optparse'
+# require 'optparse/time'
+# OptionParser.new do |parser|
+# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
+# p time
+# end
+# end.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb -t nonsense
+# ... invalid argument: -t nonsense (OptionParser::InvalidArgument)
+# $ ruby optparse-test.rb -t 10-11-12
+# 2010-11-12 00:00:00 -0500
+# $ ruby optparse-test.rb -t 9:30
+# 2014-08-13 09:30:00 -0400
+#
+# ==== Creating Custom Conversions
+#
+# The +accept+ method on OptionParser may be used to create converters.
+# It specifies which conversion block to call whenever a class is specified.
+# The example below uses it to fetch a +User+ object before the +on+ handler receives it.
+#
+# require 'optparse'
+#
+# User = Struct.new(:id, :name)
+#
+# def find_user id
+# not_found = ->{ raise "No User Found for id #{id}" }
+# [ User.new(1, "Sam"),
+# User.new(2, "Gandalf") ].find(not_found) do |u|
+# u.id == id
+# end
+# end
+#
+# op = OptionParser.new
+# op.accept(User) do |user_id|
+# find_user user_id.to_i
+# end
+#
+# op.on("--user ID", User) do |user|
+# puts user
+# end
+#
+# op.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb --user 1
+# #<struct User id=1, name="Sam">
+# $ ruby optparse-test.rb --user 2
+# #<struct User id=2, name="Gandalf">
+# $ ruby optparse-test.rb --user 3
+# optparse-test.rb:15:in 'block in find_user': No User Found for id 3 (RuntimeError)
+#
+# === Store options to a Hash
+#
+# The +into+ option of +order+, +parse+ and so on methods stores command line options into a Hash.
+#
+# require 'optparse'
+#
+# options = {}
+# OptionParser.new do |parser|
+# parser.on('-a')
+# parser.on('-b NUM', Integer)
+# parser.on('-v', '--verbose')
+# end.parse!(into: options)
+#
+# p options
+#
+# Used:
+#
+# $ ruby optparse-test.rb -a
+# {:a=>true}
+# $ ruby optparse-test.rb -a -v
+# {:a=>true, :verbose=>true}
+# $ ruby optparse-test.rb -a -b 100
+# {:a=>true, :b=>100}
+#
+# === Complete example
#
# 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
@@ -74,129 +272,165 @@
# require 'optparse/time'
# require 'ostruct'
# require 'pp'
-#
+#
# class OptparseExample
-#
+# Version = '1.0.0'
+#
# 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.
-# #
-# def self.parse(args)
-# # The options specified on the command line will be collected in *options*.
-# # We set default values here.
-# options = OpenStruct.new
-# options.library = []
-# options.inplace = false
-# options.encoding = "utf8"
-# options.transfer_type = :auto
-# options.verbose = false
-#
-# opts = OptionParser.new do |opts|
-# opts.banner = "Usage: example.rb [options]"
-#
-# opts.separator ""
-# opts.separator "Specific options:"
-#
-# # Mandatory argument.
-# opts.on("-r", "--require LIBRARY",
-# "Require the LIBRARY before executing your script") do |lib|
-# options.library << lib
+#
+# class ScriptOptions
+# attr_accessor :library, :inplace, :encoding, :transfer_type,
+# :verbose, :extension, :delay, :time, :record_separator,
+# :list
+#
+# def initialize
+# self.library = []
+# self.inplace = false
+# self.encoding = "utf8"
+# self.transfer_type = :auto
+# self.verbose = false
+# end
+#
+# def define_options(parser)
+# parser.banner = "Usage: example.rb [options]"
+# parser.separator ""
+# parser.separator "Specific options:"
+#
+# # add additional options
+# perform_inplace_option(parser)
+# delay_execution_option(parser)
+# execute_at_time_option(parser)
+# specify_record_separator_option(parser)
+# list_example_option(parser)
+# specify_encoding_option(parser)
+# optional_option_argument_with_keyword_completion_option(parser)
+# boolean_verbose_option(parser)
+#
+# parser.separator ""
+# parser.separator "Common options:"
+# # No argument, shows at tail. This will print an options summary.
+# # Try it and see!
+# parser.on_tail("-h", "--help", "Show this message") do
+# puts parser
+# exit
# end
-#
-# # Optional argument; multi-line description.
-# opts.on("-i", "--inplace [EXTENSION]",
-# "Edit ARGV files in place",
-# " (make backup if EXTENSION supplied)") do |ext|
-# options.inplace = true
-# options.extension = ext || ''
-# options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
+# # Another typical switch to print the version.
+# parser.on_tail("--version", "Show version") do
+# puts Version
+# exit
# end
-#
+# end
+#
+# def perform_inplace_option(parser)
+# # Specifies an optional option argument
+# parser.on("-i", "--inplace [EXTENSION]",
+# "Edit ARGV files in place",
+# "(make backup if EXTENSION supplied)") do |ext|
+# self.inplace = true
+# self.extension = ext || ''
+# self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
+# end
+# end
+#
+# def delay_execution_option(parser)
# # Cast 'delay' argument to a Float.
-# opts.on("--delay N", Float, "Delay N seconds before executing") do |n|
-# options.delay = n
+# parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
+# self.delay = n
# end
-#
+# end
+#
+# def execute_at_time_option(parser)
# # Cast 'time' argument to a Time object.
-# opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
-# options.time = time
+# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
+# self.time = time
# end
-#
+# end
+#
+# def specify_record_separator_option(parser)
# # Cast to octal integer.
-# opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
-# "Specify record separator (default \\0)") do |rs|
-# options.record_separator = rs
+# parser.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
+# "Specify record separator (default \\0)") do |rs|
+# self.record_separator = rs
# end
-#
+# end
+#
+# def list_example_option(parser)
# # List of arguments.
-# opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
-# options.list = list
+# parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
+# self.list = list
# end
-#
+# end
+#
+# def specify_encoding_option(parser)
# # 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
+# code_list = (CODE_ALIASES.keys + CODES).join(', ')
+# parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
+# "(#{code_list})") do |encoding|
+# self.encoding = encoding
# end
-#
-# # Optional argument with keyword completion.
-# opts.on("--type [TYPE]", [:text, :binary, :auto],
-# "Select transfer type (text, binary, auto)") do |t|
-# options.transfer_type = t
+# end
+#
+# def optional_option_argument_with_keyword_completion_option(parser)
+# # Optional '--type' option argument with keyword completion.
+# parser.on("--type [TYPE]", [:text, :binary, :auto],
+# "Select transfer type (text, binary, auto)") do |t|
+# self.transfer_type = t
# end
-#
+# end
+#
+# def boolean_verbose_option(parser)
# # Boolean switch.
-# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
-# options.verbose = v
-# end
-#
-# opts.separator ""
-# opts.separator "Common options:"
-#
-# # No argument, shows at tail. This will print an options summary.
-# # Try it and see!
-# opts.on_tail("-h", "--help", "Show this message") do
-# puts opts
-# exit
-# end
-#
-# # Another typical switch to print the version.
-# opts.on_tail("--version", "Show version") do
-# puts OptionParser::Version.join('.')
-# exit
+# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
+# self.verbose = v
# end
# end
-#
-# opts.parse!(args)
-# options
-# end # parse()
-#
+# end
+#
+# #
+# # Return a structure describing the options.
+# #
+# def parse(args)
+# # The options specified on the command line will be collected in
+# # *options*.
+#
+# @options = ScriptOptions.new
+# @args = OptionParser.new do |parser|
+# @options.define_options(parser)
+# parser.parse!(args)
+# end
+# @options
+# end
+#
+# attr_reader :parser, :options
# end # class OptparseExample
-#
-# options = OptparseExample.parse(ARGV)
-# pp options
#
-# Note: some bugs were fixed between 1.8.0 and 1.8.1. If you experience trouble
-# with the above code, keep this in mind.
+# example = OptparseExample.new
+# options = example.parse(ARGV)
+# pp options # example.options
+# pp ARGV
+#
+# === Shell Completion
+#
+# For modern shells (e.g. bash, zsh, etc.), you can use shell
+# completion for command line options.
#
# === Further documentation
#
-# The methods are not individually documented at this stage. The above example
-# should be enough to learn how to use this class. If you have any questions,
-# email me (gsinclair@soyabean.com.au) and I will update this document.
+# The above examples, along with the accompanying
+# {Tutorial}[optparse/tutorial.rdoc],
+# should be enough to learn how to use this class.
+# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
#
class OptionParser
- # :stopdoc:
- RCSID = %w$Id$[1..-1].each {|s| s.freeze}.freeze
- Version = (RCSID[1].split('.').collect {|s| s.to_i}.extend(Comparable).freeze if RCSID[1])
- LastModified = (Time.gm(*RCSID[2, 2].join('-').scan(/\d+/).collect {|s| s.to_i}) if RCSID[2])
- Release = RCSID[2]
+ # The version string
+ VERSION = "0.8.1"
+ # An alias for compatibility
+ Version = VERSION
+ # :stopdoc:
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
@@ -207,14 +441,18 @@ class OptionParser
# and resolved against a list of acceptable values.
#
module Completion
- def complete(key, pat = nil)
- pat ||= Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'),
- ignore_case?)
- canon, sw, k, v, cn = nil
+ # :nodoc:
+
+ def self.regexp(key, icase)
+ Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
+ end
+
+ def self.candidate(key, icase = false, pat = nil, &block)
+ pat ||= Completion.regexp(key, icase)
candidates = []
- each do |k, *v|
+ block.call do |k, *v|
(if Regexp === k
- kn = nil
+ kn = ""
k === key
else
kn = defined?(k.id2name) ? k.id2name : k
@@ -223,7 +461,19 @@ class OptionParser
v << k if v.empty?
candidates << [k, v, kn]
end
- candidates = candidates.sort_by {|k, v, kn| kn.size}
+ candidates
+ end
+
+ def self.completable?(key)
+ String.try_convert(key) or defined?(key.id2name)
+ end
+
+ def candidate(key, icase = false, pat = nil, &_)
+ Completion.candidate(key, icase, pat, &method(:each))
+ end
+
+ def complete(key, icase = false, pat = nil)
+ candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
if candidates.size == 1
canon, sw, * = candidates[0]
elsif candidates.size > 1
@@ -250,33 +500,24 @@ class OptionParser
def convert(opt = nil, val = nil, *)
val
end
-
- def ignore_case?
- false
- end
end
-
#
# Map from option/keyword string to object with completion.
#
class OptionMap < Hash
include Completion
end
- class OptionCaseMap < OptionMap
- def ignore_case?
- true
- end
- end
-
#
# Individual switch class. Not important to the user.
#
# Defined within Switch are several Switch-derived classes: NoArgument,
- # RequiredArgument, etc.
+ # RequiredArgument, etc.
#
class Switch
+ # :nodoc:
+
attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
#
@@ -299,7 +540,8 @@ class OptionParser
end
def self.incompatible_argument_styles(arg, t)
- raise ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}"
+ raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
+ ParseError.filter_backtrace(caller(2)))
end
def self.pattern
@@ -308,28 +550,22 @@ class OptionParser
def initialize(pattern = nil, conv = nil,
short = nil, long = nil, arg = nil,
- desc = ([] if short or long), block = Proc.new)
+ desc = ([] if short or long), block = nil, values = nil, &_block)
raise if Array === pattern
- @pattern, @conv, @short, @long, @arg, @desc, @block =
- pattern, conv, short, long, arg, desc, block
+ block ||= _block
+ @pattern, @conv, @short, @long, @arg, @desc, @block, @values =
+ pattern, conv, short, long, arg, desc, block, values
end
#
- # OptionParser::Switch#parse_arg(arg) {non-serious error handler}
- #
- # Parses argument and returns rest of ((|arg|)), and matched portion
- # to the argument pattern.
- # :Parameters:
- # : ((|arg|))
- # option argument to be parsed.
- # : (({block}))
- # yields when the pattern doesn't match sub-string.
+ # Parses +arg+ and returns rest of +arg+ and matched portion to the
+ # argument pattern. Yields when the pattern doesn't match substring.
#
- def parse_arg(arg)
- pattern or return nil, arg
+ private def parse_arg(arg) # :nodoc:
+ pattern or return nil, [arg]
unless m = pattern.match(arg)
yield(InvalidArgument, arg)
- return arg, nil
+ return arg, []
end
if String === m
m = [s = m]
@@ -343,59 +579,39 @@ class OptionParser
yield(InvalidArgument, arg) # didn't match whole arg
return arg[s.length..-1], m
end
- private :parse_arg
#
- # OptionParser::Switch#conv_arg(arg, val) {semi-error handler}
+ # Parses argument, converts and returns +arg+, +block+ and result of
+ # conversion. Yields at semi-error condition instead of raising an
+ # exception.
#
- # Parses argument, convert and returns ((|arg|)), ((|block|)) and
- # result of conversion.
- # : Arguments to ((|@conv|))
- # substrings matched to ((|@pattern|)), ((|$&|)), ((|$1|)),
- # ((|$2|)) and so on.
- # :Parameters:
- # : ((|arg|))
- # argument string follows the switch.
- # : ((|val|))
- # following argument.
- # : (({block}))
- # (({yields})) at semi-error condition, instead of raises exception.
- #
- def conv_arg(arg, val = nil)
- if block
- if conv
- val = conv.call(*val)
- else
- val = *val
- end
- return arg, block, val
+ private def conv_arg(arg, val = []) # :nodoc:
+ v, = *val
+ if conv
+ val = conv.call(*val)
else
- return arg, nil
+ val = proc {|v| v}.call(*val)
+ end
+ if @values
+ @values.include?(val) or raise InvalidArgument, v
end
+ return arg, block, val
end
- private :conv_arg
-
- #
- # OptionParser::Switch#summarize(sdone, ldone, width, max, indent)
- #
- # Makes summary strings.
- # :Parameters:
- # : ((|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 word, right side,
- # description part strings start at ((|width|)) column.
- # : ((|max|))
- # maximum width of left side, options are filled within ((|max|)) columns.
- # : ((|indent|))
- # prefix string indents each summarized lines.
- # : (({block}))
- # to be passed each lines(without newline).
- #
- def summarize(sdone = [], ldone = [], width = 1, max = width - 1, indent = "")
- sopts, lopts, s = [], [], nil
+
+ #
+ # 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
+ # +max+ columns.
+ # +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
@@ -406,18 +622,24 @@ class OptionParser
while s = lopts.shift
l = left[-1].length + s.length
l += arg.length if left.size == 1 && arg
- l < max or left << ''
- left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s
+ l < max or sopts.empty? or left << +''
+ left[-1] << (left[-1].empty? ? ' ' * 4 : ', ') << s
end
- left[0] << arg if arg
- mlen = left.collect {|s| s.length}.max.to_i
+ if arg
+ left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
+ end
+ mlen = left.collect {|ss| ss.length}.max.to_i
while mlen > width and l = left.shift
- mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen
+ 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
+ right.shift
+ end
yield(indent + l)
end
- while (l = left.shift; r = right.shift; l or 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?
yield(indent + l)
end
@@ -425,37 +647,114 @@ class OptionParser
self
end
+ def add_banner(to) # :nodoc:
+ unless @short or @long
+ s = desc.join
+ to << " [" + s + "]..." unless s.empty?
+ end
+ to
+ end
+
+ def match_nonswitch?(str) # :nodoc:
+ @pattern =~ str unless @short or @long
+ end
+
+ #
+ # Main name of the switch.
+ #
+ def switch_name
+ (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
+ end
+
+ def compsys(sdone, ldone) # :nodoc:
+ sopts, lopts = [], []
+ @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 /\A--\[no-\](.+)$/ =~ opt
+ o = $1
+ yield("--#{o}", desc.join(""))
+ yield("--no-#{o}", desc.join(""))
+ else
+ yield("#{opt}", desc.join(""))
+ end
+ end
+ end
+
+ def pretty_print_contents(q) # :nodoc:
+ if @block
+ q.text ":" + @block.source_location.join(":") + ":"
+ first = false
+ else
+ first = true
+ end
+ [@short, @long].each do |list|
+ list.each do |opt|
+ if first
+ q.text ":"
+ first = false
+ end
+ q.breakable
+ q.text opt
+ end
+ end
+ end
+
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) {pretty_print_contents(q)}
+ end
+
+ def omitted_argument(val) # :nodoc:
+ val.pop if val.size == 3 and val.last.nil?
+ val
+ end
+
#
# Switch that takes no arguments.
#
class NoArgument < self
+
#
# Raises an exception if any arguments given.
#
- def parse(arg, argv, &error)
+ def parse(arg, argv)
yield(NeedlessArgument, arg) if arg
conv_arg(arg)
end
- def self.incompatible_argument_styles(*)
+
+ def self.incompatible_argument_styles(*) # :nodoc:
end
- def self.pattern
+
+ def self.pattern # :nodoc:
Object
end
+
+ def pretty_head # :nodoc:
+ "NoArgument"
+ end
end
#
# Switch that takes an argument.
#
class RequiredArgument < self
+
#
# Raises an exception if argument is not present.
#
- def parse(arg, argv, &error)
+ def parse(arg, argv, &_)
unless arg
raise MissingArgument if argv.empty?
arg = argv.shift
end
- conv_arg(*parse_arg(arg, &error))
+ conv_arg(*parse_arg(arg, &method(:raise)))
+ end
+
+ def pretty_head # :nodoc:
+ "Required"
end
end
@@ -463,6 +762,7 @@ class OptionParser
# Switch that can omit argument.
#
class OptionalArgument < self
+
#
# Parses argument if given, or uses default value.
#
@@ -470,50 +770,61 @@ class OptionParser
if arg
conv_arg(*parse_arg(arg, &error))
else
- conv_arg(arg)
+ omitted_argument conv_arg(arg)
end
end
+
+ def pretty_head # :nodoc:
+ "Optional"
+ end
end
#
- # ?
+ # Switch that takes an argument, which does not begin with '-' or is '-'.
#
class PlacedArgument < self
+
#
- # ?
+ # Returns nil if argument is not present or begins with '-' and is not '-'.
#
def parse(arg, argv, &error)
- if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
- return nil, block, nil
+ if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0]))
+ return nil, block
end
opt = (val = parse_arg(val, &error))[1]
val = conv_arg(*val)
if opt and !arg
argv.shift
else
+ omitted_argument val
val[0] = nil
end
val
end
+
+ def pretty_head # :nodoc:
+ "Placed"
+ end
end
end
#
# Simple option list providing mapping from short and/or long option
- # string to ((<OptionParser::Switch>)), and mapping from acceptable
- # argument to matching pattern and converter pair. Also provides
- # summary feature.
+ # string to OptionParser::Switch and mapping from acceptable argument to
+ # matching pattern and converter pair. Also provides summary feature.
#
class List
+ # :nodoc:
+
# Map from acceptable argument types to pattern and converter pairs.
attr_reader :atype
-
+
# Map from short style option switches to actual switch objects.
attr_reader :short
-
+
# Map from long style option switches to actual switch objects.
attr_reader :long
-
+
# List of all switches and summary string.
attr_reader :list
@@ -523,16 +834,28 @@ class OptionParser
def initialize
@atype = {}
@short = OptionMap.new
- @long = OptionCaseMap.new
+ @long = OptionMap.new
@list = []
end
+ def pretty_print(q) # :nodoc:
+ q.group(1, "(", ")") do
+ @list.each do |sw|
+ next unless Switch === sw
+ q.group(1, "(" + sw.pretty_head, ")") do
+ sw.pretty_print_contents(q)
+ end
+ end
+ end
+ end
+
#
# See OptionParser.accept.
#
- def accept(t, pat = /.*/, &block)
+ def accept(t, pat = /.*/m, &block)
if pat
- pat.respond_to?(:match) or raise TypeError, "has no `match'"
+ pat.respond_to?(:match) or
+ raise TypeError, "has no 'match'", ParseError.filter_backtrace(caller(2))
else
pat = t if t.respond_to?(:match)
end
@@ -550,156 +873,156 @@ class OptionParser
end
#
- # OptionParser::List#update(sw, sopts, lopts, nlopts = nil)
+ # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
#
- # Adds ((|sw|)) according to ((|sopts|)), ((|lopts|)) and
- # ((|nlopts|)).
- # :Parameters:
- # : ((|sw|))
- # ((<OptionParser::Switch>)) instance to be added.
- # : ((|sopts|))
- # short style options list.
- # : ((|lopts|))
- # long style options list.
- # : ((|nlopts|))
- # negated long style options list.
+ # +sw+:: OptionParser::Switch instance to be added.
+ # +sopts+:: Short style option list.
+ # +lopts+:: Long style option list.
+ # +nlopts+:: Negated long style options list.
#
- def update(sw, sopts, lopts, nsw = nil, nlopts = nil)
- o = nil
+ private def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
sopts.each {|o| @short[o] = sw} if sopts
lopts.each {|o| @long[o] = sw} if lopts
nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
used = @short.invert.update(@long.invert)
@list.delete_if {|o| Switch === o and !used[o]}
end
- private :update
#
- # OptionParser::List#prepend(switch, short_opts, long_opts, nolong_opts)
+ # Inserts +switch+ at the head of the list, and associates short, long
+ # and negated long options. Arguments are:
+ #
+ # +switch+:: OptionParser::Switch instance to be inserted.
+ # +short_opts+:: List of short style options.
+ # +long_opts+:: List of long style options.
+ # +nolong_opts+:: List of long style options with "no-" prefix.
+ #
+ # prepend(switch, short_opts, long_opts, nolong_opts)
#
- # Inserts ((|switch|)) at head of the list, and associates short,
- # long and negated long options.
def prepend(*args)
update(*args)
@list.unshift(args[0])
end
#
- # OptionParser::List#append(switch, short_opts, long_opts, nolong_opts)
+ # Appends +switch+ at the tail of the list, and associates short, long
+ # and negated long options. Arguments are:
+ #
+ # +switch+:: OptionParser::Switch instance to be inserted.
+ # +short_opts+:: List of short style options.
+ # +long_opts+:: List of long style options.
+ # +nolong_opts+:: List of long style options with "no-" prefix.
+ #
+ # append(switch, short_opts, long_opts, nolong_opts)
#
- # Appends ((|switch|)) at tail of the list, and associates short,
- # long and negated long options.
- # :Parameters:
- # : ((|switch|))
- # ((<OptionParser::Switch>)) instance to be inserted.
- # : ((|short_opts|))
- # list of short style options.
- # : ((|long_opts|))
- # list of long style options.
- # : ((|nolong_opts|))
- # list of long style options with (({"no-"})) prefix.
def append(*args)
update(*args)
@list.push(args[0])
end
#
- # OptionParser::List#search(id, key) [{block}]
- #
- # Searches ((|key|)) in ((|id|)) list.
- # :Parameters:
- # : ((|id|))
- # searching list.
- # : ((|k|))
- # searching key.
- # : (({block}))
- # yielded with the found value when succeeded.
+ # Searches +key+ in +id+ list. The result is returned or yielded if a
+ # block is given. If it isn't found, nil is returned.
#
def search(id, key)
if list = __send__(id)
val = list.fetch(key) {return nil}
- return val unless block_given?
- yield(val)
+ block_given? ? yield(val) : val
end
end
#
- # OptionParser::List#complete(id, opt, *pat, &block)
+ # Searches list +id+ for +opt+ and the optional patterns for completion
+ # +pat+. If +icase+ is true, the search is case insensitive. The result
+ # is returned or yielded if a block is given. If it isn't found, nil is
+ # returned.
#
- # Searches list ((|id|)) for ((|opt|)) and ((|*pat|)).
- # :Parameters:
- # : ((|id|))
- # searching list.
- # : ((|opt|))
- # searching key.
- # : ((|*pat|))
- # optional pattern for completion.
- # : (({block}))
- # yielded with the found value when succeeded.
- #
- def complete(id, opt, *pat, &block)
- __send__(id).complete(opt, *pat, &block)
+ def complete(id, opt, icase = false, *pat, &block)
+ __send__(id).complete(opt, icase, *pat, &block)
end
+ def get_candidates(id)
+ yield __send__(id).keys
+ end
+
+ #
+ # Iterates over each option, passing the option to the +block+.
#
- # OptionParser::List#summarize(*args) {...}
+ def each_option(&block)
+ list.each(&block)
+ end
+
#
- # Making summary table, yields the (({block})) with each lines.
- # Each elements of (({@list})) should be able to (({summarize})).
- # :Parameters:
- # : ((|args|))
- # passed to elements#summarize through.
- # : (({block}))
- # to be passed each lines(without newline).
+ # Creates the summary table, passing each line to the +block+ (without
+ # newline). The arguments +args+ are passed along to the summarize
+ # method which is called on every option.
#
def summarize(*args, &block)
- list.each do |opt|
+ sum = []
+ list.reverse_each do |opt|
if opt.respond_to?(:summarize) # perhaps OptionParser::Switch
- opt.summarize(*args, &block)
- elsif opt.empty?
- yield("")
+ s = []
+ opt.summarize(*args) {|l| s << l}
+ sum.concat(s.reverse)
+ elsif !opt or opt.empty?
+ sum << ""
+ elsif opt.respond_to?(:each_line)
+ sum.concat([*opt.each_line].reverse)
else
- opt.each(&block)
+ sum.concat([*opt.each].reverse)
+ end
+ end
+ sum.reverse_each(&block)
+ end
+
+ def add_banner(to) # :nodoc:
+ list.each do |opt|
+ if opt.respond_to?(:add_banner)
+ opt.add_banner(to)
+ end
+ end
+ to
+ end
+
+ def compsys(*args, &block) # :nodoc:
+ list.each do |opt|
+ if opt.respond_to?(:compsys)
+ opt.compsys(*args, &block)
end
end
end
end
#
- # Hash with completion search feature. See Completion module.
+ # Hash with completion search feature. See OptionParser::Completion.
#
class CompletingHash < Hash
include Completion
#
- # OptionParser::CompletingHash#match(key)
- #
# Completion for hash key.
#
def match(key)
- return key, *fetch(key) {
+ *values = fetch(key) {
raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
}
+ return key, *values
end
end
+ # :stopdoc:
+
#
- # OptionParser::ArgumentStyle
- # Enumeration of acceptable argument styles; possible values are:
- # : OptionParser::NO_ARGUMENT
- # the switch takes no arguments. ((({:NONE})))
- # : OptionParser::REQUIRED_ARGUMENT
- # the switch requires an argument. ((({:REQUIRED})))
- # : OptionParser::OPTIONAL_ARGUMENT
- # the switch requires an optional argument, that is, may take or
- # not. ((({:OPTIONAL})))
+ # Enumeration of acceptable argument styles. Possible values are:
#
- # Use like (({--switch=argument}))(long style) or
- # (({-Xargument}))(short style). For short style, only portion
- # matched to ((<argument pattern>)) is dealed as argument.
+ # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
+ # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
+ # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
+ #
+ # Use like --switch=argument (long style) or -Xargument (short style). For
+ # short style, only portion matched to argument pattern is treated as
+ # argument.
#
-
- # :stopdoc:
ArgumentStyle = {}
NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
@@ -707,41 +1030,107 @@ class OptionParser
ArgumentStyle.freeze
#
- # OptionParser::DefaultList
- #
# Switches common used such as '--', and also provides default
# argument classes
#
-
DefaultList = List.new
DefaultList.short['-'] = Switch::NoArgument.new {}
DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
+ COMPSYS_HEADER = <<'XXX' # :nodoc:
+
+typeset -A opt_args
+local context state line
+
+_arguments -s -S \
+XXX
+
+ def compsys(to, name = File.basename($0)) # :nodoc:
+ to << "#compdef #{name}\n"
+ to << COMPSYS_HEADER
+ visit(:compsys, {}, {}) {|o, d|
+ to << %Q[ "#{o}[#{d.gsub(/[\\\"\[\]]/, '\\\\\&')}]" \\\n]
+ }
+ to << " '*:file:_files' && return 0\n"
+ end
+
+ def help_exit
+ if $stdout.tty? && (pager = ENV.values_at(*%w[RUBY_PAGER PAGER]).find {|e| e && !e.empty?})
+ less = ENV["LESS"]
+ args = [{"LESS" => "#{less} -Fe"}, pager, "w"]
+ print = proc do |f|
+ f.puts help
+ rescue Errno::EPIPE
+ # pager terminated
+ end
+ if Process.respond_to?(:fork) and false
+ IO.popen("-") {|f| f ? Process.exec(*args, in: f) : print.call($stdout)}
+ # unreachable
+ end
+ IO.popen(*args, &print)
+ else
+ puts help
+ end
+ exit
+ end
+
#
- # Default options, which never appear in option summary.
- # --help
- # Shows option summary.
- # --version
- # Shows version string if (({::Version})) is defined.
+ # Default options for ARGV, which never appear in option summary.
#
- DefaultList.long['help'] = Switch::NoArgument.new do
- puts ARGV.options
- exit
+ Officious = {}
+
+ #
+ # --help
+ # Shows option summary.
+ #
+ Officious['help'] = proc do |parser|
+ Switch::NoArgument.new do |arg|
+ parser.help_exit
+ end
end
- DefaultList.long['version'] = Switch::OptionalArgument.new do |pkg|
- if pkg
- begin
- require 'optparse/version'
- rescue LoadError
- pkg = nil
- else
- show_version(*pkg.split(/,/))
- end
+
+ #
+ # --*-completion-bash=WORD
+ # Shows candidates for command line completion.
+ #
+ Officious['*-completion-bash'] = proc do |parser|
+ Switch::RequiredArgument.new do |arg|
+ puts parser.candidate(arg)
+ exit
end
- unless pkg
- v = ARGV.options.ver and puts v
+ end
+
+ #
+ # --*-completion-zsh[=NAME:FILE]
+ # Creates zsh completion file.
+ #
+ Officious['*-completion-zsh'] = proc do |parser|
+ Switch::OptionalArgument.new do |arg|
+ parser.compsys($stdout, arg)
+ exit
+ end
+ end
+
+ #
+ # --version
+ # Shows version string if Version is defined.
+ #
+ Officious['version'] = proc do |parser|
+ Switch::OptionalArgument.new do |pkg|
+ if pkg
+ begin
+ require_relative 'optparse/version'
+ rescue LoadError
+ else
+ show_version(*pkg.split(/,/)) or
+ abort("#{parser.program_name}: no version found in package #{pkg}")
+ exit
+ end
+ end
+ v = parser.ver or abort("#{parser.program_name}: version unknown")
+ puts v
+ exit
end
- exit
end
# :startdoc:
@@ -750,34 +1139,23 @@ class OptionParser
# Class methods
#
-=begin
---- OptionParser.with([banner[, width[, indent]]]) [{...}]
- Initializes new instance, and evaluates the block in context of
- the instance if called as iterator. This behavior is equivalent
- to older (({new})). This is ((*deprecated*)) method.
-
- cf. ((<OptionParser.new>))
- :Parameters:
- : ((|banner|))
- banner message.
- : ((|width|))
- summary width.
- : ((|indent|))
- summary indent.
- : (({block}))
- to be evaluated in the new instance context.
-=end #'#"#`#
+ #
+ # Initializes a new instance and evaluates the optional block in context
+ # of the instance. Arguments +args+ are passed to #new, see there for
+ # description of parameters.
+ #
+ # This method is *deprecated*, its behavior corresponds to the older #new
+ # method.
+ #
def self.with(*args, &block)
opts = new(*args)
opts.instance_eval(&block)
opts
end
-=begin
---- OptionParser.inc(arg[, default])
---- OptionParser#inc(arg[, default])
- Returns incremented value of ((|default|)) according to ((|arg|)).
-=end
+ #
+ # Returns an incremented value of +default+ according to +arg+.
+ #
def self.inc(arg, default = nil)
case arg
when Integer
@@ -786,170 +1164,223 @@ class OptionParser
default.to_i + 1
end
end
+
+ #
+ # See self.inc
+ #
def inc(*args)
self.class.inc(*args)
end
-=begin
---- OptionParser.new([banner[, width[, indent]]]) [{...}]
- Initializes the instance, and yields itself if called as iterator.
- :Parameters:
- : ((|banner|))
- banner message.
- : ((|width|))
- summary width.
- : ((|indent|))
- summary indent.
- : (({block}))
- to be evaluated in the new instance context.
-=end #'#"#`#
+ #
+ # Initializes the instance and yields itself if called with a block.
+ #
+ # +banner+:: Banner message.
+ # +width+:: Summary width.
+ # +indent+:: Summary indent.
+ #
def initialize(banner = nil, width = 32, indent = ' ' * 4)
@stack = [DefaultList, List.new, List.new]
@program_name = nil
@banner = banner
@summary_width = width
@summary_indent = indent
+ @default_argv = ARGV
+ @require_exact = false
+ @raise_unknown = true
+ add_officious
yield self if block_given?
end
-=begin
---- OptionParser.terminate([arg])
- Terminates option parsing. Optional parameter ((|arg|)) would be
- pushed back if given.
- :Parameters:
- : ((|arg|))
- string pushed back to be first non-option argument
-=end #'#"#`#
+ def add_officious # :nodoc:
+ list = base()
+ Officious.each do |opt, block|
+ list.long[opt] ||= block.call(self)
+ end
+ end
+
+ #
+ # Terminates option parsing. Optional parameter +arg+ is a string pushed
+ # back to be the first non-option argument.
+ #
def terminate(arg = nil)
self.class.terminate(arg)
end
+ #
+ # See #terminate.
+ #
def self.terminate(arg = nil)
throw :terminate, arg
end
@stack = [DefaultList]
+ #
+ # Returns the global top option list.
+ #
+ # Do not use directly.
+ #
def self.top() DefaultList end
-=begin
---- OptionParser.accept(t, [pat]) {...}
---- OptionParser#accept(t, [pat]) {...}
- Directs to accept specified class argument.
- :Parameters:
- : ((|t|))
- argument class specifier, any object including Class.
- : ((|pat|))
- pattern for argument, defaulted to ((|t|)) if it respond to (({match})).
- : (({block}))
- receives argument string and should be convert to desired class.
-=end #'#"#`#
+ #
+ # Directs to accept specified class +t+. The argument string is passed to
+ # the block in which it should be converted to the desired class.
+ #
+ # +t+:: Argument class specifier, any object including Class.
+ # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
+ #
+ # accept(t, pat, &block)
+ #
def accept(*args, &blk) top.accept(*args, &blk) end
+ #
+ # See #accept.
+ #
def self.accept(*args, &blk) top.accept(*args, &blk) end
-=begin
---- OptionParser.reject(t)
---- OptionParser#reject(t)
- Directs to reject specified class argument.
- :Parameters:
- : ((|t|))
- argument class specifier, any object including Class.
-=end #'#"#`#
+ #
+ # Directs to reject specified class argument.
+ #
+ # +type+:: Argument class specifier, any object including Class.
+ #
+ # reject(type)
+ #
def reject(*args, &blk) top.reject(*args, &blk) end
+ #
+ # See #reject.
+ #
def self.reject(*args, &blk) top.reject(*args, &blk) end
-
-=begin
-=== Instance methods
-=end #'#"#`#
-
-=begin
---- OptionParser#banner
---- OptionParser#banner=(heading)
- Heading banner preceding summary.
---- OptionParser#summary_width
---- OptionParser#summary_width=(width)
- Width for option list portion of summary. Must be (({Numeric})).
---- OptionParser#summary_indent
---- OptionParser#summary_indent=(indent)
- Indentation for summary. Must be (({String})) (or have (({+ String}))).
---- OptionParser#program_name
---- OptionParser#program_name=(name)
- Program name to be emitted in error message and default banner,
- defaulted to (({$0})).
-=end #'#"#`#
- attr_writer :banner, :program_name
- attr_accessor :summary_width, :summary_indent
+ #
+ # Instance methods
+ #
+
+ # Heading banner preceding summary.
+ attr_writer :banner
+
+ # Program name to be emitted in error message and default banner,
+ # defaults to $0.
+ attr_writer :program_name
+
+ # Width for option list portion of summary. Must be Numeric.
+ attr_accessor :summary_width
+
+ # Indentation for summary. Must be String (or have + String method).
+ attr_accessor :summary_indent
+ # Strings to be parsed in default.
+ attr_accessor :default_argv
+
+ # Whether to require that options match exactly (disallows providing
+ # abbreviated long option as short option).
+ attr_accessor :require_exact
+
+ # Whether to raise at unknown option.
+ attr_accessor :raise_unknown
+
+ #
+ # Heading banner preceding summary.
+ #
def banner
- @banner ||= "Usage: #{program_name} [options]"
+ unless @banner
+ @banner = +"Usage: #{program_name} [options]"
+ visit(:add_banner, @banner)
+ end
+ @banner
end
+ #
+ # Program name to be emitted in error message and default banner, defaults
+ # to $0.
+ #
def program_name
- @program_name || File.basename($0, '.*')
+ @program_name || strip_ext(File.basename($0))
end
-# for experimental cascading :-)
+ private def strip_ext(name) # :nodoc:
+ exts = /#{
+ require "rbconfig"
+ Regexp.union(*RbConfig::CONFIG["EXECUTABLE_EXTS"]&.split(" "))
+ }\z/o
+ name.sub(exts, "")
+ end
+
+ # for experimental cascading :-)
alias set_banner banner=
alias set_program_name program_name=
alias set_summary_width summary_width=
alias set_summary_indent summary_indent=
-=begin
---- OptionParser#version
---- OptionParser#version=(ver)
- Version.
---- OptionParser#release
---- OptionParser#release=(rel)
- Release code.
---- OptionParser#ver
- Returns version string from ((<program_name>)), (({version})) and
- (({release})).
-=end #'#"#`#
- attr_writer :version, :release
+ # Version
+ attr_writer :version
+ # Release code
+ attr_writer :release
+ #
+ # Version
+ #
def version
- @version || (defined?(::Version) && ::Version) || (defined?(::VERSION) && ::VERSION)
+ (defined?(@version) && @version) || (defined?(::Version) && ::Version)
end
+ #
+ # Release code
+ #
def release
- @release || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
+ (defined?(@release) && @release) || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
end
+ #
+ # Returns version string from program_name, version and release.
+ #
def ver
if v = version
- str = "#{program_name} #{[v].join('.')}"
+ str = +"#{program_name} #{[v].join('.')}"
str << " (#{v})" if v = release
str
end
end
+ #
+ # Shows warning message with the program name
+ #
+ # +mesg+:: Message, defaulted to +$!+.
+ #
+ # See Kernel#warn.
+ #
def warn(mesg = $!)
- super(program_name + ': ' + mesg)
+ super("#{program_name}: #{mesg}")
end
+ #
+ # Shows message with the program name then aborts.
+ #
+ # +mesg+:: Message, defaulted to +$!+.
+ #
+ # See Kernel#abort.
+ #
def abort(mesg = $!)
- super(program_name + ': ' + mesg)
+ super("#{program_name}: #{mesg}")
end
-=begin
---- OptionParser#top
- Subject of ((<on>))/((<on_head>)), ((<accept>))/((<reject>)).
-=end #'#"#`#
+ #
+ # Subject of #on / #on_head, #accept / #reject
+ #
def top
@stack[-1]
end
-=begin
---- OptionParser#base
- Subject of ((<on_tail>)).
-=end #'#"#`#
+ #
+ # Subject of #on_tail.
+ #
def base
@stack[1]
end
-=begin
---- OptionParser#new
- Pushes a new (({List})).
-=end #'#"#`#
+ #
+ # Pushes a new List.
+ #
+ # If a block is given, yields +self+ and returns the result of the
+ # block, otherwise returns +self+.
+ #
def new
@stack.push(List.new)
if block_given?
@@ -959,120 +1390,95 @@ class OptionParser
end
end
-=begin
---- OptionParser#remove
- Removes the last (({List})).
-=end #'#"#`#
+ #
+ # Removes the last List.
+ #
def remove
@stack.pop
end
-
-=begin
---- OptionParser#summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent)
- Puts option summary into ((|to|)), and returns ((|to|)).
- :Parameters:
- : ((|to|))
- output destination, which must have method ((|<<|)). Defaulted to (({[]})).
- : ((|width|))
- width of left side. Defaulted to ((|@summary_width|))
- : ((|max|))
- maximum length allowed for left side. Defaulted to (({((|width|)) - 1}))
- : ((|indent|))
- indentation. Defaulted to ((|@summary_indent|))
- : (({block}))
- yields with each line if called as iterator.
-=end #'#"#`#
+ #
+ # Puts option summary into +to+ and returns +to+. Yields each line if
+ # a block is given.
+ #
+ # +to+:: Output destination, which must have method <<. Defaults to [].
+ # +width+:: Width of left side, defaults to @summary_width.
+ # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
+ # +indent+:: Indentation, defaults to @summary_indent.
+ #
def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
- visit(:summarize, {}, {}, width, max, indent, &(blk || proc {|l| to << l + $/}))
+ nl = "\n"
+ blk ||= proc {|l| to << (l.index(nl, -1) ? l : l + nl)}
+ visit(:summarize, {}, {}, width, max, indent, &blk)
to
end
-=begin
---- OptionParser#help
---- OptionParser#to_s
- Returns option summary string.
-=end #'#"#`#
- def help; summarize(banner.to_s.sub(/\n?\z/, "\n")) end
+ #
+ # Returns option summary string.
+ #
+ def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
alias to_s help
-=begin
---- OptionParser#to_a
- Returns option summary list.
-=end #'#"#`#
- def to_a; summarize(banner.to_a.dup) end
-
-
-=begin
---- OptionParser#switch
- Creates ((<OptionParser::Switch>)).
- :Parameters:
- : ((|*opts|))
- option definition:
- : argument style
- see ((<OptionParser::ArgumentStyle>))
- : argument pattern
- acceptable option argument format, must pre-defined with
- ((<OptionParser.accept>)) or ((<OptionParser#accept>)), or
- (({Regexp})). This can appear once or assigned as (({String}))
- if not present, otherwise causes exception (({ArgumentError})).
-
- cf. ((<Acceptable argument classes>)).
- : Hash
- : Array
- possible argument values.
- : Proc
- : Method
- alternative way to give the ((*handler*)).
- : "--switch=MANDATORY", "--switch[=OPTIONAL]", "--switch"
- specifies long style switch that takes ((*mandatory*)),
- ((*optional*)) and ((*no*)) argument, respectively.
- : "-xMANDATORY", "-x[OPTIONAL]", "-x"
- specifies short style switch that takes ((*mandatory*)),
- ((*optional*)) and ((*no*)) argument, respectively.
- : "-[a-z]MANDATORY", "-[a-z][OPTIONAL]", "-[a-z]"
- special form short style switch that matches character
- range(not fullset of regular expression).
- : "=MANDATORY", "=[OPTIONAL]"
- argument style and description.
- : "description", ...
- ((*description*)) for this option.
- : (({block}))
- ((*handler*)) to convert option argument to arbitrary (({Class})).
-=end #'#"#`#
-=begin private
---- OptionParser#notwice(obj, prv, msg)
- Checks never given twice an argument.
- ((*Called from OptionParser#switch only*))
- :Parameters:
- : ((|obj|))
- new argument.
- : ((|prv|))
- previously specified argument.
- : ((|msg|))
- exception message
-=end #'#"#`#
- def notwice(obj, prv, msg)
- unless !prv or prv == obj
- begin
- raise ArgumentError, "argument #{msg} given twice: #{obj}"
- rescue
- $@[0, 2] = nil
- raise
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) do
+ first = true
+ if @stack.size > 2
+ @stack.each_with_index do |s, i|
+ next if i < 2
+ next if s.list.empty?
+ if first
+ first = false
+ q.text ":"
+ end
+ q.breakable
+ s.pretty_print(q)
+ end
end
end
+ end
+
+ def inspect # :nodoc:
+ require 'pp'
+ pretty_print_inspect
+ end
+
+ #
+ # Returns option summary list.
+ #
+ def to_a; summarize("#{banner}".split(/^/)) end
+
+ #
+ # Checks if an argument is given twice, in which case an ArgumentError is
+ # raised. Called from OptionParser#switch only.
+ #
+ # +obj+:: New argument.
+ # +prv+:: Previously specified argument.
+ # +msg+:: Exception message.
+ #
+ private def notwice(obj, prv, msg) # :nodoc:
+ unless !prv or prv == obj
+ raise(ArgumentError, "argument #{msg} given twice: #{obj}",
+ ParseError.filter_backtrace(caller(2)))
+ end
obj
end
- private :notwice
- def make_switch(*opts, &block)
+ SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a} # :nodoc:
+
+ # :call-seq:
+ # make_switch(params, block = nil)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def make_switch(opts, block = nil)
short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
ldesc, sdesc, desc, arg = [], [], []
default_style = Switch::NoArgument
default_pattern = nil
klass = nil
- o = nil
- n, q, a = nil
+ q, a = nil
+ has_arg = false
+ values = nil
opts.each do |o|
# argument class
@@ -1086,9 +1492,13 @@ class OptionParser
end
# directly specified pattern(any object possible to match)
- if !(String === o) and o.respond_to?(:match)
+ if !Completion.completable?(o) and o.respond_to?(:match)
pattern = notwice(o, pattern, 'pattern')
- conv = (pattern.method(:convert).to_proc if pattern.respond_to?(:convert))
+ if pattern.respond_to?(:convert)
+ conv = pattern.method(:convert).to_proc
+ else
+ conv = SPLAT_PROC
+ end
next
end
@@ -1096,21 +1506,28 @@ class OptionParser
case o
when Proc, Method
block = notwice(o, block, 'block')
- when Array, Hash
+ when Array, Hash, Set
+ if Array === o
+ o, v = o.partition {|v,| Completion.completable?(v)}
+ values = notwice(v, values, 'values') unless v.empty?
+ next if o.empty?
+ end
case pattern
when CompletingHash
when nil
pattern = CompletingHash.new
- conv = (pattern.method(:convert).to_proc if pattern.respond_to?(:convert))
+ conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
else
raise ArgumentError, "argument pattern given twice"
end
- o.each {|(o, *v)| pattern[o] = v.fetch(0) {o}}
+ o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
+ when Range
+ values = notwice(o, values, 'values')
when Module
- raise ArgumentError, "unsupported argument type: #{o}"
+ raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
when *ArgumentStyle.keys
style = notwice(ArgumentStyle[o], style, 'style')
- when /^--no-([^\[\]=\s]*)(.+)?/
+ when /\A--no-([^\[\]=\s]*)(.+)?/
q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type')
not_pattern, not_conv = search(:atype, o) unless not_style
@@ -1118,9 +1535,10 @@ class OptionParser
default_style = Switch::NoArgument
default_pattern, conv = search(:atype, FalseClass) unless default_pattern
ldesc << "--no-#{q}"
- long << 'no-' + (q = q.downcase)
+ (q = q.downcase).tr!('_', '-')
+ long << "no-#{q}"
nolong << q
- when /^--\[no-\]([^\[\]=\s]*)(.+)?/
+ when /\A--\[no-\]([^\[\]=\s]*)(.+)?/
q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type')
if a
@@ -1128,11 +1546,12 @@ class OptionParser
default_pattern, conv = search(:atype, o) unless default_pattern
end
ldesc << "--[no-]#{q}"
- long << (o = q.downcase)
+ (o = q.downcase).tr!('_', '-')
+ long << o
not_pattern, not_conv = search(:atype, FalseClass) unless not_style
not_style = Switch::NoArgument
- nolong << 'no-' + o
- when /^--([^\[\]=\s]*)(.+)?/
+ nolong << "no-#{o}"
+ when /\A--([^\[\]=\s]*)(.+)?/
q, a = $1, $2
if a
o = notwice(NilClass, klass, 'type')
@@ -1140,17 +1559,20 @@ class OptionParser
default_pattern, conv = search(:atype, o) unless default_pattern
end
ldesc << "--#{q}"
- long << (o = q.downcase)
- when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
+ (o = q.downcase).tr!('_', '-')
+ long << o
+ when /\A-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
q, a = $1, $2
o = notwice(Object, klass, 'type')
if a
default_style = default_style.guess(arg = a)
default_pattern, conv = search(:atype, o) unless default_pattern
+ else
+ has_arg = true
end
sdesc << "-#{q}"
short << Regexp.new(q)
- when /^-(.)(.+)?/
+ when /\A-(.)(.+)?/
q, a = $1, $2
if a
o = notwice(NilClass, klass, 'type')
@@ -1159,129 +1581,200 @@ class OptionParser
end
sdesc << "-#{q}"
short << q
- when /^=/
+ when /\A=/
style = notwice(default_style.guess(arg = o), style, 'style')
default_pattern, conv = search(:atype, Object) unless default_pattern
else
- desc.push(o)
+ desc.push(o) if o && !o.empty?
end
end
default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
- s = if short.empty? and long.empty?
- raise ArgumentError, "no switch given" if style or pattern or block
- desc
- else
- (style || default_style).new(pattern || default_pattern,
- conv, sdesc, ldesc, arg, desc, block)
- end
+ if Range === values and klass
+ unless (!values.begin or klass === values.begin) and
+ (!values.end or klass === values.end)
+ raise ArgumentError, "range does not match class"
+ end
+ end
+ if !(short.empty? and long.empty?)
+ if has_arg and default_style == Switch::NoArgument
+ default_style = Switch::RequiredArgument
+ end
+ s = (style || default_style).new(pattern || default_pattern,
+ conv, sdesc, ldesc, arg, desc, block, values)
+ elsif !block
+ if style or pattern
+ raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
+ end
+ s = desc
+ else
+ short << pattern
+ s = (style || default_style).new(pattern,
+ conv, nil, nil, arg, desc, block, values)
+ end
return s, short, long,
(not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
nolong
end
-=begin
---- OptionParser#on(*opts) [{...}]
---- OptionParser#def_option(*opts) [{...}]
---- OptionParser#on_head(*opts) [{...}]
---- OptionParser#def_head_option(*opts) [{...}]
---- OptionParser#on_tail(*opts) [{...}]
---- OptionParser#def_tail_option(*opts) [{...}]
- Defines option switch and handler. (({on_head})), (({def_head_option}))
- and (({on_tail})), (({def_tail_option})) put the switch at head
- and tail of summary, respectively.
+ # ----
+ # Option definition phase methods
+ #
+ # These methods are used to define options, or to construct an
+ # OptionParser instance in other words.
- cf. ((<OptionParser#switch>)).
-=end #'#"#`#
+ # :call-seq:
+ # define(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
def define(*opts, &block)
- top.append(*(sw = make_switch(*opts, &block)))
+ top.append(*(sw = make_switch(opts, block)))
sw[0]
end
+
+ # :call-seq:
+ # on(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
def on(*opts, &block)
define(*opts, &block)
self
end
alias def_option define
+ # :call-seq:
+ # define_head(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
def define_head(*opts, &block)
- top.prepend(*(sw = make_switch(*opts, &block)))
+ top.prepend(*(sw = make_switch(opts, block)))
sw[0]
end
+
+ # :call-seq:
+ # on_head(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ # The new option is added at the head of the summary.
+ #
def on_head(*opts, &block)
define_head(*opts, &block)
self
end
alias def_head_option define_head
+ # :call-seq:
+ # define_tail(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
def define_tail(*opts, &block)
- base.append(*(sw = make_switch(*opts, &block)))
+ base.append(*(sw = make_switch(opts, block)))
sw[0]
end
+
+ #
+ # :call-seq:
+ # on_tail(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ # The new option is added at the tail of the summary.
+ #
def on_tail(*opts, &block)
define_tail(*opts, &block)
self
end
alias def_tail_option define_tail
+ #
+ # Add separator in summary.
+ #
def separator(string)
top.append(string, nil, nil)
end
-
-=begin
---- OptionParser#order(*argv) [{...}]
---- OptionParser#order!([argv = ARGV]) [{...}]
- Parses ((|argv|)) in order. When non-option argument encountered,
- yields it if called as iterator, otherwise terminates the parse
- process.
- Returns rest of ((|argv|)) left unparsed.
-
- (({order!})) takes argument array itself, and removes switches
- destructively.
- Defaults to parse ((|ARGV|)).
- :Parameters:
- : ((|argv|))
- command line arguments to be parsed.
- : (({block}))
- called with each non-option argument.
-=end #'#"#`#
- def order(*argv, &block)
+ # ----
+ # Arguments parse phase methods
+ #
+ # These methods parse +argv+, convert, and store the results by
+ # calling handlers. As these methods do not modify +self+, +self+
+ # can be frozen.
+
+ #
+ # Parses command line arguments +argv+ in order. When a block is given,
+ # each non-option argument is yielded. When optional +into+ keyword
+ # argument is provided, the parsed option values are stored there via
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
+ # similar object).
+ #
+ # Returns the rest of +argv+ left unparsed.
+ #
+ def order(*argv, **keywords, &nonopt)
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- order!(argv, &block)
+ order!(argv, **keywords, &nonopt)
end
- def order!(argv = ARGV, &nonopt)
- opt, arg, sw, val, rest = nil
- nonopt ||= proc {|arg| throw :terminate, arg}
+ #
+ # Same as #order, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def order!(argv = default_argv, into: nil, **keywords, &nonopt)
+ setter = ->(name, val) {into[name.to_sym] = val} if into
+ parse_in_order(argv, setter, **keywords, &nonopt)
+ end
+
+ private def parse_in_order(argv = default_argv, setter = nil, exact: require_exact, **, &nonopt) # :nodoc:
+ opt, arg, val, rest = nil
+ nonopt ||= proc {|a| throw :terminate, a}
argv.unshift(arg) if arg = catch(:terminate) {
while arg = argv.shift
case arg
# long option
- when /\A--([^=]*)(?:=(.*))?/
+ when /\A--([^=]*)(?:=(.*))?/m
opt, rest = $1, $2
+ opt.tr!('_', '-')
begin
- sw, = complete(:long, opt)
+ if exact
+ sw, = search(:long, opt)
+ else
+ sw, = complete(:long, opt, true)
+ end
rescue ParseError
+ throw :terminate, arg unless raise_unknown
raise $!.set_option(arg, true)
+ else
+ unless sw
+ throw :terminate, arg unless raise_unknown
+ raise InvalidOption, arg
+ end
end
begin
- opt, sw, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
- sw.call(val) if sw
+ opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
+ val = callback!(cb, 1, val) if cb
+ callback!(setter, 2, sw.switch_name, val) if setter
rescue ParseError
raise $!.set_option(arg, rest)
end
# short option
- when /\A-(.)((=).*|.+)?/
- opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2
+ when /\A-(.)((=).*|.+)?/m
+ eq, rest, opt = $3, $2, $1
+ has_arg, val = eq, rest
begin
- unless sw = search(:short, opt)
+ sw, = search(:short, opt)
+ unless sw
begin
sw, = complete(:short, opt)
# short option matched.
- val = arg.sub(/\A-/, '')
+ val = arg.delete_prefix('-')
has_arg = true
rescue InvalidOption
+ raise if exact
# if no short options match, try completion with long
# options.
sw, = complete(:long, opt)
@@ -1289,320 +1782,504 @@ class OptionParser
end
end
rescue ParseError
+ throw :terminate, arg unless raise_unknown
raise $!.set_option(arg, true)
end
begin
- opt, sw, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
+ opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
+ rescue ParseError
+ raise $!.set_option(arg, arg.length > 2)
+ else
raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
- argv.unshift(opt) if opt and (opt = opt.sub(/\A-*/, '-')) != '-'
- sw.call(val) if sw
+ end
+ begin
+ argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
+ val = callback!(cb, 1, val) if cb
+ callback!(setter, 2, sw.switch_name, val) if setter
rescue ParseError
raise $!.set_option(arg, arg.length > 2)
end
# non-option argument
else
- nonopt.call(arg)
+ catch(:prune) do
+ visit(:each_option) do |sw0|
+ sw = sw0
+ sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
+ end
+ nonopt.call(arg)
+ end
end
end
nil
}
+ visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
+
argv
end
-=begin
---- OptionParser#permute(*argv)
---- OptionParser#permute!([argv = ARGV])
- Parses ((|argv|)) in permutation mode, and returns list of
- non-option arguments.
-
- (({permute!})) takes argument array itself, and removes switches
- destructively.
- Defaults to parse ((|ARGV|)).
- :Parameters:
- : ((|argv|))
- command line arguments to be parsed.
-=end #'#"#`#
- def permute(*argv)
+ # Calls callback with _val_.
+ private def callback!(cb, max_arity, *args) # :nodoc:
+ args.compact!
+
+ if (size = args.size) < max_arity and cb.to_proc.lambda?
+ (arity = cb.arity) < 0 and arity = (1-arity)
+ arity = max_arity if arity > max_arity
+ args[arity - 1] = nil if arity > size
+ end
+ cb.call(*args)
+ end
+
+ #
+ # Parses command line arguments +argv+ in permutation mode and returns
+ # list of non-option arguments. When optional +into+ keyword
+ # argument is provided, the parsed option values are stored there via
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
+ # similar object).
+ #
+ def permute(*argv, **keywords)
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- permute!(argv)
+ permute!(argv, **keywords)
end
- def permute!(argv = ARGV)
+ #
+ # Same as #permute, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def permute!(argv = default_argv, **keywords)
nonopts = []
- arg = nil
- order!(argv) {|arg| nonopts << arg}
+ order!(argv, **keywords) {|nonopt| nonopts << nonopt}
argv[0, 0] = nonopts
argv
end
-=begin
---- OptionParser#parse(*argv)
---- OptionParser#parse!([argv = ARGV])
- Parses ((|argv|)) in order when environment variable (({POSIXLY_CORRECT}))
- is set, otherwise permutation mode
-
- (({parse!})) takes argument array itself, and removes switches
- destructively.
- Defaults to parse ((|ARGV|)).
- :Parameters:
- : ((|argv|))
- command line arguments to be parsed.
-=end #'#"#`#
- def parse(*argv)
+ #
+ # Parses command line arguments +argv+ in order when environment variable
+ # POSIXLY_CORRECT is set, and in permutation mode otherwise.
+ # When optional +into+ keyword argument is provided, the parsed option
+ # values are stored there via <code>[]=</code> method (so it can be Hash,
+ # or OpenStruct, or other similar object).
+ #
+ def parse(*argv, **keywords)
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- parse!(argv)
+ parse!(argv, **keywords)
end
- def parse!(argv = ARGV)
+ #
+ # Same as #parse, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def parse!(argv = default_argv, **keywords)
if ENV.include?('POSIXLY_CORRECT')
- order!(argv)
+ order!(argv, **keywords)
else
- permute!(argv)
- end
- end
-
-
-=begin private
---- OptionParser#visit(id, *args) {block}
- Traverses (({stack}))s calling method ((|id|)) with ((|*args|)).
- :Parameters:
- : ((|id|))
- called method in each elements of (({stack}))s.
- : ((|*args|))
- passed to ((|id|)).
- : (({block}))
- passed to ((|id|)).
-=end #'#"#`#
- def visit(id, *args, &block)
- el = nil
+ permute!(argv, **keywords)
+ end
+ end
+
+ #
+ # Wrapper method for getopts.rb.
+ #
+ # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
+ # # params["a"] = true # -a
+ # # params["b"] = "1" # -b1
+ # # params["foo"] = "1" # --foo
+ # # params["bar"] = "x" # --bar x
+ # # params["zot"] = "z" # --zot Z
+ #
+ # Option +symbolize_names+ (boolean) specifies whether returned Hash keys should be Symbols; defaults to +false+ (use Strings).
+ #
+ # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option", symbolize_names: true)
+ # # params[:a] = true # -a
+ # # params[:b] = "1" # -b1
+ # # params[:foo] = "1" # --foo
+ # # params[:bar] = "x" # --bar x
+ # # params[:zot] = "z" # --zot Z
+ #
+ def getopts(*args, symbolize_names: false, **keywords)
+ argv = Array === args.first ? args.shift : default_argv
+ single_options, *long_options = *args
+
+ result = {}
+ setter = (symbolize_names ?
+ ->(name, val) {result[name.to_sym] = val}
+ : ->(name, val) {result[name] = val})
+
+ single_options.scan(/(.)(:)?/) do |opt, val|
+ if val
+ setter[opt, nil]
+ define("-#{opt} VAL")
+ else
+ setter[opt, false]
+ define("-#{opt}")
+ end
+ end if single_options
+
+ long_options.each do |arg|
+ arg, desc = arg.split(';', 2)
+ opt, val = arg.split(':', 2)
+ if val
+ setter[opt, (val unless val.empty?)]
+ define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
+ else
+ setter[opt, false]
+ define("--#{opt}", *[desc].compact)
+ end
+ end
+
+ parse_in_order(argv, setter, **keywords)
+ result
+ end
+
+ #
+ # See #getopts.
+ #
+ def self.getopts(*args, symbolize_names: false)
+ new.getopts(*args, symbolize_names: symbolize_names)
+ end
+
+ #
+ # Traverses @stack, sending each element method +id+ with +args+ and
+ # +block+.
+ #
+ private def visit(id, *args, &block) # :nodoc:
@stack.reverse_each do |el|
- el.send(id, *args, &block)
+ el.__send__(id, *args, &block)
end
nil
end
- private :visit
-
-=begin private
---- OptionParser#search(id, k)
- Searches ((|k|)) in stack for ((|id|)) hash, and returns it or yielded
- value if called as iterator.
- :Parameters:
- : ((|id|))
- searching table.
- : ((|k|))
- searching key.
- : (({block}))
- yielded with the found value when succeeded.
-=end #'#"#`#
- def search(id, k)
- visit(:search, id, k) do |k|
- return k unless block_given?
- return yield(k)
- end
- end
- private :search
-
-=begin private
---- OptionParser#complete(typ, opt, *etc)
- Completes shortened long style option switch, and returns pair of
- canonical switch and switch descriptor((<OptionParser::Switch>)).
- :Parameters:
- : ((|id|))
- searching table.
- : ((|opt|))
- searching key.
- : ((|*pat|))
- optional pattern for completion.
- : (({block}))
- yielded with the found value when succeeded.
-=end #'#"#`#
- def complete(typ, opt, *pat)
+
+ #
+ # Searches +key+ in @stack for +id+ hash and returns or yields the result.
+ #
+ private def search(id, key) # :nodoc:
+ block_given = block_given?
+ visit(:search, id, key) do |k|
+ return block_given ? yield(k) : k
+ end
+ end
+
+ #
+ # Completes shortened long style option switch and returns pair of
+ # canonical switch and switch descriptor OptionParser::Switch.
+ #
+ # +typ+:: Searching table.
+ # +opt+:: Searching key.
+ # +icase+:: Search case insensitive if true.
+ # +pat+:: Optional pattern for completion.
+ #
+ private def complete(typ, opt, icase = false, *pat) # :nodoc:
if pat.empty?
search(typ, opt) {|sw| return [sw, opt]} # exact match or...
end
- raise AmbiguousOption, catch(:ambiguous) {
- visit(:complete, typ, opt, *pat) {|opt, *sw| return sw}
- raise InvalidOption, opt
+ ambiguous = catch(:ambiguous) {
+ visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
}
+ exc = ambiguous ? AmbiguousOption : InvalidOption
+ raise exc.new(opt, additional: proc {|o| additional_message(typ, o)})
end
- private :complete
-
-=begin undocumented
---- OptionParser#load([filename])
- Loads options from file named as ((|filename|)). Does nothing when
- the file is not present. Returns whether successfuly loaded.
- :Parameters:
- : ((|filename|))
- option file name. defaulted to basename of the program without
- suffix in a directory ((%~/.options%)).
-=end #'#"#`#
- def load(filename = nil)
- begin
- filename ||= File.expand_path(File.basename($0, '.*'), '~/.options')
- rescue
- return false
+
+ #
+ # Returns additional info.
+ #
+ def additional_message(typ, opt)
+ return unless typ and opt and defined?(DidYouMean::SpellChecker)
+ all_candidates = []
+ visit(:get_candidates, typ) do |candidates|
+ all_candidates.concat(candidates)
+ end
+ all_candidates.select! {|cand| cand.is_a?(String) }
+ checker = DidYouMean::SpellChecker.new(dictionary: all_candidates)
+ DidYouMean.formatter.message_for(all_candidates & checker.correct(opt))
+ end
+
+ #
+ # Return candidates for +word+.
+ #
+ def candidate(word)
+ list = []
+ case word
+ when '-'
+ long = short = true
+ when /\A--/
+ word, arg = word.split(/=/, 2)
+ argpat = Completion.regexp(arg, false) if arg and !arg.empty?
+ long = true
+ when /\A-/
+ short = true
+ end
+ pat = Completion.regexp(word, long)
+ visit(:each_option) do |opt|
+ next unless Switch === opt
+ opts = (long ? opt.long : []) + (short ? opt.short : [])
+ opts = Completion.candidate(word, true, pat, &opts.method(:each)).map(&:first) if pat
+ if /\A=/ =~ opt.arg
+ opts.map! {|sw| sw + "="}
+ if arg and CompletingHash === opt.pattern
+ if opts = opt.pattern.candidate(arg, false, argpat)
+ opts.map!(&:last)
+ end
+ end
+ end
+ list.concat(opts)
+ end
+ list
+ end
+
+ #
+ # Loads options from file names as +filename+. Does nothing when the file
+ # is not present. Returns whether successfully loaded.
+ #
+ # +filename+ defaults to basename of the program without suffix in a
+ # directory ~/.options, then the basename with '.options' suffix
+ # under XDG and Haiku standard places.
+ #
+ # The optional +into+ keyword argument works exactly like that accepted in
+ # method #parse.
+ #
+ def load(filename = nil, **keywords)
+ unless filename
+ basename = File.basename($0, '.*')
+ return true if load(File.expand_path("~/.options/#{basename}"), **keywords) rescue nil
+ basename << ".options"
+ if !(xdg = ENV['XDG_CONFIG_HOME']) or xdg.empty?
+ # https://specifications.freedesktop.org/basedir-spec/latest/#variables
+ #
+ # If $XDG_CONFIG_HOME is either not set or empty, a default
+ # equal to $HOME/.config should be used.
+ xdg = ['~/.config', true]
+ end
+ return [
+ xdg,
+
+ *ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
+
+ # Haiku
+ ['~/config/settings', true],
+ ].any? {|dir, expand|
+ next if !dir or dir.empty?
+ filename = File.join(dir, basename)
+ filename = File.expand_path(filename) if expand
+ load(filename, **keywords) rescue nil
+ }
end
begin
- parse(*IO.readlines(filename).each {|s| s.chomp!})
+ parse(*File.readlines(filename, chomp: true), **keywords)
true
rescue Errno::ENOENT, Errno::ENOTDIR
false
end
end
-=begin undocumented
---- OptionParser#environment([env])
- Parses environment variable ((|env|)) or its uppercase with spliting
- like as shell.
- :Parameters:
- : ((|env|))
- defaulted to basename of the program.
-=end #'#"#`#
- def environment(env = File.basename($0, '.*'))
+ #
+ # Parses environment variable +env+ or its uppercase with splitting like a
+ # shell.
+ #
+ # +env+ defaults to the basename of the program.
+ #
+ def environment(env = File.basename($0, '.*'), **keywords)
env = ENV[env] || ENV[env.upcase] or return
- parse(*Shellwords.shellwords(env))
+ require 'shellwords'
+ parse(*Shellwords.shellwords(env), **keywords)
end
-
-=begin
-= Acceptable argument classes
-=end #'#"#`#
+ #
+ # Acceptable argument classes
+ #
-=begin
-: Object
- any string, and no conversion. this is fall-back.
-=end #'#"#`#
+ #
+ # Any string and no conversion. This is fall-back.
+ #
accept(Object) {|s,|s or s.nil?}
accept(NilClass) {|s,|s}
-=begin
-: String
- any none-empty string, and no conversion.
-=end #'#"#`#
- accept(String, /.+/) {|s,*|s}
-
-=begin
-: Integer
- Ruby/C-like integer, octal for (({0-7})) sequence, binary for
- (({0b})), hexadecimal for (({0x})), and decimal for others; with
- optional sign prefix. Converts to (({Integer})).
-=end #'#"#`#
+ #
+ # Any non-empty string, and no conversion.
+ #
+ accept(String, /.+/m) {|s,*|s}
+
+ #
+ # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
+ # for 0x, and decimal for others; with optional sign prefix. Converts to
+ # Integer.
+ #
decimal = '\d+(?:_\d+)*'
binary = 'b[01]+(?:_[01]+)*'
hex = 'x[\da-f]+(?:_[\da-f]+)*'
- octal = "0(?:[0-7]*(?:_[0-7]+)*|#{binary}|#{hex})"
+ octal = "0(?:[0-7]+(?:_[0-7]+)*|#{binary}|#{hex})?"
integer = "#{octal}|#{decimal}"
- accept(Integer, %r"\A[-+]?(?:#{integer})"io) {|s,| Integer(s) if s}
-
-=begin
-: Float
- Float number format, and converts to (({Float})).
-=end #'#"#`#
- float = "(?:#{decimal}(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
- floatpat = %r"\A[-+]?#{float}"io
+
+ accept(Integer, %r"\A[-+]?(?:#{integer})\z"io) {|s,|
+ begin
+ Integer(s)
+ rescue ArgumentError
+ raise OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Float number format, and converts to Float.
+ #
+ float = "(?:#{decimal}(?=(.)?)(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
+ floatpat = %r"\A[-+]?#{float}\z"io
accept(Float, floatpat) {|s,| s.to_f if s}
-=begin
-: Numeric
- Generic numeric format, and converts to (({Integer})) for integer
- format, (({Float})) for float format.
-=end #'#"#`#
- accept(Numeric, %r"\A[-+]?(?:#{octal}|#{float})"io) {|s,| eval(s) if s}
-
-=begin
-: OptionParser::DecimalInteger
- Decimal integer format, to be converted to (({Integer})).
-=end #'#"#`#
- DecimalInteger = /\A[-+]?#{decimal}/io
- accept(DecimalInteger) {|s,| s.to_i if s}
-
-=begin
-: OptionParser::OctalInteger
- Ruby/C like octal/hexadecimal/binary integer format, to be converted
- to (({Integer})).
-=end #'#"#`#
- OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))/io
- accept(OctalInteger) {|s,| s.oct if s}
-
-=begin
-: OptionParser::DecimalNumeric
- Decimal integer/float number format, to be converted to
- (({Integer})) for integer format, (({Float})) for float format.
-=end #'#"#`#
+ #
+ # Generic numeric format, converts to Integer for integer format, Float
+ # for float format, and Rational for rational format.
+ #
+ real = "[-+]?(?:#{octal}|#{float})"
+ accept(Numeric, /\A(#{real})(?:\/(#{real}))?\z/io) {|s, d, f, n,|
+ if n
+ Rational(d, n)
+ elsif f
+ Float(s)
+ else
+ Integer(s)
+ end
+ }
+
+ #
+ # Decimal integer format, to be converted to Integer.
+ #
+ DecimalInteger = /\A[-+]?#{decimal}\z/io
+ accept(DecimalInteger, DecimalInteger) {|s,|
+ begin
+ Integer(s, 10)
+ rescue ArgumentError
+ raise OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
+ # Integer.
+ #
+ OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))\z/io
+ accept(OctalInteger, OctalInteger) {|s,|
+ begin
+ Integer(s, 8)
+ rescue ArgumentError
+ raise OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Decimal integer/float number format, to be converted to Integer for
+ # integer format, Float for float format.
+ #
DecimalNumeric = floatpat # decimal integer is allowed as float also.
- accept(DecimalNumeric) {|s,| eval(s) if s}
-
-=begin
-: TrueClass
- Boolean switch, which means whether it is present or not, whether it
- is absent or not with prefix (({no-})), or it takes an argument
- (({yes/no/true/false/+/-})).
-: FalseClass
- Similar to ((<TrueClass>)), but defaulted to (({false})).
-=end #'#"#`#
+ accept(DecimalNumeric, floatpat) {|s, f|
+ begin
+ if f
+ Float(s)
+ else
+ Integer(s)
+ end
+ rescue ArgumentError
+ raise OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Boolean switch, which means whether it is present or not, whether it is
+ # absent or not with prefix no-, or it takes an argument
+ # yes/no/true/false/+/-.
+ #
yesno = CompletingHash.new
%w[- no false].each {|el| yesno[el] = false}
%w[+ yes true].each {|el| yesno[el] = true}
- yesno['nil'] = false # shoud be nil?
+ yesno['nil'] = false # should be nil?
accept(TrueClass, yesno) {|arg, val| val == nil or val}
+ #
+ # Similar to TrueClass, but defaults to false.
+ #
accept(FalseClass, yesno) {|arg, val| val != nil and val}
-=begin
-: Array
- List of strings separated by ","
-=end #'#"#`#
- accept(Array) do |s,|
+ #
+ # List of strings separated by ",".
+ #
+ accept(Array) do |s, |
if s
- s = s.split(',').collect {|s| s unless s.empty?}
+ s = s.split(',').collect {|ss| ss unless ss.empty?}
end
s
end
-
-=begin
-= Exceptions
-=end #'#"#`#
-
-=begin
-== ((:OptionParser::ParseError:))
-Base class of exceptions from ((<OptionParser>))
-=== Superclass
-(({RuntimeError}))
-=== Constants
-: OptionParser::ParseError::Reason
- Reason caused error.
-=== Instance methods
---- OptionParser::ParseError#recover(argv)
- Push backs erred argument(s) to ((|argv|)).
---- OptionParser::ParseError#reason
- Returns error reason. Override this to I18N.
---- OptionParser::ParseError#inspect
- Returns inspection string.
---- OptionParser::ParseError#message
---- OptionParser::ParseError#to_s
---- OptionParser::ParseError#to_str
- Default stringizing method to emit standard error message.
-=end #'#"#`#
+ #
+ # Regular expression with options.
+ #
+ accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
+ f = 0
+ if o
+ f |= Regexp::IGNORECASE if /i/ =~ o
+ f |= Regexp::MULTILINE if /m/ =~ o
+ f |= Regexp::EXTENDED if /x/ =~ o
+ case o = o.delete("imx")
+ when ""
+ when "u"
+ s = s.encode(Encoding::UTF_8)
+ when "e"
+ s = s.encode(Encoding::EUC_JP)
+ when "s"
+ s = s.encode(Encoding::SJIS)
+ when "n"
+ f |= Regexp::NOENCODING
+ else
+ raise OptionParser::InvalidArgument, "unknown regexp option - #{o}"
+ end
+ else
+ s ||= all
+ end
+ Regexp.new(s, f)
+ end
+
+ #
+ # Exceptions
+ #
+
+ #
+ # Base class of exceptions from OptionParser.
+ #
class ParseError < RuntimeError
- Reason = 'parse error'.freeze
+ # Reason which caused the error.
+ Reason = 'parse error'
- def initialize(*args)
+ # :nodoc:
+ def initialize(*args, additional: nil)
+ @additional = additional
+ @arg0, = args
@args = args
@reason = nil
end
attr_reader :args
attr_writer :reason
+ attr_accessor :additional
+ #
+ # Pushes back erred argument(s) to +argv+.
+ #
def recover(argv)
argv[0, 0] = @args
argv
end
+ DIR = File.join(__dir__, '')
+ def self.filter_backtrace(array)
+ unless $DEBUG
+ array.delete_if {|bt| bt.start_with?(DIR)}
+ end
+ array
+ end
+
+ def set_backtrace(array)
+ super(self.class.filter_backtrace(array))
+ end
+
def set_option(opt, eq)
if eq
@args[0] = opt
@@ -1612,101 +2289,84 @@ Base class of exceptions from ((<OptionParser>))
self
end
+ #
+ # Returns error reason. Override this for I18N.
+ #
def reason
@reason || self.class::Reason
end
def inspect
- "#<#{self.class.to_s}: #{args.join(' ')}>"
+ "#<#{self.class}: #{args.join(' ')}>"
end
+ #
+ # Default stringizing method to emit standard error message.
+ #
def message
- reason + ': ' + args.join(' ')
+ "#{reason}: #{args.join(' ')}#{additional[@arg0] if additional}"
end
alias to_s message
- alias to_str message
end
-=begin
-== ((:OptionParser::AmbiguousOption:))
-Raises when encountered ambiguously completable string.
-=== Superclass
-((<OptionParser::ParseError>))
-=end #'#"#`#
+ #
+ # Raises when ambiguously completable string is encountered.
+ #
class AmbiguousOption < ParseError
- const_set(:Reason, 'ambiguous option'.freeze)
+ Reason = 'ambiguous option' # :nodoc:
end
-=begin
-== ((:OptionParser::NeedlessArgument:))
-Raises when encountered argument for switch defined as which takes no
-argument.
-=== Superclass
-((<OptionParser::ParseError>))
-=end #'#"#`#
+ #
+ # Raises when there is an argument for a switch which takes no argument.
+ #
class NeedlessArgument < ParseError
- const_set(:Reason, 'needles argument'.freeze)
+ Reason = 'needless argument' # :nodoc:
end
-=begin
-== ((:OptionParser::MissingArgument:))
-Raises when no argument found for switch defined as which needs
-argument.
-=== Superclass
-((<OptionParser::ParseError>))
-=end #'#"#`#
+ #
+ # Raises when a switch with mandatory argument has no argument.
+ #
class MissingArgument < ParseError
- const_set(:Reason, 'missing argument'.freeze)
+ Reason = 'missing argument' # :nodoc:
end
-=begin
-== ((:OptionParser::InvalidOption:))
-Raises when undefined switch.
-=== Superclass
-((<OptionParser::ParseError>))
-=end #'#"#`#
+ #
+ # Raises when switch is undefined.
+ #
class InvalidOption < ParseError
- const_set(:Reason, 'invalid option'.freeze)
+ Reason = 'invalid option' # :nodoc:
end
-=begin
-== ((:OptionParser::InvalidArgument:))
-Raises when the given argument does not match required format.
-=== Superclass
-((<OptionParser::ParseError>))
-=end #'#"#`#
+ #
+ # Raises when the given argument does not match required format.
+ #
class InvalidArgument < ParseError
- const_set(:Reason, 'invalid argument'.freeze)
+ Reason = 'invalid argument' # :nodoc:
end
-=begin
-== ((:OptionParser::AmbiguousArgument:))
-Raises when the given argument word can't completed uniquely.
-=== Superclass
-((<OptionParser::InvalidArgument>))
-=end #'#"#`#
+ #
+ # Raises when the given argument word can't be completed uniquely.
+ #
class AmbiguousArgument < InvalidArgument
- const_set(:Reason, 'ambiguous argument'.freeze)
+ Reason = 'ambiguous argument' # :nodoc:
end
-
-=begin
-= Miscellaneous
-=end #'#"#`#
-=begin
-== ((:OptionParser::Arguable:))
-Extends command line arguments array to parse itself.
-=end #'#"#`#
+ #
+ # Miscellaneous
+ #
+
+ #
+ # Extends command line arguments array (ARGV) to parse itself.
+ #
module Arguable
-=begin
---- OptionParser::Arguable#options=(opt)
- Sets ((<OptionParser>)) object, when ((|opt|)) is (({false})) or
- (({nil})), methods ((<OptionParser::Arguable#options>)) and
- ((<OptionParser::Arguable#options=>)) are undefined. Thus, there
- is no ways to access the ((<OptionParser>)) object via the
- receiver object.
-=end #'#"#`#
+
+ #
+ # Sets OptionParser object, when +opt+ is +false+ or +nil+, methods
+ # OptionParser::Arguable#options and OptionParser::Arguable#options= are
+ # undefined. Thus, there is no ways to access the OptionParser object
+ # via the receiver object.
+ #
def options=(opt)
unless @optparse = opt
class << self
@@ -1716,23 +2376,17 @@ Extends command line arguments array to parse itself.
end
end
-=begin
---- OptionParser::Arguable#options
- Actual ((<OptionParser>)) object, automatically created if not
- yet.
-
- If called as iterator, yields with the ((<OptionParser>)) object
- and returns the result of the block. In this case, rescues any
- ((<OptionParser::ParseError>)) exceptions in the block, just emits
- error message to ((<STDERR>)) and returns (({nil})).
-
- :Parameters:
- : (({block}))
- Yielded with the ((<OptionParser>)) instance.
-
-=end #'#"#`#
+ #
+ # Actual OptionParser object, automatically created if nonexistent.
+ #
+ # If called with a block, yields the OptionParser object and returns the
+ # result of the block. If an OptionParser::ParseError exception occurs
+ # in the block, it is rescued, a error message printed to STDERR and
+ # +nil+ returned.
+ #
def options
@optparse ||= OptionParser.new
+ @optparse.default_argv = self
block_given? or return @optparse
begin
yield @optparse
@@ -1742,55 +2396,68 @@ Extends command line arguments array to parse itself.
end
end
-=begin
---- OptionParser::Arguable#order!
---- OptionParser::Arguable#permute!
---- OptionParser::Arguable#parse!
- Parses ((|self|)) destructively, and returns ((|self|)) just contains
- rest arguments left without parsed.
-=end #'#"#`#
- def order!(&blk) options.order!(self, &blk) end
- def permute!() options.permute!(self) end
- def parse!() options.parse!(self) end
-
-=begin private
-Initializes instance variable.
-=end #'#"#`#
+ #
+ # Parses +self+ destructively in order and returns +self+ containing the
+ # rest arguments left unparsed.
+ #
+ def order!(**keywords, &blk) options.order!(self, **keywords, &blk) end
+
+ #
+ # Parses +self+ destructively in permutation mode and returns +self+
+ # containing the rest arguments left unparsed.
+ #
+ def permute!(**keywords) options.permute!(self, **keywords) end
+
+ #
+ # Parses +self+ destructively and returns +self+ containing the
+ # rest arguments left unparsed.
+ #
+ def parse!(**keywords) options.parse!(self, **keywords) end
+
+ #
+ # Substitution of getopts is possible as follows. Also see
+ # OptionParser#getopts.
+ #
+ # def getopts(*args)
+ # ($OPT = ARGV.getopts(*args)).each do |opt, val|
+ # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
+ # end
+ # rescue OptionParser::ParseError
+ # end
+ #
+ def getopts(*args, symbolize_names: false, **keywords)
+ options.getopts(self, *args, symbolize_names: symbolize_names, **keywords)
+ end
+
+ #
+ # Initializes instance variable.
+ #
def self.extend_object(obj)
super
obj.instance_eval {@optparse = nil}
end
- def initialize(*args)
+
+ def initialize(*args) # :nodoc:
super
@optparse = nil
end
end
-=begin
-== OptionParser::Acceptables
-Acceptable argument classes. Now contains (({DecimalInteger})),
-(({OctalInteger})) and (({DecimalNumeric})).
-see ((<Acceptable argument classes>)).
-=end #'#"#`#
+ #
+ # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
+ # and DecimalNumeric. See Acceptable argument classes (in source code).
+ #
module Acceptables
- const_set(:DecimalInteger, OptionParser::DecimalInteger)
- const_set(:OctalInteger, OptionParser::OctalInteger)
- const_set(:DecimalNumeric, OptionParser::DecimalNumeric)
+ # :stopdoc:
+ DecimalInteger = OptionParser::DecimalInteger
+ OctalInteger = OptionParser::OctalInteger
+ DecimalNumeric = OptionParser::DecimalNumeric
+ # :startdoc:
end
end
# ARGV is arguable by OptionParser
ARGV.extend(OptionParser::Arguable)
-
-if $0 == __FILE__
- Version = OptionParser::Version
- ARGV.options {|q|
- q.parse!.empty? or puts "what's #{ARGV.join(' ')}?"
- } or exit 1
-end
-__END__
-=begin example
-= Example
-<<< opttest.rb
-=end #'#"#`#
+# An alias for OptionParser.
+OptParse = OptionParser # :nodoc: