Class | GetoptLong |
In: |
lib/getoptlong.rb
|
Parent: | Object |
The GetoptLong class allows you to parse command line options similarly to the GNU getopt_long() C library call. Note, however, that GetoptLong is a pure Ruby implementation.
GetoptLong allows for POSIX-style options like —file as well as single letter options like -f
The empty option — (two minus symbols) is used to end option processing. This can be particularly important if options have optional arguments.
Here is a simple example of usage:
# == Synopsis # # hello: greets user, demonstrates command line parsing # # == Usage # # hello [OPTION] ... DIR # # -h, --help: # show help # # --repeat x, -n x: # repeat x times # # --name [name]: # greet user by name, if name not supplied default is John # # DIR: The directory in which to issue the greeting. require 'getoptlong' require 'rdoc/usage' opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ], [ '--name', GetoptLong::OPTIONAL_ARGUMENT ] ) dir = nil name = nil repetitions = 1 opts.each do |opt, arg| case opt when '--help' RDoc::usage when '--repeat' repetitions = arg.to_i when '--name' if arg == '' name = 'John' else name = arg end end end if ARGV.length != 1 puts "Missing dir argument (try --help)" exit 0 end dir = ARGV.shift Dir.chdir(dir) for i in (1..repetitions) print "Hello" if name print ", #{name}" end puts end
Example command line:
hello -n 6 --name -- /tmp
ORDERINGS | = | [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2] | Orderings. | |
ARGUMENT_FLAGS | = | [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1, OPTIONAL_ARGUMENT = 2] | Argument flags. | |
STATUS_TERMINATED | = | 0, 1, 2 |
quiet | -> | quiet? |
`quiet?’ is an alias of `quiet’. | ||
error | -> | error? |
`error?’ is an alias of `error’. |
error | [R] | Examine whether an option processing is failed. |
ordering | [R] | Return ordering. |
quiet | [W] | Set/Unset `quiet’ mode. |
quiet | [R] | Return the flag of `quiet’ mode. |
Set up option processing.
The options to support are passed to new() as an array of arrays. Each sub-array contains any number of String option names which carry the same meaning, and one of the following flags:
GetoptLong::NO_ARGUMENT : | Option does not take an argument. |
GetoptLong::REQUIRED_ARGUMENT : | Option always takes an argument. |
GetoptLong::OPTIONAL_ARGUMENT : | Option may or may not take an argument. |
The first option name is considered to be the preferred (canonical) name. Other than that, the elements of each sub-array can be in any order.
# File lib/getoptlong.rb, line 135 135: def initialize(*arguments) 136: # 137: # Current ordering. 138: # 139: if ENV.include?('POSIXLY_CORRECT') 140: @ordering = REQUIRE_ORDER 141: else 142: @ordering = PERMUTE 143: end 144: 145: # 146: # Hash table of option names. 147: # Keys of the table are option names, and their values are canonical 148: # names of the options. 149: # 150: @canonical_names = Hash.new 151: 152: # 153: # Hash table of argument flags. 154: # Keys of the table are option names, and their values are argument 155: # flags of the options. 156: # 157: @argument_flags = Hash.new 158: 159: # 160: # Whether error messages are output to $deferr. 161: # 162: @quiet = FALSE 163: 164: # 165: # Status code. 166: # 167: @status = STATUS_YET 168: 169: # 170: # Error code. 171: # 172: @error = nil 173: 174: # 175: # Error message. 176: # 177: @error_message = nil 178: 179: # 180: # Rest of catenated short options. 181: # 182: @rest_singles = '' 183: 184: # 185: # List of non-option-arguments. 186: # Append them to ARGV when option processing is terminated. 187: # 188: @non_option_arguments = Array.new 189: 190: if 0 < arguments.length 191: set_options(*arguments) 192: end 193: end
Iterator version of `get’.
The block is called repeatedly with two arguments: The first is the option name. The second is the argument which followed it (if any). Example: (’—opt’, ‘value’)
The option name is always converted to the first (preferred) name given in the original options to GetoptLong.new.
# File lib/getoptlong.rb, line 609 609: def each 610: loop do 611: option_name, option_argument = get_option 612: break if option_name == nil 613: yield option_name, option_argument 614: end 615: end
Return the appropriate error message in POSIX-defined format. If no error has occurred, returns nil.
# File lib/getoptlong.rb, line 420 420: def error_message 421: return @error_message 422: end
Get next option name and its argument, as an Array of two elements.
The option name is always converted to the first (preferred) name given in the original options to GetoptLong.new.
Example: [’—option’, ‘value’]
Returns nil if the processing is complete (as determined by STATUS_TERMINATED).
# File lib/getoptlong.rb, line 435 435: def get 436: option_name, option_argument = nil, '' 437: 438: # 439: # Check status. 440: # 441: return nil if @error != nil 442: case @status 443: when STATUS_YET 444: @status = STATUS_STARTED 445: when STATUS_TERMINATED 446: return nil 447: end 448: 449: # 450: # Get next option argument. 451: # 452: if 0 < @rest_singles.length 453: argument = '-' + @rest_singles 454: elsif (ARGV.length == 0) 455: terminate 456: return nil 457: elsif @ordering == PERMUTE 458: while 0 < ARGV.length && ARGV[0] !~ /^-./ 459: @non_option_arguments.push(ARGV.shift) 460: end 461: if ARGV.length == 0 462: terminate 463: return nil 464: end 465: argument = ARGV.shift 466: elsif @ordering == REQUIRE_ORDER 467: if (ARGV[0] !~ /^-./) 468: terminate 469: return nil 470: end 471: argument = ARGV.shift 472: else 473: argument = ARGV.shift 474: end 475: 476: # 477: # Check the special argument `--'. 478: # `--' indicates the end of the option list. 479: # 480: if argument == '--' && @rest_singles.length == 0 481: terminate 482: return nil 483: end 484: 485: # 486: # Check for long and short options. 487: # 488: if argument =~ /^(--[^=]+)/ && @rest_singles.length == 0 489: # 490: # This is a long style option, which start with `--'. 491: # 492: pattern = $1 493: if @canonical_names.include?(pattern) 494: option_name = pattern 495: else 496: # 497: # The option `option_name' is not registered in `@canonical_names'. 498: # It may be an abbreviated. 499: # 500: match_count = 0 501: @canonical_names.each_key do |key| 502: if key.index(pattern) == 0 503: option_name = key 504: match_count += 1 505: end 506: end 507: if 2 <= match_count 508: set_error(AmbigousOption, "option `#{argument}' is ambiguous") 509: elsif match_count == 0 510: set_error(InvalidOption, "unrecognized option `#{argument}'") 511: end 512: end 513: 514: # 515: # Check an argument to the option. 516: # 517: if @argument_flags[option_name] == REQUIRED_ARGUMENT 518: if argument =~ /=(.*)$/ 519: option_argument = $1 520: elsif 0 < ARGV.length 521: option_argument = ARGV.shift 522: else 523: set_error(MissingArgument, 524: "option `#{argument}' requires an argument") 525: end 526: elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT 527: if argument =~ /=(.*)$/ 528: option_argument = $1 529: elsif 0 < ARGV.length && ARGV[0] !~ /^-./ 530: option_argument = ARGV.shift 531: else 532: option_argument = '' 533: end 534: elsif argument =~ /=(.*)$/ 535: set_error(NeedlessArgument, 536: "option `#{option_name}' doesn't allow an argument") 537: end 538: 539: elsif argument =~ /^(-(.))(.*)/ 540: # 541: # This is a short style option, which start with `-' (not `--'). 542: # Short options may be catenated (e.g. `-l -g' is equivalent to 543: # `-lg'). 544: # 545: option_name, ch, @rest_singles = $1, $2, $3 546: 547: if @canonical_names.include?(option_name) 548: # 549: # The option `option_name' is found in `@canonical_names'. 550: # Check its argument. 551: # 552: if @argument_flags[option_name] == REQUIRED_ARGUMENT 553: if 0 < @rest_singles.length 554: option_argument = @rest_singles 555: @rest_singles = '' 556: elsif 0 < ARGV.length 557: option_argument = ARGV.shift 558: else 559: # 1003.2 specifies the format of this message. 560: set_error(MissingArgument, "option requires an argument -- #{ch}") 561: end 562: elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT 563: if 0 < @rest_singles.length 564: option_argument = @rest_singles 565: @rest_singles = '' 566: elsif 0 < ARGV.length && ARGV[0] !~ /^-./ 567: option_argument = ARGV.shift 568: else 569: option_argument = '' 570: end 571: end 572: else 573: # 574: # This is an invalid option. 575: # 1003.2 specifies the format of this message. 576: # 577: if ENV.include?('POSIXLY_CORRECT') 578: set_error(InvalidOption, "illegal option -- #{ch}") 579: else 580: set_error(InvalidOption, "invalid option -- #{ch}") 581: end 582: end 583: else 584: # 585: # This is a non-option argument. 586: # Only RETURN_IN_ORDER falled into here. 587: # 588: return '', argument 589: end 590: 591: return @canonical_names[option_name], option_argument 592: end
Set the handling of the ordering of options and arguments. A RuntimeError is raised if option processing has already started.
The supplied value must be a member of GetoptLong::ORDERINGS. It alters the processing of options as follows:
REQUIRE_ORDER :
Options are required to occur before non-options.
Processing of options ends as soon as a word is encountered that has not been preceded by an appropriate option flag.
For example, if -a and -b are options which do not take arguments, parsing command line arguments of ’-a one -b two’ would result in ‘one’, ’-b’, ‘two’ being left in ARGV, and only (’-a’, ’’) being processed as an option/arg pair.
This is the default ordering, if the environment variable POSIXLY_CORRECT is set. (This is for compatibility with GNU getopt_long.)
PERMUTE :
Options can occur anywhere in the command line parsed. This is the default behavior.
Every sequence of words which can be interpreted as an option (with or without argument) is treated as an option; non-option words are skipped.
For example, if -a does not require an argument and -b optionally takes an argument, parsing ’-a one -b two three’ would result in (’-a’,’’) and (’-b’, ‘two’) being processed as option/arg pairs, and ‘one’,’three’ being left in ARGV.
If the ordering is set to PERMUTE but the environment variable POSIXLY_CORRECT is set, REQUIRE_ORDER is used instead. This is for compatibility with GNU getopt_long.
RETURN_IN_ORDER :
All words on the command line are processed as options. Words not preceded by a short or long option flag are passed as arguments with an option of ’’ (empty string).
For example, if -a requires an argument but -b does not, a command line of ’-a one -b two three’ would result in option/arg pairs of (’-a’, ‘one’) (’-b’, ’’), (’’, ‘two’), (’’, ‘three’) being processed.
# File lib/getoptlong.rb, line 244 244: def ordering=(ordering) 245: # 246: # The method is failed if option processing has already started. 247: # 248: if @status != STATUS_YET 249: set_error(ArgumentError, "argument error") 250: raise RuntimeError, 251: "invoke ordering=, but option processing has already started" 252: end 253: 254: # 255: # Check ordering. 256: # 257: if !ORDERINGS.include?(ordering) 258: raise ArgumentError, "invalid ordering `#{ordering}'" 259: end 260: if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT') 261: @ordering = REQUIRE_ORDER 262: else 263: @ordering = ordering 264: end 265: end
Set options. Takes the same argument as GetoptLong.new.
Raises a RuntimeError if option processing has already started.
# File lib/getoptlong.rb, line 277 277: def set_options(*arguments) 278: # 279: # The method is failed if option processing has already started. 280: # 281: if @status != STATUS_YET 282: raise RuntimeError, 283: "invoke set_options, but option processing has already started" 284: end 285: 286: # 287: # Clear tables of option names and argument flags. 288: # 289: @canonical_names.clear 290: @argument_flags.clear 291: 292: arguments.each do |arg| 293: # 294: # Each argument must be an Array. 295: # 296: if !arg.is_a?(Array) 297: raise ArgumentError, "the option list contains non-Array argument" 298: end 299: 300: # 301: # Find an argument flag and it set to `argument_flag'. 302: # 303: argument_flag = nil 304: arg.each do |i| 305: if ARGUMENT_FLAGS.include?(i) 306: if argument_flag != nil 307: raise ArgumentError, "too many argument-flags" 308: end 309: argument_flag = i 310: end 311: end 312: raise ArgumentError, "no argument-flag" if argument_flag == nil 313: 314: canonical_name = nil 315: arg.each do |i| 316: # 317: # Check an option name. 318: # 319: next if i == argument_flag 320: begin 321: if !i.is_a?(String) || i !~ /^-([^-]|-.+)$/ 322: raise ArgumentError, "an invalid option `#{i}'" 323: end 324: if (@canonical_names.include?(i)) 325: raise ArgumentError, "option redefined `#{i}'" 326: end 327: rescue 328: @canonical_names.clear 329: @argument_flags.clear 330: raise 331: end 332: 333: # 334: # Register the option (`i') to the `@canonical_names' and 335: # `@canonical_names' Hashes. 336: # 337: if canonical_name == nil 338: canonical_name = i 339: end 340: @canonical_names[i] = canonical_name 341: @argument_flags[i] = argument_flag 342: end 343: raise ArgumentError, "no option name" if canonical_name == nil 344: end 345: return self 346: end
Explicitly terminate option processing.
# File lib/getoptlong.rb, line 366 366: def terminate 367: return nil if @status == STATUS_TERMINATED 368: raise RuntimeError, "an error has occured" if @error != nil 369: 370: @status = STATUS_TERMINATED 371: @non_option_arguments.reverse_each do |argument| 372: ARGV.unshift(argument) 373: end 374: 375: @canonical_names = nil 376: @argument_flags = nil 377: @rest_singles = nil 378: @non_option_arguments = nil 379: 380: return self 381: end
Returns true if option processing has terminated, false otherwise.
# File lib/getoptlong.rb, line 386 386: def terminated? 387: return @status == STATUS_TERMINATED 388: end
Set an error (protected).
# File lib/getoptlong.rb, line 393 393: def set_error(type, message) 394: $deferr.print("#{$0}: #{message}\n") if !@quiet 395: 396: @error = type 397: @error_message = message 398: @canonical_names = nil 399: @argument_flags = nil 400: @rest_singles = nil 401: @non_option_arguments = nil 402: 403: raise type, message 404: end