зеркало из https://github.com/github/ruby.git
Extract getoptlong as bundled gems
This commit is contained in:
Родитель
c5d54e1db1
Коммит
b68dab2d0f
|
@ -22,3 +22,4 @@ typeprof 0.21.9 https://github.com/ruby/typeprof
|
|||
debug 1.9.1 https://github.com/ruby/debug
|
||||
racc 1.7.3 https://github.com/ruby/racc
|
||||
mutex_m 0.2.0 https://github.com/ruby/mutex_m
|
||||
getoptlong 0.2.1 https://github.com/ruby/getoptlong
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
name = File.basename(__FILE__, ".gemspec")
|
||||
version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
|
||||
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
|
||||
/^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
|
||||
end rescue nil
|
||||
end
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = name
|
||||
spec.version = version
|
||||
spec.authors = ["Yukihiro Matsumoto"]
|
||||
spec.email = ["matz@ruby-lang.org"]
|
||||
|
||||
spec.summary = %q{GetoptLong for Ruby}
|
||||
spec.description = spec.summary
|
||||
spec.homepage = "https://github.com/ruby/getoptlong"
|
||||
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
||||
|
||||
spec.metadata["homepage_uri"] = spec.homepage
|
||||
spec.metadata["source_code_uri"] = spec.homepage
|
||||
|
||||
# Specify which files should be added to the gem when it is released.
|
||||
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
||||
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
||||
`git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
||||
end
|
||||
spec.require_paths = ["lib"]
|
||||
end
|
|
@ -1,867 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
#
|
||||
# GetoptLong for Ruby
|
||||
#
|
||||
# Copyright (C) 1998, 1999, 2000 Motoyuki Kasahara.
|
||||
#
|
||||
# You may redistribute and/or modify this library under the same license
|
||||
# terms as Ruby.
|
||||
|
||||
# \Class \GetoptLong provides parsing both for options
|
||||
# and for regular arguments.
|
||||
#
|
||||
# Using \GetoptLong, you can define options for your program.
|
||||
# The program can then capture and respond to whatever options
|
||||
# are included in the command that executes the program.
|
||||
#
|
||||
# A simple example: file <tt>simple.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/simple.rb
|
||||
#
|
||||
# If you are somewhat familiar with options,
|
||||
# you may want to skip to this
|
||||
# {full example}[#class-GetoptLong-label-Full+Example].
|
||||
#
|
||||
# == Options
|
||||
#
|
||||
# A \GetoptLong option has:
|
||||
#
|
||||
# - A string <em>option name</em>.
|
||||
# - Zero or more string <em>aliases</em> for the name.
|
||||
# - An <em>option type</em>.
|
||||
#
|
||||
# Options may be defined by calling singleton method GetoptLong.new,
|
||||
# which returns a new \GetoptLong object.
|
||||
# Options may then be processed by calling other methods
|
||||
# such as GetoptLong#each.
|
||||
#
|
||||
# === Option Name and Aliases
|
||||
#
|
||||
# In the array that defines an option,
|
||||
# the first element is the string option name.
|
||||
# Often the name takes the 'long' form, beginning with two hyphens.
|
||||
#
|
||||
# The option name may have any number of aliases,
|
||||
# which are defined by additional string elements.
|
||||
#
|
||||
# The name and each alias must be of one of two forms:
|
||||
#
|
||||
# - Two hyphens, followed by one or more letters.
|
||||
# - One hyphen, followed by a single letter.
|
||||
#
|
||||
# File <tt>aliases.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/aliases.rb
|
||||
#
|
||||
# An option may be cited by its name,
|
||||
# or by any of its aliases;
|
||||
# the parsed option always reports the name, not an alias:
|
||||
#
|
||||
# $ ruby aliases.rb -a -p --xxx --aaa -x
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--xxx", ""]
|
||||
# ["--xxx", ""]
|
||||
# ["--xxx", ""]
|
||||
# ["--xxx", ""]
|
||||
# ["--xxx", ""]
|
||||
#
|
||||
#
|
||||
# An option may also be cited by an abbreviation of its name or any alias,
|
||||
# as long as that abbreviation is unique among the options.
|
||||
#
|
||||
# File <tt>abbrev.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/abbrev.rb
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby abbrev.rb --xxx --xx --xyz --xy
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--xxx", ""]
|
||||
# ["--xxx", ""]
|
||||
# ["--xyz", ""]
|
||||
# ["--xyz", ""]
|
||||
#
|
||||
# This command line raises GetoptLong::AmbiguousOption:
|
||||
#
|
||||
# $ ruby abbrev.rb --x
|
||||
#
|
||||
# === Repetition
|
||||
#
|
||||
# An option may be cited more than once:
|
||||
#
|
||||
# $ ruby abbrev.rb --xxx --xyz --xxx --xyz
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--xxx", ""]
|
||||
# ["--xyz", ""]
|
||||
# ["--xxx", ""]
|
||||
# ["--xyz", ""]
|
||||
#
|
||||
# === Treating Remaining Options as Arguments
|
||||
#
|
||||
# A option-like token that appears
|
||||
# anywhere after the token <tt>--</tt> is treated as an ordinary argument,
|
||||
# and is not processed as an option:
|
||||
#
|
||||
# $ ruby abbrev.rb --xxx --xyz -- --xxx --xyz
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--xxx", ""]
|
||||
# ["--xyz", ""]
|
||||
#
|
||||
# === Option Types
|
||||
#
|
||||
# Each option definition includes an option type,
|
||||
# which controls whether the option takes an argument.
|
||||
#
|
||||
# File <tt>types.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/types.rb
|
||||
#
|
||||
# Note that an option type has to do with the <em>option argument</em>
|
||||
# (whether it is required, optional, or forbidden),
|
||||
# not with whether the option itself is required.
|
||||
#
|
||||
# ==== Option with Required Argument
|
||||
#
|
||||
# An option of type <tt>GetoptLong::REQUIRED_ARGUMENT</tt>
|
||||
# must be followed by an argument, which is associated with that option:
|
||||
#
|
||||
# $ ruby types.rb --xxx foo
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--xxx", "foo"]
|
||||
#
|
||||
# If the option is not last, its argument is whatever follows it
|
||||
# (even if the argument looks like another option):
|
||||
#
|
||||
# $ ruby types.rb --xxx --yyy
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--xxx", "--yyy"]
|
||||
#
|
||||
# If the option is last, an exception is raised:
|
||||
#
|
||||
# $ ruby types.rb
|
||||
# # Raises GetoptLong::MissingArgument
|
||||
#
|
||||
# ==== Option with Optional Argument
|
||||
#
|
||||
# An option of type <tt>GetoptLong::OPTIONAL_ARGUMENT</tt>
|
||||
# may be followed by an argument, which if given is associated with that option.
|
||||
#
|
||||
# If the option is last, it does not have an argument:
|
||||
#
|
||||
# $ ruby types.rb --yyy
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--yyy", ""]
|
||||
#
|
||||
# If the option is followed by another option, it does not have an argument:
|
||||
#
|
||||
# $ ruby types.rb --yyy --zzz
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--yyy", ""]
|
||||
# ["--zzz", ""]
|
||||
#
|
||||
# Otherwise the option is followed by its argument, which is associated
|
||||
# with that option:
|
||||
#
|
||||
# $ ruby types.rb --yyy foo
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--yyy", "foo"]
|
||||
#
|
||||
# ==== Option with No Argument
|
||||
#
|
||||
# An option of type <tt>GetoptLong::NO_ARGUMENT</tt> takes no argument:
|
||||
#
|
||||
# ruby types.rb --zzz foo
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# ["--zzz", ""]
|
||||
#
|
||||
# === ARGV
|
||||
#
|
||||
# You can process options either with method #each and a block,
|
||||
# or with method #get.
|
||||
#
|
||||
# During processing, each found option is removed, along with its argument
|
||||
# if there is one.
|
||||
# After processing, each remaining element was neither an option
|
||||
# nor the argument for an option.
|
||||
#
|
||||
# File <tt>argv.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/argv.rb
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby argv.rb --xxx Foo --yyy Bar Baz --zzz Bat Bam
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# Original ARGV: ["--xxx", "Foo", "--yyy", "Bar", "Baz", "--zzz", "Bat", "Bam"]
|
||||
# ["--xxx", "Foo"]
|
||||
# ["--yyy", "Bar"]
|
||||
# ["--zzz", ""]
|
||||
# Remaining ARGV: ["Baz", "Bat", "Bam"]
|
||||
#
|
||||
# === Ordering
|
||||
#
|
||||
# There are three settings that control the way the options
|
||||
# are interpreted:
|
||||
#
|
||||
# - +PERMUTE+.
|
||||
# - +REQUIRE_ORDER+.
|
||||
# - +RETURN_IN_ORDER+.
|
||||
#
|
||||
# The initial setting for a new \GetoptLong object is +REQUIRE_ORDER+
|
||||
# if environment variable +POSIXLY_CORRECT+ is defined, +PERMUTE+ otherwise.
|
||||
#
|
||||
# ==== PERMUTE Ordering
|
||||
#
|
||||
# In the +PERMUTE+ ordering, options and other, non-option,
|
||||
# arguments may appear in any order and any mixture.
|
||||
#
|
||||
# File <tt>permute.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/permute.rb
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby permute.rb Foo --zzz Bar --xxx Baz --yyy Bat Bam --xxx Bag Bah
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# Original ARGV: ["Foo", "--zzz", "Bar", "--xxx", "Baz", "--yyy", "Bat", "Bam", "--xxx", "Bag", "Bah"]
|
||||
# ["--zzz", ""]
|
||||
# ["--xxx", "Baz"]
|
||||
# ["--yyy", "Bat"]
|
||||
# ["--xxx", "Bag"]
|
||||
# Remaining ARGV: ["Foo", "Bar", "Bam", "Bah"]
|
||||
#
|
||||
# ==== REQUIRE_ORDER Ordering
|
||||
#
|
||||
# In the +REQUIRE_ORDER+ ordering, all options precede all non-options;
|
||||
# that is, each word after the first non-option word
|
||||
# is treated as a non-option word (even if it begins with a hyphen).
|
||||
#
|
||||
# File <tt>require_order.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/require_order.rb
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby require_order.rb --xxx Foo Bar --xxx Baz --yyy Bat -zzz
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# Original ARGV: ["--xxx", "Foo", "Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
|
||||
# ["--xxx", "Foo"]
|
||||
# Remaining ARGV: ["Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
|
||||
#
|
||||
# ==== RETURN_IN_ORDER Ordering
|
||||
#
|
||||
# In the +RETURN_IN_ORDER+ ordering, every word is treated as an option.
|
||||
# A word that begins with a hyphen (or two) is treated in the usual way;
|
||||
# a word +word+ that does not so begin is treated as an option
|
||||
# whose name is an empty string, and whose value is +word+.
|
||||
#
|
||||
# File <tt>return_in_order.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/return_in_order.rb
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby return_in_order.rb Foo --xxx Bar Baz --zzz Bat Bam
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# Original ARGV: ["Foo", "--xxx", "Bar", "Baz", "--zzz", "Bat", "Bam"]
|
||||
# ["", "Foo"]
|
||||
# ["--xxx", "Bar"]
|
||||
# ["", "Baz"]
|
||||
# ["--zzz", ""]
|
||||
# ["", "Bat"]
|
||||
# ["", "Bam"]
|
||||
# Remaining ARGV: []
|
||||
#
|
||||
# === Full Example
|
||||
#
|
||||
# File <tt>fibonacci.rb</tt>:
|
||||
#
|
||||
# :include: ../sample/getoptlong/fibonacci.rb
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby fibonacci.rb
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# Option --number is required.
|
||||
# Usage:
|
||||
#
|
||||
# -n n, --number n:
|
||||
# Compute Fibonacci number for n.
|
||||
# -v [boolean], --verbose [boolean]:
|
||||
# Show intermediate results; default is 'false'.
|
||||
# -h, --help:
|
||||
# Show this help.
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby fibonacci.rb --number
|
||||
#
|
||||
# Raises GetoptLong::MissingArgument:
|
||||
#
|
||||
# fibonacci.rb: option `--number' requires an argument
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby fibonacci.rb --number 6
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# 8
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby fibonacci.rb --number 6 --verbose
|
||||
#
|
||||
# Output:
|
||||
# 1
|
||||
# 2
|
||||
# 3
|
||||
# 5
|
||||
# 8
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# $ ruby fibonacci.rb --number 6 --verbose yes
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# --verbose argument must be true or false
|
||||
# Usage:
|
||||
#
|
||||
# -n n, --number n:
|
||||
# Compute Fibonacci number for n.
|
||||
# -v [boolean], --verbose [boolean]:
|
||||
# Show intermediate results; default is 'false'.
|
||||
# -h, --help:
|
||||
# Show this help.
|
||||
#
|
||||
class GetoptLong
|
||||
# Version.
|
||||
VERSION = "0.2.1"
|
||||
|
||||
#
|
||||
# Orderings.
|
||||
#
|
||||
ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2]
|
||||
|
||||
#
|
||||
# Argument flags.
|
||||
#
|
||||
ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1,
|
||||
OPTIONAL_ARGUMENT = 2]
|
||||
|
||||
#
|
||||
# Status codes.
|
||||
#
|
||||
STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0, 1, 2
|
||||
|
||||
#
|
||||
# Error types.
|
||||
#
|
||||
class Error < StandardError; end
|
||||
class AmbiguousOption < Error; end
|
||||
class NeedlessArgument < Error; end
|
||||
class MissingArgument < Error; end
|
||||
class InvalidOption < Error; end
|
||||
|
||||
#
|
||||
# Returns a new \GetoptLong object based on the given +arguments+.
|
||||
# See {Options}[#class-GetoptLong-label-Options].
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# :include: ../sample/getoptlong/simple.rb
|
||||
#
|
||||
# Raises an exception if:
|
||||
#
|
||||
# - Any of +arguments+ is not an array.
|
||||
# - Any option name or alias is not a string.
|
||||
# - Any option type is invalid.
|
||||
#
|
||||
def initialize(*arguments)
|
||||
#
|
||||
# Current ordering.
|
||||
#
|
||||
if ENV.include?('POSIXLY_CORRECT')
|
||||
@ordering = REQUIRE_ORDER
|
||||
else
|
||||
@ordering = PERMUTE
|
||||
end
|
||||
|
||||
#
|
||||
# Hash table of option names.
|
||||
# Keys of the table are option names, and their values are canonical
|
||||
# names of the options.
|
||||
#
|
||||
@canonical_names = Hash.new
|
||||
|
||||
#
|
||||
# Hash table of argument flags.
|
||||
# Keys of the table are option names, and their values are argument
|
||||
# flags of the options.
|
||||
#
|
||||
@argument_flags = Hash.new
|
||||
|
||||
#
|
||||
# Whether error messages are output to $stderr.
|
||||
#
|
||||
@quiet = false
|
||||
|
||||
#
|
||||
# Status code.
|
||||
#
|
||||
@status = STATUS_YET
|
||||
|
||||
#
|
||||
# Error code.
|
||||
#
|
||||
@error = nil
|
||||
|
||||
#
|
||||
# Error message.
|
||||
#
|
||||
@error_message = nil
|
||||
|
||||
#
|
||||
# Rest of catenated short options.
|
||||
#
|
||||
@rest_singles = ''
|
||||
|
||||
#
|
||||
# List of non-option-arguments.
|
||||
# Append them to ARGV when option processing is terminated.
|
||||
#
|
||||
@non_option_arguments = Array.new
|
||||
|
||||
if 0 < arguments.length
|
||||
set_options(*arguments)
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the ordering; see {Ordering}[#class-GetoptLong-label-Ordering];
|
||||
# returns the new ordering.
|
||||
#
|
||||
# If the given +ordering+ is +PERMUTE+ and environment variable
|
||||
# +POSIXLY_CORRECT+ is defined, sets the ordering to +REQUIRE_ORDER+;
|
||||
# otherwise sets the ordering to +ordering+:
|
||||
#
|
||||
# options = GetoptLong.new
|
||||
# options.ordering == GetoptLong::PERMUTE # => true
|
||||
# options.ordering = GetoptLong::RETURN_IN_ORDER
|
||||
# options.ordering == GetoptLong::RETURN_IN_ORDER # => true
|
||||
# ENV['POSIXLY_CORRECT'] = 'true'
|
||||
# options.ordering = GetoptLong::PERMUTE
|
||||
# options.ordering == GetoptLong::REQUIRE_ORDER # => true
|
||||
#
|
||||
# Raises an exception if +ordering+ is invalid.
|
||||
#
|
||||
def ordering=(ordering)
|
||||
#
|
||||
# The method is failed if option processing has already started.
|
||||
#
|
||||
if @status != STATUS_YET
|
||||
set_error(ArgumentError, "argument error")
|
||||
raise RuntimeError,
|
||||
"invoke ordering=, but option processing has already started"
|
||||
end
|
||||
|
||||
#
|
||||
# Check ordering.
|
||||
#
|
||||
if !ORDERINGS.include?(ordering)
|
||||
raise ArgumentError, "invalid ordering `#{ordering}'"
|
||||
end
|
||||
if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT')
|
||||
@ordering = REQUIRE_ORDER
|
||||
else
|
||||
@ordering = ordering
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the ordering setting.
|
||||
#
|
||||
attr_reader :ordering
|
||||
|
||||
#
|
||||
# Replaces existing options with those given by +arguments+,
|
||||
# which have the same form as the arguments to ::new;
|
||||
# returns +self+.
|
||||
#
|
||||
# Raises an exception if option processing has begun.
|
||||
#
|
||||
def set_options(*arguments)
|
||||
#
|
||||
# The method is failed if option processing has already started.
|
||||
#
|
||||
if @status != STATUS_YET
|
||||
raise RuntimeError,
|
||||
"invoke set_options, but option processing has already started"
|
||||
end
|
||||
|
||||
#
|
||||
# Clear tables of option names and argument flags.
|
||||
#
|
||||
@canonical_names.clear
|
||||
@argument_flags.clear
|
||||
|
||||
arguments.each do |arg|
|
||||
if !arg.is_a?(Array)
|
||||
raise ArgumentError, "the option list contains non-Array argument"
|
||||
end
|
||||
|
||||
#
|
||||
# Find an argument flag and it set to `argument_flag'.
|
||||
#
|
||||
argument_flag = nil
|
||||
arg.each do |i|
|
||||
if ARGUMENT_FLAGS.include?(i)
|
||||
if argument_flag != nil
|
||||
raise ArgumentError, "too many argument-flags"
|
||||
end
|
||||
argument_flag = i
|
||||
end
|
||||
end
|
||||
|
||||
raise ArgumentError, "no argument-flag" if argument_flag == nil
|
||||
|
||||
canonical_name = nil
|
||||
arg.each do |i|
|
||||
#
|
||||
# Check an option name.
|
||||
#
|
||||
next if i == argument_flag
|
||||
begin
|
||||
if !i.is_a?(String) || i !~ /\A-([^-]|-.+)\z/
|
||||
raise ArgumentError, "an invalid option `#{i}'"
|
||||
end
|
||||
if (@canonical_names.include?(i))
|
||||
raise ArgumentError, "option redefined `#{i}'"
|
||||
end
|
||||
rescue
|
||||
@canonical_names.clear
|
||||
@argument_flags.clear
|
||||
raise
|
||||
end
|
||||
|
||||
#
|
||||
# Register the option (`i') to the `@canonical_names' and
|
||||
# `@canonical_names' Hashes.
|
||||
#
|
||||
if canonical_name == nil
|
||||
canonical_name = i
|
||||
end
|
||||
@canonical_names[i] = canonical_name
|
||||
@argument_flags[i] = argument_flag
|
||||
end
|
||||
raise ArgumentError, "no option name" if canonical_name == nil
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
#
|
||||
# Sets quiet mode and returns the given argument:
|
||||
#
|
||||
# - When +false+ or +nil+, error messages are written to <tt>$stdout</tt>.
|
||||
# - Otherwise, error messages are not written.
|
||||
#
|
||||
attr_writer :quiet
|
||||
|
||||
#
|
||||
# Returns the quiet mode setting.
|
||||
#
|
||||
attr_reader :quiet
|
||||
alias quiet? quiet
|
||||
|
||||
#
|
||||
# Terminate option processing;
|
||||
# returns +nil+ if processing has already terminated;
|
||||
# otherwise returns +self+.
|
||||
#
|
||||
def terminate
|
||||
return nil if @status == STATUS_TERMINATED
|
||||
raise RuntimeError, "an error has occurred" if @error != nil
|
||||
|
||||
@status = STATUS_TERMINATED
|
||||
@non_option_arguments.reverse_each do |argument|
|
||||
ARGV.unshift(argument)
|
||||
end
|
||||
|
||||
@canonical_names = nil
|
||||
@argument_flags = nil
|
||||
@rest_singles = nil
|
||||
@non_option_arguments = nil
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
#
|
||||
# Returns +true+ if option processing has terminated, +false+ otherwise.
|
||||
#
|
||||
def terminated?
|
||||
return @status == STATUS_TERMINATED
|
||||
end
|
||||
|
||||
#
|
||||
# \Set an error (a protected method).
|
||||
#
|
||||
def set_error(type, message)
|
||||
$stderr.print("#{$0}: #{message}\n") if !@quiet
|
||||
|
||||
@error = type
|
||||
@error_message = message
|
||||
@canonical_names = nil
|
||||
@argument_flags = nil
|
||||
@rest_singles = nil
|
||||
@non_option_arguments = nil
|
||||
|
||||
raise type, message
|
||||
end
|
||||
protected :set_error
|
||||
|
||||
#
|
||||
# Returns whether option processing has failed.
|
||||
#
|
||||
attr_reader :error
|
||||
alias error? error
|
||||
|
||||
# Return the appropriate error message in POSIX-defined format.
|
||||
# If no error has occurred, returns +nil+.
|
||||
#
|
||||
def error_message
|
||||
return @error_message
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the next option as a 2-element array containing:
|
||||
#
|
||||
# - The option name (the name itself, not an alias).
|
||||
# - The option value.
|
||||
#
|
||||
# Returns +nil+ if there are no more options.
|
||||
#
|
||||
def get
|
||||
option_name, option_argument = nil, ''
|
||||
|
||||
#
|
||||
# Check status.
|
||||
#
|
||||
return nil if @error != nil
|
||||
case @status
|
||||
when STATUS_YET
|
||||
@status = STATUS_STARTED
|
||||
when STATUS_TERMINATED
|
||||
return nil
|
||||
end
|
||||
|
||||
#
|
||||
# Get next option argument.
|
||||
#
|
||||
if 0 < @rest_singles.length
|
||||
argument = '-' + @rest_singles
|
||||
elsif (ARGV.length == 0)
|
||||
terminate
|
||||
return nil
|
||||
elsif @ordering == PERMUTE
|
||||
while 0 < ARGV.length && ARGV[0] !~ /\A-./
|
||||
@non_option_arguments.push(ARGV.shift)
|
||||
end
|
||||
if ARGV.length == 0
|
||||
terminate
|
||||
return nil
|
||||
end
|
||||
argument = ARGV.shift
|
||||
elsif @ordering == REQUIRE_ORDER
|
||||
if (ARGV[0] !~ /\A-./)
|
||||
terminate
|
||||
return nil
|
||||
end
|
||||
argument = ARGV.shift
|
||||
else
|
||||
argument = ARGV.shift
|
||||
end
|
||||
|
||||
#
|
||||
# Check the special argument `--'.
|
||||
# `--' indicates the end of the option list.
|
||||
#
|
||||
if argument == '--' && @rest_singles.length == 0
|
||||
terminate
|
||||
return nil
|
||||
end
|
||||
|
||||
#
|
||||
# Check for long and short options.
|
||||
#
|
||||
if argument =~ /\A(--[^=]+)/ && @rest_singles.length == 0
|
||||
#
|
||||
# This is a long style option, which start with `--'.
|
||||
#
|
||||
pattern = $1
|
||||
if @canonical_names.include?(pattern)
|
||||
option_name = pattern
|
||||
else
|
||||
#
|
||||
# The option `option_name' is not registered in `@canonical_names'.
|
||||
# It may be an abbreviated.
|
||||
#
|
||||
matches = []
|
||||
@canonical_names.each_key do |key|
|
||||
if key.index(pattern) == 0
|
||||
option_name = key
|
||||
matches << key
|
||||
end
|
||||
end
|
||||
if 2 <= matches.length
|
||||
set_error(AmbiguousOption, "option `#{argument}' is ambiguous between #{matches.join(', ')}")
|
||||
elsif matches.length == 0
|
||||
set_error(InvalidOption, "unrecognized option `#{argument}'")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Check an argument to the option.
|
||||
#
|
||||
if @argument_flags[option_name] == REQUIRED_ARGUMENT
|
||||
if argument =~ /=(.*)/m
|
||||
option_argument = $1
|
||||
elsif 0 < ARGV.length
|
||||
option_argument = ARGV.shift
|
||||
else
|
||||
set_error(MissingArgument,
|
||||
"option `#{argument}' requires an argument")
|
||||
end
|
||||
elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
|
||||
if argument =~ /=(.*)/m
|
||||
option_argument = $1
|
||||
elsif 0 < ARGV.length && ARGV[0] !~ /\A-./
|
||||
option_argument = ARGV.shift
|
||||
else
|
||||
option_argument = ''
|
||||
end
|
||||
elsif argument =~ /=(.*)/m
|
||||
set_error(NeedlessArgument,
|
||||
"option `#{option_name}' doesn't allow an argument")
|
||||
end
|
||||
|
||||
elsif argument =~ /\A(-(.))(.*)/m
|
||||
#
|
||||
# This is a short style option, which start with `-' (not `--').
|
||||
# Short options may be catenated (e.g. `-l -g' is equivalent to
|
||||
# `-lg').
|
||||
#
|
||||
option_name, ch, @rest_singles = $1, $2, $3
|
||||
|
||||
if @canonical_names.include?(option_name)
|
||||
#
|
||||
# The option `option_name' is found in `@canonical_names'.
|
||||
# Check its argument.
|
||||
#
|
||||
if @argument_flags[option_name] == REQUIRED_ARGUMENT
|
||||
if 0 < @rest_singles.length
|
||||
option_argument = @rest_singles
|
||||
@rest_singles = ''
|
||||
elsif 0 < ARGV.length
|
||||
option_argument = ARGV.shift
|
||||
else
|
||||
# 1003.2 specifies the format of this message.
|
||||
set_error(MissingArgument, "option requires an argument -- #{ch}")
|
||||
end
|
||||
elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
|
||||
if 0 < @rest_singles.length
|
||||
option_argument = @rest_singles
|
||||
@rest_singles = ''
|
||||
elsif 0 < ARGV.length && ARGV[0] !~ /\A-./
|
||||
option_argument = ARGV.shift
|
||||
else
|
||||
option_argument = ''
|
||||
end
|
||||
end
|
||||
else
|
||||
#
|
||||
# This is an invalid option.
|
||||
# 1003.2 specifies the format of this message.
|
||||
#
|
||||
if ENV.include?('POSIXLY_CORRECT')
|
||||
set_error(InvalidOption, "invalid option -- #{ch}")
|
||||
else
|
||||
set_error(InvalidOption, "invalid option -- #{ch}")
|
||||
end
|
||||
end
|
||||
else
|
||||
#
|
||||
# This is a non-option argument.
|
||||
# Only RETURN_IN_ORDER fell into here.
|
||||
#
|
||||
return '', argument
|
||||
end
|
||||
|
||||
return @canonical_names[option_name], option_argument
|
||||
end
|
||||
alias get_option get
|
||||
|
||||
#
|
||||
# Calls the given block with each option;
|
||||
# each option is a 2-element array containing:
|
||||
#
|
||||
# - The option name (the name itself, not an alias).
|
||||
# - The option value.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# :include: ../sample/getoptlong/each.rb
|
||||
#
|
||||
# Command line:
|
||||
#
|
||||
# ruby each.rb -xxx Foo -x Bar --yyy Baz -y Bat --zzz
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# Original ARGV: ["-xxx", "Foo", "-x", "Bar", "--yyy", "Baz", "-y", "Bat", "--zzz"]
|
||||
# ["--xxx", "xx"]
|
||||
# ["--xxx", "Bar"]
|
||||
# ["--yyy", "Baz"]
|
||||
# ["--yyy", "Bat"]
|
||||
# ["--zzz", ""]
|
||||
# Remaining ARGV: ["Foo"]
|
||||
#
|
||||
def each
|
||||
loop do
|
||||
option_name, option_argument = get_option
|
||||
break if option_name == nil
|
||||
yield option_name, option_argument
|
||||
end
|
||||
end
|
||||
alias each_option each
|
||||
end
|
|
@ -1,163 +0,0 @@
|
|||
require 'test/unit'
|
||||
require 'getoptlong'
|
||||
|
||||
class TestGetoptLong < Test::Unit::TestCase
|
||||
|
||||
def verify(test_argv, expected_remaining_argv, expected_options)
|
||||
# Save ARGV and replace it with a test ARGV.
|
||||
argv_saved = ARGV.dup
|
||||
ARGV.replace(test_argv)
|
||||
# Define options.
|
||||
opts = GetoptLong.new(
|
||||
['--xxx', '-x', '--aaa', '-a', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--yyy', '-y', '--bbb', '-b', GetoptLong::OPTIONAL_ARGUMENT],
|
||||
['--zzz', '-z', '--ccc', '-c', GetoptLong::NO_ARGUMENT]
|
||||
)
|
||||
opts.quiet = true
|
||||
# Gather options.
|
||||
actual_options = []
|
||||
opts.each do |opt, arg|
|
||||
actual_options << "#{opt}: #{arg}"
|
||||
end
|
||||
# Save remaining test ARGV and restore original ARGV.
|
||||
actual_remaining_argv = ARGV.dup
|
||||
ARGV.replace(argv_saved)
|
||||
# Assert.
|
||||
assert_equal(expected_remaining_argv, actual_remaining_argv, 'ARGV')
|
||||
assert_equal(expected_options, actual_options, 'Options')
|
||||
end
|
||||
|
||||
def test_no_options
|
||||
expected_options = []
|
||||
expected_argv = %w[foo bar]
|
||||
argv = %w[foo bar]
|
||||
verify(argv, expected_argv, expected_options)
|
||||
end
|
||||
|
||||
def test_required_argument
|
||||
expected_options = [
|
||||
'--xxx: arg'
|
||||
]
|
||||
expected_argv = %w[foo bar]
|
||||
options = %w[--xxx --xx --x -x --aaa --aa --a -a]
|
||||
options.each do |option|
|
||||
argv = ['foo', option, 'arg', 'bar']
|
||||
verify(argv, expected_argv, expected_options)
|
||||
end
|
||||
end
|
||||
|
||||
def test_required_argument_missing
|
||||
options = %w[--xxx --xx --x -x --aaa --aa --a -a]
|
||||
options.each do |option|
|
||||
argv = [option]
|
||||
e = assert_raise(GetoptLong::MissingArgument) do
|
||||
verify(argv, [], [])
|
||||
end
|
||||
assert_match('requires an argument', e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_optional_argument
|
||||
expected_options = [
|
||||
'--yyy: arg'
|
||||
]
|
||||
expected_argv = %w[foo bar]
|
||||
options = %w[--yyy --y --y -y --bbb --bb --b -b]
|
||||
options.each do |option|
|
||||
argv = ['foo', 'bar', option, 'arg']
|
||||
verify(argv, expected_argv, expected_options)
|
||||
end
|
||||
end
|
||||
|
||||
def test_optional_argument_missing
|
||||
expected_options = [
|
||||
'--yyy: '
|
||||
]
|
||||
expected_argv = %w[foo bar]
|
||||
options = %w[--yyy --y --y -y --bbb --bb --b -b]
|
||||
options.each do |option|
|
||||
argv = ['foo', 'bar', option]
|
||||
verify(argv, expected_argv, expected_options)
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_argument
|
||||
expected_options = [
|
||||
'--zzz: '
|
||||
]
|
||||
expected_argv = %w[foo bar]
|
||||
options = %w[--zzz --zz --z -z --ccc --cc --c -c]
|
||||
options.each do |option|
|
||||
argv = ['foo', option, 'bar']
|
||||
verify(argv, expected_argv, expected_options)
|
||||
end
|
||||
end
|
||||
|
||||
def test_new_with_empty_array
|
||||
e = assert_raise(ArgumentError) do
|
||||
GetoptLong.new([])
|
||||
end
|
||||
assert_match(/no argument-flag/, e.message)
|
||||
end
|
||||
|
||||
def test_new_with_bad_array
|
||||
e = assert_raise(ArgumentError) do
|
||||
GetoptLong.new('foo')
|
||||
end
|
||||
assert_match(/option list contains non-Array argument/, e.message)
|
||||
end
|
||||
|
||||
def test_new_with_empty_subarray
|
||||
e = assert_raise(ArgumentError) do
|
||||
GetoptLong.new([[]])
|
||||
end
|
||||
assert_match(/no argument-flag/, e.message)
|
||||
end
|
||||
|
||||
def test_new_with_bad_subarray
|
||||
e = assert_raise(ArgumentError) do
|
||||
GetoptLong.new([1])
|
||||
end
|
||||
assert_match(/no option name/, e.message)
|
||||
end
|
||||
|
||||
def test_new_with_invalid_option
|
||||
invalid_options = %w[verbose -verbose -- +]
|
||||
invalid_options.each do |invalid_option|
|
||||
e = assert_raise(ArgumentError, invalid_option.to_s) do
|
||||
arguments = [
|
||||
[invalid_option, '-v', GetoptLong::NO_ARGUMENT]
|
||||
]
|
||||
GetoptLong.new(*arguments)
|
||||
end
|
||||
assert_match(/invalid option/, e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_new_with_invalid_alias
|
||||
invalid_aliases = %w[v - -- +]
|
||||
invalid_aliases.each do |invalid_alias|
|
||||
e = assert_raise(ArgumentError, invalid_alias.to_s) do
|
||||
arguments = [
|
||||
['--verbose', invalid_alias, GetoptLong::NO_ARGUMENT]
|
||||
]
|
||||
GetoptLong.new(*arguments)
|
||||
end
|
||||
assert_match(/invalid option/, e.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_new_with_invalid_flag
|
||||
invalid_flags = ['foo']
|
||||
invalid_flags.each do |invalid_flag|
|
||||
e = assert_raise(ArgumentError, invalid_flag.to_s) do
|
||||
arguments = [
|
||||
['--verbose', '-v', invalid_flag]
|
||||
]
|
||||
GetoptLong.new(*arguments)
|
||||
end
|
||||
assert_match(/no argument-flag/, e.message)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Загрузка…
Ссылка в новой задаче