1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* lib/optparse.rb: incomplete RDoc documentation added in place of

existing RD comments.  Tabs converted to spaces.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5264 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
gsinclair 2003-12-23 13:27:42 +00:00
parent 818ecd7d0b
commit fd4a3ee4ac
2 changed files with 406 additions and 302 deletions

View file

@ -1,3 +1,8 @@
Tue Dec 23 22:25:00 2003 Gavin Sinclair <gsinclair@soyabean.com.au>
* lib/optparse.rb: incomplete RDoc documentation added in place of
existing RD comments. Tabs converted to spaces.
Tue Dec 23 19:44:47 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org> Tue Dec 23 19:44:47 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
* test/soap/test_streamhandler.rb (test_basic_auth): removed. * test/soap/test_streamhandler.rb (test_basic_auth): removed.

View file

@ -1,61 +1,184 @@
# optparse library, not octopus. #
# optparse.rb - command-line option analysis with the OptionParser class.
#
# Author:: Nobu Nakada
# Documentation:: Nobu Nakada and Gavin Sinclair.
#
=begin
= Summary
Library for command line option analysis.
features:
(1) It is possible <option switch of a short form and a long form> to
exist together. It is also possible in one to bring the switch of
a short form together.
(2) It is possible to write bringing specification and the handler of
the switch together respectively in one place.
(3) The argument of the switch is converted into the class which
automatically specifies it.
(4) The option summary can be made.
(5) The option can be added on the way later.
=end #'#"#`#
# Not yet (;_;)
=begin
== Class tree
* ((<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 relations
+--------------+
| OptionParser |<>-----+
+--------------+ | +--------+
| ,-| Switch |
on_head -------->+---------------+ / +--------+
accept/reject -->| List |<|>-
| |<|>- +----------+
on ------------->+---------------+ `-| argument |
: : | class |
+---------------+ |==========|
on_tail -------->| | |pattern |
+---------------+ |----------|
OptionParser.accept ->| DefaultList | |converter |
reject |(shared between| +----------+
| all instances)|
+---------------+
=end #'#"#`#
=begin
= Classes & Modules
=end #'#"#`#
#
# == OptionParser
#
# === Introduction
#
# OptionParser (in optparse.rb) is a library for command-line option analysis.
# It is much more advanced, yet also easier to use, than GetoptLong, and is a
# more Ruby-oriented solution.
#
# === Features
#
# 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.
#
# === Class tree
#
# - 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 |<>-----+
# +--------------+ | +--------+
# | ,-| Switch |
# on_head -------->+---------------+ / +--------+
# accept/reject -->| List |<|>-
# | |<|>- +----------+
# on ------------->+---------------+ `-| argument |
# : : | class |
# +---------------+ |==========|
# on_tail -------->| | |pattern |
# +---------------+ |----------|
# OptionParser.accept ->| DefaultList | |converter |
# reject |(shared between| +----------+
# | all instances)|
# +---------------+
# === Example
#
# The following example is a complete Ruby program. You can run it and see the
# effect of specifying various options.
#
# require 'optparse'
# require 'optparse/time'
# require 'ostruct'
# require 'pp'
#
# class OptparseExample
#
# 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
# 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.
# end
#
# # Cast 'delay' argument to a Float.
# opts.on("--delay N", Float, "Delay N seconds before executing") do |n|
# options.delay = n
# end
#
# # Cast 'time' argument to a Time object.
# opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
# options.time = time
# end
#
# # Cast to octal integer.
# opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
# "Specify record separator (default \\0)") do |rs|
# options.record_separator = rs
# end
#
# # List of arguments.
# opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
# options.list = list
# end
#
# # 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
# 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
#
# # 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
# end
# end
#
# opts.parse!(args)
# options
# end # parse()
#
# end # class OptparseExample
#
# options = OptparseExample.parse(ARGV)
# pp options
#
# Note: if you get errors or strange results from any of the above code, make
# sure you have the latest version installed. Some changes have been made since
# Ruby 1.8.0 was released.
#
class OptionParser class OptionParser
# :stopdoc:
RCSID = %w$Id$[1..-1].each {|s| s.freeze}.freeze 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]) 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]) LastModified = (Time.gm(*RCSID[2, 2].join('-').scan(/\d+/).collect {|s| s.to_i}) if RCSID[2])
@ -64,35 +187,28 @@ class OptionParser
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
# :startdoc:
=begin private #
== ((:OptionParser::Completion:)) # Keyword completion module. This allows partial arguments to be specified
Keyword completion module. # and resolved against a list of acceptable values. The average user does not
=end #'#"#`# # need to comprehend this.
module Completion #
=begin private module Completion # :nodoc:
--- OptionParser::Completion#complete(key[, pat])
Searches ((|key|)), or ((|pat|)) with completion if not found.
:Parameters:
: ((|key|))
keyword to search.
: ((|pat|))
completion pattern.
=end #'#"#`#
def complete(key, pat = nil) def complete(key, pat = nil)
pat ||= Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), pat ||= Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'),
ignore_case?) ignore_case?)
canon, sw, k, v, cn = nil canon, sw, k, v, cn = nil
candidates = [] candidates = []
each do |k, *v| each do |k, *v|
(if Regexp === k (if Regexp === k
kn = nil kn = nil
k === key k === key
else else
kn = defined?(k.id2name) ? k.id2name : k kn = defined?(k.id2name) ? k.id2name : k
pat === kn pat === kn
end) or next end) or next
v << k if v.empty? v << k if v.empty?
candidates << [k, v, kn] candidates << [k, v, kn]
end end
candidates = candidates.sort_by {|k, v, kn| kn.size} candidates = candidates.sort_by {|k, v, kn| kn.size}
@ -102,28 +218,23 @@ Keyword completion module.
canon, sw, cn = candidates.shift canon, sw, cn = candidates.shift
candidates.each do |k, v, kn| candidates.each do |k, v, kn|
next if sw == v next if sw == v
if String === cn and String === kn if String === cn and String === kn
if cn.rindex(kn, 0) if cn.rindex(kn, 0)
canon, sw, cn = k, v, kn canon, sw, cn = k, v, kn
next next
elsif kn.rindex(cn, 0) elsif kn.rindex(cn, 0)
next next
end end
end end
throw :ambiguous, key throw :ambiguous, key
end end
end end
if canon if canon
block_given? or return key, *sw block_given? or return key, *sw
yield(key, *sw) yield(key, *sw)
end end
end end
=begin private
--- OptionParser::Completion#convert(opt, *val)
Extracts the first element from result of
((<OptionParser::Completion#complete>)).
=end #'#"#`#
def convert(opt = nil, val = nil, *) def convert(opt = nil, val = nil, *)
val val
end end
@ -133,14 +244,10 @@ Keyword completion module.
end end
end end
=begin private
== ((:OptionParser::OptionMap:)) #
Map from option/keyword string to object with completion. # Map from option/keyword string to object with completion.
=== Superclass #
(({Hash}))
=== Including modules
((<OptionParser::Completion>))
=end #'#"#`#
class OptionMap < Hash class OptionMap < Hash
include Completion include Completion
end end
@ -150,22 +257,17 @@ Map from option/keyword string to object with completion.
end end
end end
=begin #
== ((:OptionParser::Switch:)) # Individual switch class.
Individual switch class. #
=end #'#"#`#
class Switch class Switch
attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
=begin private #
=== Class methods # Guesses argument style from +arg+. Returns corresponding
=end # OptionParser::Switch class (OptionalArgument, etc.).
=begin private #
--- OptionParser::Switch.guess(arg)
Guesses argument style from ((|arg|)).
Returns corresponding ((<OptionParser::Switch>)) subclass.
=end #'#"#`#
def self.guess(arg) def self.guess(arg)
case arg case arg
when "" when ""
@ -189,15 +291,12 @@ Individual switch class.
NilClass NilClass
end end
=begin private
--- OptionParser::Switch.new
=end #'#"#`#
def initialize(pattern = nil, conv = nil, def initialize(pattern = nil, conv = nil,
short = nil, long = nil, arg = nil, short = nil, long = nil, arg = nil,
desc = ([] if short or long), block = Proc.new) desc = ([] if short or long), block = Proc.new)
raise if Array === pattern raise if Array === pattern
@pattern, @conv, @short, @long, @arg, @desc, @block = @pattern, @conv, @short, @long, @arg, @desc, @block =
pattern, conv, short, long, arg, desc, block pattern, conv, short, long, arg, desc, block
end end
=begin =begin
@ -216,15 +315,15 @@ Individual switch class.
def parse_arg(arg) def parse_arg(arg)
pattern or return nil, arg pattern or return nil, arg
unless m = pattern.match(arg) unless m = pattern.match(arg)
yield(InvalidArgument, arg) yield(InvalidArgument, arg)
return arg, nil return arg, nil
end end
if String === m if String === m
m = [s = m] m = [s = m]
else else
m = m.to_a m = m.to_a
s = m[0] s = m[0]
return nil, m unless String === s return nil, m unless String === s
end end
raise InvalidArgument, arg unless arg.rindex(s, 0) raise InvalidArgument, arg unless arg.rindex(s, 0)
return nil, m if s.length == arg.length return nil, m if s.length == arg.length
@ -255,9 +354,9 @@ Individual switch class.
else else
val = *val val = *val
end end
return arg, block, val return arg, block, val
else else
return arg, nil return arg, nil
end end
end end
private :conv_arg private :conv_arg
@ -290,22 +389,22 @@ Individual switch class.
right = desc.dup right = desc.dup
while s = lopts.shift while s = lopts.shift
l = left[-1].length + s.length l = left[-1].length + s.length
l += arg.length if left.size == 1 && arg l += arg.length if left.size == 1 && arg
l < max or left << '' l < max or left << ''
left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s
end end
left[0] << arg if arg left[0] << arg if arg
mlen = left.collect {|s| s.length}.max.to_i mlen = left.collect {|s| s.length}.max.to_i
while mlen > width and l = left.shift while mlen > width and l = left.shift
mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen
yield(indent + l) yield(indent + l)
end end
while (l = left.shift; r = right.shift; l or r) while (l = left.shift; r = right.shift; l or r)
l = l.to_s.ljust(width) + ' ' + r if r and !r.empty? l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
yield(indent + l) yield(indent + l)
end end
self self
@ -326,13 +425,13 @@ Switch that takes no arguments.
=end #'#"#`# =end #'#"#`#
class NoArgument < self class NoArgument < self
def parse(arg, argv, &error) def parse(arg, argv, &error)
yield(NeedlessArgument, arg) if arg yield(NeedlessArgument, arg) if arg
conv_arg(arg) conv_arg(arg)
end end
def self.incompatible_argument_styles(*) def self.incompatible_argument_styles(*)
end end
def self.pattern def self.pattern
Object Object
end end
end end
@ -347,11 +446,11 @@ Switch that takes an argument.
=end #'#"#`# =end #'#"#`#
class RequiredArgument < self class RequiredArgument < self
def parse(arg, argv, &error) def parse(arg, argv, &error)
unless arg unless arg
raise MissingArgument if argv.empty? raise MissingArgument if argv.empty?
arg = argv.shift arg = argv.shift
end end
conv_arg(*parse_arg(arg, &error)) conv_arg(*parse_arg(arg, &error))
end end
end end
@ -366,19 +465,19 @@ Switch that can omit argument.
=end #'#"#`# =end #'#"#`#
class OptionalArgument < self class OptionalArgument < self
def parse(arg, argv, &error) def parse(arg, argv, &error)
if arg if arg
conv_arg(*parse_arg(arg, &error)) conv_arg(*parse_arg(arg, &error))
else else
conv_arg(arg) conv_arg(arg)
end end
end end
end end
class PlacedArgument < self class PlacedArgument < self
def parse(arg, argv, &error) def parse(arg, argv, &error)
if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0])) if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
return nil, block, nil return nil, block, nil
end end
opt = (val = parse_arg(val, &error))[1] opt = (val = parse_arg(val, &error))[1]
val = conv_arg(*val) val = conv_arg(*val)
if opt and !arg if opt and !arg
@ -437,12 +536,12 @@ summary feature.
=end #'#"#`# =end #'#"#`#
def accept(t, pat = /.*/, &block) def accept(t, pat = /.*/, &block)
if pat if pat
pat.respond_to?(:match) or raise TypeError, "has no `match'" pat.respond_to?(:match) or raise TypeError, "has no `match'"
else else
pat = t if t.respond_to?(:match) pat = t if t.respond_to?(:match)
end end
unless block unless block
block = pat.method(:convert).to_proc if pat.respond_to?(:convert) block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
end end
@atype[t] = [pat, block] @atype[t] = [pat, block]
end end
@ -515,9 +614,9 @@ summary feature.
=end #'#"#`# =end #'#"#`#
def search(id, key) def search(id, key)
if list = __send__(id) if list = __send__(id)
val = list.fetch(key) {return nil} val = list.fetch(key) {return nil}
return val unless block_given? return val unless block_given?
yield(val) yield(val)
end end
end end
@ -550,13 +649,13 @@ summary feature.
=end #'#"#`# =end #'#"#`#
def summarize(*args, &block) def summarize(*args, &block)
list.each do |opt| list.each do |opt|
if opt.respond_to?(:summarize) # perhaps OptionParser::Switch if opt.respond_to?(:summarize) # perhaps OptionParser::Switch
opt.summarize(*args, &block) opt.summarize(*args, &block)
elsif opt.empty? elsif opt.empty?
yield("") yield("")
else else
opt.each(&block) opt.each(&block)
end end
end end
end end
end end
@ -580,7 +679,7 @@ summary feature.
=end #'#"#`# =end #'#"#`#
def match(key) def match(key)
return key, *fetch(key) { return key, *fetch(key) {
raise AmbiguousArgument, catch(:ambiguous) {return complete(key)} raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
} }
end end
end end
@ -962,10 +1061,10 @@ Default options, which never appear in option summary.
def notwice(obj, prv, msg) def notwice(obj, prv, msg)
unless !prv or prv == obj unless !prv or prv == obj
begin begin
raise ArgumentError, "argument #{msg} given twice: #{obj}" raise ArgumentError, "argument #{msg} given twice: #{obj}"
rescue rescue
$@[0, 2] = nil $@[0, 2] = nil
raise raise
end end
end end
obj obj
@ -984,104 +1083,104 @@ Default options, which never appear in option summary.
opts.each do |o| opts.each do |o|
# argument class # argument class
next if search(:atype, o) do |pat, c| next if search(:atype, o) do |pat, c|
klass = notwice(o, klass, 'type') klass = notwice(o, klass, 'type')
if not_style and not_style != Switch::NoArgument if not_style and not_style != Switch::NoArgument
not_pattern, not_conv = pat, c not_pattern, not_conv = pat, c
else else
default_pattern, conv = pat, c default_pattern, conv = pat, c
end end
end end
# directly specified pattern(any object possible to match) # directly specified pattern(any object possible to match)
if !(String === o) and o.respond_to?(:match) if !(String === o) and o.respond_to?(:match)
pattern = notwice(o, pattern, 'pattern') pattern = notwice(o, pattern, 'pattern')
conv = (pattern.method(:convert).to_proc if pattern.respond_to?(:convert)) conv = (pattern.method(:convert).to_proc if pattern.respond_to?(:convert))
next next
end end
# anything others # anything others
case o case o
when Proc, Method when Proc, Method
block = notwice(o, block, 'block') block = notwice(o, block, 'block')
when Array, Hash when Array, Hash
case pattern case pattern
when CompletingHash when CompletingHash
when nil when nil
pattern = CompletingHash.new 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 else
raise ArgumentError, "argument pattern given twice" raise ArgumentError, "argument pattern given twice"
end end
o.each {|(o, *v)| pattern[o] = v.fetch(0) {o}} o.each {|(o, *v)| pattern[o] = v.fetch(0) {o}}
when Module when Module
raise ArgumentError, "unsupported argument type: #{o}" raise ArgumentError, "unsupported argument type: #{o}"
when *ArgumentStyle.keys when *ArgumentStyle.keys
style = notwice(ArgumentStyle[o], style, 'style') style = notwice(ArgumentStyle[o], style, 'style')
when /^--no-([^\[\]=\s]*)(.+)?/ when /^--no-([^\[\]=\s]*)(.+)?/
q, a = $1, $2 q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type') o = notwice(a ? Object : TrueClass, klass, 'type')
not_pattern, not_conv = search(:atype, o) unless not_style not_pattern, not_conv = search(:atype, o) unless not_style
not_style = (not_style || default_style).guess(arg = a) if a not_style = (not_style || default_style).guess(arg = a) if a
default_style = Switch::NoArgument default_style = Switch::NoArgument
default_pattern, conv = search(:atype, FalseClass) unless default_pattern default_pattern, conv = search(:atype, FalseClass) unless default_pattern
ldesc << "--no-#{q}" ldesc << "--no-#{q}"
long << 'no-' + (q = q.downcase) long << 'no-' + (q = q.downcase)
nolong << q nolong << q
when /^--\[no-\]([^\[\]=\s]*)(.+)?/ when /^--\[no-\]([^\[\]=\s]*)(.+)?/
q, a = $1, $2 q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type') o = notwice(a ? Object : TrueClass, klass, 'type')
if a if a
default_style = default_style.guess(arg = a) default_style = default_style.guess(arg = a)
default_pattern, conv = search(:atype, o) unless default_pattern default_pattern, conv = search(:atype, o) unless default_pattern
end end
ldesc << "--[no-]#{q}" ldesc << "--[no-]#{q}"
long << (o = q.downcase) long << (o = q.downcase)
not_pattern, not_conv = search(:atype, FalseClass) unless not_style not_pattern, not_conv = search(:atype, FalseClass) unless not_style
not_style = Switch::NoArgument not_style = Switch::NoArgument
nolong << 'no-' + o nolong << 'no-' + o
when /^--([^\[\]=\s]*)(.+)?/ when /^--([^\[\]=\s]*)(.+)?/
q, a = $1, $2 q, a = $1, $2
if a if a
o = notwice(NilClass, klass, 'type') o = notwice(NilClass, klass, 'type')
default_style = default_style.guess(arg = a) default_style = default_style.guess(arg = a)
default_pattern, conv = search(:atype, o) unless default_pattern default_pattern, conv = search(:atype, o) unless default_pattern
end end
ldesc << "--#{q}" ldesc << "--#{q}"
long << (o = q.downcase) long << (o = q.downcase)
when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/ when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
q, a = $1, $2 q, a = $1, $2
o = notwice(Object, klass, 'type') o = notwice(Object, klass, 'type')
if a if a
default_style = default_style.guess(arg = a) default_style = default_style.guess(arg = a)
default_pattern, conv = search(:atype, o) unless default_pattern default_pattern, conv = search(:atype, o) unless default_pattern
end end
sdesc << "-#{q}" sdesc << "-#{q}"
short << Regexp.new(q) short << Regexp.new(q)
when /^-(.)(.+)?/ when /^-(.)(.+)?/
q, a = $1, $2 q, a = $1, $2
if a if a
o = notwice(NilClass, klass, 'type') o = notwice(NilClass, klass, 'type')
default_style = default_style.guess(arg = a) default_style = default_style.guess(arg = a)
default_pattern, conv = search(:atype, o) unless default_pattern default_pattern, conv = search(:atype, o) unless default_pattern
end end
sdesc << "-#{q}" sdesc << "-#{q}"
short << q short << q
when /^=/ when /^=/
style = notwice(default_style.guess(arg = o), style, 'style') style = notwice(default_style.guess(arg = o), style, 'style')
default_pattern, conv = search(:atype, Object) unless default_pattern default_pattern, conv = search(:atype, Object) unless default_pattern
else else
desc.push(o) desc.push(o)
end end
end end
default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
s = if short.empty? and long.empty? s = if short.empty? and long.empty?
raise ArgumentError, "no switch given" if style or pattern or block raise ArgumentError, "no switch given" if style or pattern or block
desc desc
else else
(style || default_style).new(pattern || default_pattern, (style || default_style).new(pattern || default_pattern,
conv, sdesc, ldesc, arg, desc, block) conv, sdesc, ldesc, arg, desc, block)
end end
return s, short, long, return s, short, long,
(not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style), (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
nolong nolong
@ -1162,55 +1261,55 @@ Default options, which never appear in option summary.
nonopt ||= proc {|arg| throw :terminate, arg} nonopt ||= proc {|arg| throw :terminate, arg}
argv.unshift(arg) if arg = catch(:terminate) { argv.unshift(arg) if arg = catch(:terminate) {
while arg = argv.shift while arg = argv.shift
case arg case arg
# long option # long option
when /\A--([^=]*)(?:=(.*))?/ when /\A--([^=]*)(?:=(.*))?/
opt, rest = $1, $2 opt, rest = $1, $2
begin begin
sw, = complete(:long, opt) sw, = complete(:long, opt)
rescue ParseError rescue ParseError
raise $!.set_option(arg, true) raise $!.set_option(arg, true)
end end
begin begin
opt, sw, val = sw.parse(rest, argv) {|*exc| raise(*exc)} opt, sw, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
sw.call(val) if sw sw.call(val) if sw
rescue ParseError rescue ParseError
raise $!.set_option(arg, rest) raise $!.set_option(arg, rest)
end end
# short option # short option
when /\A-(.)((=).*|.+)?/ when /\A-(.)((=).*|.+)?/
opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2 opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2
begin begin
unless sw = search(:short, opt) unless sw = search(:short, opt)
begin begin
sw, = complete(:short, opt) sw, = complete(:short, opt)
# short option matched. # short option matched.
val = arg.sub(/\A-/, '') val = arg.sub(/\A-/, '')
has_arg = true has_arg = true
rescue InvalidOption rescue InvalidOption
# if no short options match, try completion with long # if no short options match, try completion with long
# options. # options.
sw, = complete(:long, opt) sw, = complete(:long, opt)
eq ||= !rest eq ||= !rest
end end
end end
rescue ParseError rescue ParseError
raise $!.set_option(arg, true) raise $!.set_option(arg, true)
end end
begin begin
opt, sw, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq} opt, sw, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}" raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
argv.unshift(opt) if opt and (opt = opt.sub(/\A-*/, '-')) != '-' argv.unshift(opt) if opt and (opt = opt.sub(/\A-*/, '-')) != '-'
sw.call(val) if sw sw.call(val) if sw
rescue ParseError rescue ParseError
raise $!.set_option(arg, arg.length > 2) raise $!.set_option(arg, arg.length > 2)
end end
# non-option argument # non-option argument
else else
nonopt.call(arg) nonopt.call(arg)
end end
end end
nil nil
@ -1440,7 +1539,7 @@ Default options, which never appear in option summary.
Decimal integer/float number format, to be converted to Decimal integer/float number format, to be converted to
(({Integer})) for integer format, (({Float})) for float format. (({Integer})) for integer format, (({Float})) for float format.
=end #'#"#`# =end #'#"#`#
DecimalNumeric = floatpat # decimal integer is allowed as float also. DecimalNumeric = floatpat # decimal integer is allowed as float also.
accept(DecimalNumeric) {|s,| eval(s) if s} accept(DecimalNumeric) {|s,| eval(s) if s}
=begin =begin
@ -1454,7 +1553,7 @@ Default options, which never appear in option summary.
yesno = CompletingHash.new yesno = CompletingHash.new
%w[- no false].each {|el| yesno[el] = false} %w[- no false].each {|el| yesno[el] = false}
%w[+ yes true].each {|el| yesno[el] = true} %w[+ yes true].each {|el| yesno[el] = true}
yesno['nil'] = false # shoud be nil? yesno['nil'] = false # shoud be nil?
accept(TrueClass, yesno) {|arg, val| val == nil or val} accept(TrueClass, yesno) {|arg, val| val == nil or val}
accept(FalseClass, yesno) {|arg, val| val != nil and val} accept(FalseClass, yesno) {|arg, val| val != nil and val}
@ -1512,9 +1611,9 @@ Base class of exceptions from ((<OptionParser>))
def set_option(opt, eq) def set_option(opt, eq)
if eq if eq
@args[0] = opt @args[0] = opt
else else
@args.unshift(opt) @args.unshift(opt)
end end
self self
end end
@ -1616,10 +1715,10 @@ Extends command line arguments array to parse itself.
=end #'#"#`# =end #'#"#`#
def options=(opt) def options=(opt)
unless @optparse = opt unless @optparse = opt
class << self class << self
undef_method(:options) undef_method(:options)
undef_method(:options=) undef_method(:options=)
end end
end end
end end
@ -1642,10 +1741,10 @@ Extends command line arguments array to parse itself.
@optparse ||= OptionParser.new @optparse ||= OptionParser.new
block_given? or return @optparse block_given? or return @optparse
begin begin
yield @optparse yield @optparse
rescue ParseError rescue ParseError
@optparse.warn $! @optparse.warn $!
nil nil
end end
end end