类 GetoptLong
类 GetoptLong 提供对选项和常规参数的解析。
使用 GetoptLong,您可以为程序定义选项。然后,程序可以捕获并响应执行程序的命令中包含的任何选项。
一个简单的示例:文件 simple.rb
require 'getoptlong' options = GetoptLong.new( ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT], ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT] )
如果您对选项比较熟悉,则可以跳到此 完整示例。
选项¶ ↑
GetoptLong 选项具有
-
字符串选项名称。
-
零个或多个字符串别名。
-
选项类型。
可以通过调用单例方法 GetoptLong.new
来定义选项,该方法返回一个新的 GetoptLong 对象。然后可以通过调用其他方法(例如 GetoptLong#each
)来处理选项。
选项名称和别名¶ ↑
在定义选项的数组中,第一个元素是字符串选项名称。通常,名称采用“长”形式,以两个连字符开头。
选项名称可以具有任意数量的别名,这些别名由其他字符串元素定义。
名称和每个别名必须采用以下两种形式之一
-
两个连字符,后跟一个或多个字母。
-
一个连字符,后跟一个字母。
File
aliases.rb
require 'getoptlong' options = GetoptLong.new( ['--xxx', '-x', '--aaa', '-a', '-p', GetoptLong::NO_ARGUMENT] ) options.each do |option, argument| p [option, argument] end
选项可以通过其名称或其任何别名引用;解析的选项始终报告名称,而不是别名
$ ruby aliases.rb -a -p --xxx --aaa -x
输出
["--xxx", ""] ["--xxx", ""] ["--xxx", ""] ["--xxx", ""] ["--xxx", ""]
选项也可以用其名称或任何别名的缩写来引用,只要该缩写是选项中唯一的。
File
abbrev.rb
require 'getoptlong' options = GetoptLong.new( ['--xxx', GetoptLong::NO_ARGUMENT], ['--xyz', GetoptLong::NO_ARGUMENT] ) options.each do |option, argument| p [option, argument] end
命令行
$ ruby abbrev.rb --xxx --xx --xyz --xy
输出
["--xxx", ""] ["--xxx", ""] ["--xyz", ""] ["--xyz", ""]
此命令行引发 GetoptLong::AmbiguousOption
$ ruby abbrev.rb --x
重复¶ ↑
选项可以引用多次
$ ruby abbrev.rb --xxx --xyz --xxx --xyz
输出
["--xxx", ""] ["--xyz", ""] ["--xxx", ""] ["--xyz", ""]
将剩余选项视为参数¶ ↑
标记 --
之后出现的类似选项的标记将被视为普通参数,并且不会作为选项进行处理
$ ruby abbrev.rb --xxx --xyz -- --xxx --xyz
输出
["--xxx", ""] ["--xyz", ""]
选项类型¶ ↑
每个选项定义都包含一个选项类型,该类型控制选项是否采用参数。
File
types.rb
require 'getoptlong' options = GetoptLong.new( ['--xxx', GetoptLong::REQUIRED_ARGUMENT], ['--yyy', GetoptLong::OPTIONAL_ARGUMENT], ['--zzz', GetoptLong::NO_ARGUMENT] ) options.each do |option, argument| p [option, argument] end
请注意,选项类型与选项参数(无论是必需的、可选的还是禁止的)有关,而不是与选项本身是否必需有关。
带有必需参数的选项¶ ↑
类型为 GetoptLong::REQUIRED_ARGUMENT
的选项后面必须紧跟一个参数,该参数与此选项相关联
$ ruby types.rb --xxx foo
输出
["--xxx", "foo"]
如果该选项不是最后一个,则其参数是紧跟其后的任何内容(即使该参数看起来像另一个选项)
$ ruby types.rb --xxx --yyy
输出
["--xxx", "--yyy"]
如果该选项是最后一个,则会引发异常
$ ruby types.rb # Raises GetoptLong::MissingArgument
带有可选参数的选项¶ ↑
类型为 GetoptLong::OPTIONAL_ARGUMENT
的选项后面可以紧跟一个参数,如果给出,则该参数与此选项相关联。
如果该选项是最后一个,则它没有参数
$ ruby types.rb --yyy
输出
["--yyy", ""]
如果该选项后面跟着另一个选项,则它没有参数
$ ruby types.rb --yyy --zzz
输出
["--yyy", ""] ["--zzz", ""]
否则,该选项后面紧跟其参数,该参数与此选项相关联
$ ruby types.rb --yyy foo
输出
["--yyy", "foo"]
没有参数的选项¶ ↑
类型为 GetoptLong::NO_ARGUMENT
的选项不采用参数
ruby types.rb --zzz foo
输出
["--zzz", ""]
ARGV¶ ↑
您可以使用 each
方法和一个块或 get
方法来处理选项。
在处理过程中,将删除每个找到的选项,以及(如果有)其参数。处理完毕后,每个剩余元素既不是选项也不是选项的参数。
文件
argv.rb
require 'getoptlong' options = GetoptLong.new( ['--xxx', GetoptLong::REQUIRED_ARGUMENT], ['--yyy', GetoptLong::OPTIONAL_ARGUMENT], ['--zzz', GetoptLong::NO_ARGUMENT] ) puts "Original ARGV: #{ARGV}" options.each do |option, argument| p [option, argument] end puts "Remaining ARGV: #{ARGV}"
命令行
$ ruby argv.rb --xxx Foo --yyy Bar Baz --zzz Bat Bam
输出
Original ARGV: ["--xxx", "Foo", "--yyy", "Bar", "Baz", "--zzz", "Bat", "Bam"] ["--xxx", "Foo"] ["--yyy", "Bar"] ["--zzz", ""] Remaining ARGV: ["Baz", "Bat", "Bam"]
排序¶ ↑
有三个设置控制选项的解释方式
-
PERMUTE
. -
REQUIRE_ORDER
. -
RETURN_IN_ORDER
.
如果环境变量 POSIXLY_CORRECT
已定义,则新 GetoptLong 对象的初始设置是 REQUIRE_ORDER
,否则是 PERMUTE
。
PERMUTE 排序¶ ↑
在 PERMUTE
排序中,选项和其他非选项参数可以按任何顺序和任何混合出现。
文件
permute.rb
require 'getoptlong' options = GetoptLong.new( ['--xxx', GetoptLong::REQUIRED_ARGUMENT], ['--yyy', GetoptLong::OPTIONAL_ARGUMENT], ['--zzz', GetoptLong::NO_ARGUMENT] ) puts "Original ARGV: #{ARGV}" options.each do |option, argument| p [option, argument] end puts "Remaining ARGV: #{ARGV}"
命令行
$ ruby permute.rb Foo --zzz Bar --xxx Baz --yyy Bat Bam --xxx Bag Bah
输出
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 排序¶ ↑
在 REQUIRE_ORDER
排序中,所有选项都位于所有非选项之前;也就是说,第一个非选项词之后的每个词都被视为非选项词(即使它以连字符开头)。
文件
require_order.rb
require 'getoptlong' options = GetoptLong.new( ['--xxx', GetoptLong::REQUIRED_ARGUMENT], ['--yyy', GetoptLong::OPTIONAL_ARGUMENT], ['--zzz', GetoptLong::NO_ARGUMENT] ) options.ordering = GetoptLong::REQUIRE_ORDER puts "Original ARGV: #{ARGV}" options.each do |option, argument| p [option, argument] end puts "Remaining ARGV: #{ARGV}"
命令行
$ ruby require_order.rb --xxx Foo Bar --xxx Baz --yyy Bat -zzz
输出
Original ARGV: ["--xxx", "Foo", "Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"] ["--xxx", "Foo"] Remaining ARGV: ["Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
RETURN_IN_ORDER 排序¶ ↑
在 RETURN_IN_ORDER
排序中,每个词都被视为选项。以连字符(或两个连字符)开头的词以通常的方式处理;不以连字符开头的词 word
被视为选项,其名称为空字符串,其值为 word
。
文件
return_in_order.rb
require 'getoptlong' options = GetoptLong.new( ['--xxx', GetoptLong::REQUIRED_ARGUMENT], ['--yyy', GetoptLong::OPTIONAL_ARGUMENT], ['--zzz', GetoptLong::NO_ARGUMENT] ) options.ordering = GetoptLong::RETURN_IN_ORDER puts "Original ARGV: #{ARGV}" options.each do |option, argument| p [option, argument] end puts "Remaining ARGV: #{ARGV}"
命令行
$ ruby return_in_order.rb Foo --xxx Bar Baz --zzz Bat Bam
输出
Original ARGV: ["Foo", "--xxx", "Bar", "Baz", "--zzz", "Bat", "Bam"] ["", "Foo"] ["--xxx", "Bar"] ["", "Baz"] ["--zzz", ""] ["", "Bat"] ["", "Bam"] Remaining ARGV: []
完整示例¶ ↑
文件
fibonacci.rb
require 'getoptlong' options = GetoptLong.new( ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT], ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT] ) def help(status = 0) puts <<~HELP 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. HELP exit(status) end def print_fibonacci (number) return 0 if number == 0 return 1 if number == 1 or number == 2 i = 0 j = 1 (2..number).each do k = i + j i = j j = k puts j if @verbose end puts j unless @verbose end options.each do |option, argument| case option when '--number' @number = argument.to_i when '--verbose' @verbose = if argument.empty? true elsif argument.match(/true/i) true elsif argument.match(/false/i) false else puts '--verbose argument must be true or false' help(255) end when '--help' help end end unless @number puts 'Option --number is required.' help(255) end print_fibonacci(@number)
命令行
$ ruby fibonacci.rb
输出
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.
命令行
$ ruby fibonacci.rb --number
引发 GetoptLong::MissingArgument
fibonacci.rb: option `--number' requires an argument
命令行
$ ruby fibonacci.rb --number 6
输出
8
命令行
$ ruby fibonacci.rb --number 6 --verbose
输出
1 2 3 5 8
命令行
$ ruby fibonacci.rb --number 6 --verbose yes
输出
--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.
常量
- ARGUMENT_FLAGS
参数标志。
- ORDERINGS
排序。
- STATUS_TERMINATED
- VERSION
版本。
属性
返回选项处理是否失败。
返回选项处理是否失败。
返回排序设置。
设置静默模式并返回给定的参数
-
当
false
或nil
时,错误消息会写入$stdout
。 -
否则,不会写入错误消息。
设置静默模式并返回给定的参数
-
当
false
或nil
时,错误消息会写入$stdout
。 -
否则,不会写入错误消息。
公共类方法
基于给定的arguments
返回一个新的 GetoptLong 对象。请参见 Options。
示例
require 'getoptlong' options = GetoptLong.new( ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT], ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT] )
如果
-
任何
arguments
都不是数组,则引发异常。 -
任何选项名称或别名都不是字符串。
-
任何选项类型无效。
# File lib/getoptlong.rb, line 412 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
公共实例方法
使用每个选项调用给定的块;每个选项都是包含以下内容的 2 元素数组
-
选项名称(名称本身,不是别名)。
-
选项值。
示例
require 'getoptlong' options = GetoptLong.new( ['--xxx', '-x', GetoptLong::REQUIRED_ARGUMENT], ['--yyy', '-y', GetoptLong::OPTIONAL_ARGUMENT], ['--zzz', '-z',GetoptLong::NO_ARGUMENT] ) puts "Original ARGV: #{ARGV}" options.each do |option, argument| p [option, argument] end puts "Remaining ARGV: #{ARGV}"
命令行
ruby each.rb -xxx Foo -x Bar --yyy Baz -y Bat --zzz
输出
Original ARGV: ["-xxx", "Foo", "-x", "Bar", "--yyy", "Baz", "-y", "Bat", "--zzz"] ["--xxx", "xx"] ["--xxx", "Bar"] ["--yyy", "Baz"] ["--yyy", "Bat"] ["--zzz", ""] Remaining ARGV: ["Foo"]
# File lib/getoptlong.rb, line 859 def each loop do option_name, option_argument = get_option break if option_name == nil yield option_name, option_argument end end
以 POSIX 定义的格式返回适当的错误消息。如果没有发生错误,则返回nil
。
# File lib/getoptlong.rb, line 662 def error_message return @error_message end
返回包含以下内容的 2 元素数组作为下一个选项
-
选项名称(名称本身,不是别名)。
-
选项值。
如果没有更多选项,则返回nil
。
# File lib/getoptlong.rb, line 674 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
设置排序;请参见 Ordering;返回新的排序。
如果给定的ordering
是PERMUTE
,并且定义了环境变量POSIXLY_CORRECT
,则将排序设置为REQUIRE_ORDER
;否则将排序设置为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
如果ordering
无效,则引发异常。
# File lib/getoptlong.rb, line 489 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
使用arguments
给出的选项替换现有选项,这些选项与 ::new
的参数形式相同;返回self
。
如果选项处理已开始,则引发异常。
# File lib/getoptlong.rb, line 524 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
终止选项处理;如果处理已终止,则返回nil
;否则返回self
。
# File lib/getoptlong.rb, line 612 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
如果选项处理已终止,则返回 true
,否则返回 false
。
# File lib/getoptlong.rb, line 632 def terminated? return @status == STATUS_TERMINATED end
受保护的实例方法
设置错误(受保护的方法)。
# File lib/getoptlong.rb, line 639 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