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

Methods

Classes and Modules

Class GetoptLong::AmbigousOption
Class GetoptLong::Error
Class GetoptLong::InvalidOption
Class GetoptLong::MissingArgument
Class GetoptLong::NeedlessArgument

Constants

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

External Aliases

quiet -> quiet?
  `quiet?’ is an alias of `quiet’.
error -> error?
  `error?’ is an alias of `error’.

Attributes

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.

Public Class methods

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.

[Source]

     # 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

Public Instance methods

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.

[Source]

     # 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
each_option()

Alias for each

Return the appropriate error message in POSIX-defined format. If no error has occurred, returns nil.

[Source]

     # 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).

[Source]

     # 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
get_option()

Alias for get

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.

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # File lib/getoptlong.rb, line 386
386:   def terminated?
387:     return @status == STATUS_TERMINATED
388:   end

Protected Instance methods

Set an error (protected).

[Source]

     # 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

[Validate]