# class GetoptLong

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 `simple.rb`:

    require 'getoptlong'

    options = GetoptLong.new(
      ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
      ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
      ['--help', '-h', GetoptLong::NO_ARGUMENT]
    )

If you are somewhat familiar with options, you may want to skip to this full example.

## Options¶ ↑

A GetoptLong option has:

- A string option name.

- Zero or more string aliases for the name.

- An option type.

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` `aliases.rb`:

    require 'getoptlong'

    options = GetoptLong.new(
      ['--xxx', '-x', '--aaa', '-a', '-p', GetoptLong::NO_ARGUMENT]
    )
    options.each do |option, argument|
      p [option, argument]
    end

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` `abbrev.rb`:

    require 'getoptlong'

    options = GetoptLong.new(
      ['--xxx', GetoptLong::NO_ARGUMENT],
      ['--xyz', GetoptLong::NO_ARGUMENT]
    )
    options.each do |option, argument|
      p [option, argument]
    end

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 `--` 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` `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

Note that an option type has to do with the option argument (whether it is required, optional, or forbidden), not with whether the option itself is required.

#### Option with Required Argument¶ ↑

An option of type `GetoptLong::REQUIRED_ARGUMENT` 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 `GetoptLong::OPTIONAL_ARGUMENT` 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 `GetoptLong::NO_ARGUMENT` 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` `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}"

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` `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}"

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` `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}"

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` `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}"

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` `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)

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.

### Constants

ARGUMENT_FLAGS

  Argument flags.

ORDERINGS

  Orderings.

STATUS_TERMINATED
VERSION

  Version.

### Attributes

error[R]

Returns whether option processing has failed.

error?[R]

Returns whether option processing has failed.

ordering[R]

Returns the ordering setting.

quiet[RW]

Sets quiet mode and returns the given argument:

- When `false` or `nil`, error messages are written to `$stdout`.

- Otherwise, error messages are not written.

quiet?[RW]

Sets quiet mode and returns the given argument:

- When `false` or `nil`, error messages are written to `$stdout`.

- Otherwise, error messages are not written.

### Public Class Methods

new(*arguments) click to toggle source

Returns a new GetoptLong object based on the given `arguments`. See Options.

Example:

    require 'getoptlong'

    options = GetoptLong.new(
      ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
      ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
      ['--help', '-h', GetoptLong::NO_ARGUMENT]
    )

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.

    # 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

### Public Instance Methods

each() { |option_name, option_argument| ... } click to toggle source

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:

    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}"

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"]

    # 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

Also aliased as: each_option
each_option()
Alias for: each
error_message() click to toggle source

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

    # File lib/getoptlong.rb, line 662
    def error_message
      return @error_message
    end

get() click to toggle source

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.

    # 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

Also aliased as: get_option
get_option()
Alias for: get
ordering=(ordering) click to toggle source

Sets the ordering; see 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.

    # 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

set_options(*arguments) click to toggle source

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.

    # 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

terminate() click to toggle source

Terminate option processing; returns `nil` if processing has already terminated; otherwise returns `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

terminated?() click to toggle source

Returns `true` if option processing has terminated, `false` otherwise.

    # File lib/getoptlong.rb, line 632
    def terminated?
      return @status == STATUS_TERMINATED
    end

### Protected Instance Methods

set_error(type, message) click to toggle source

Set an error (a protected method).

    # 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