類別 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
方法來處理選項。
在處理過程中,會移除每個找到的選項,以及其參數(如果存在)。處理完畢後,每個剩餘元素既不是選項,也不是選項的參數。
File
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
排序中,選項和其他非選項參數可以出現在任何順序和任何組合中。
File
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
排序中,所有選項都優先於所有非選項;也就是說,第一個非選項字詞之後的每個字詞都視為非選項字詞(即使它以連字號開頭)。
File
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
。
File
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: []
完整範例¶ ↑
File
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 物件。請參閱 選項。
範例
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