Spec-Zone.ru › Ruby 3

класс GetoptLong

Родитель:
Объект

Класс GetoptLong позволяет анализировать командную строку, аналогично вызову функции GNU getopt_long() в C. Однако обратите внимание, что GetoptLong является чистой реализацией на Ruby.

GetoptLong поддерживает опции в стиле POSIX, такие как --file, а также однобуквенные опции, такие как -f

Пустая опция -- (два знака минус) используется для завершения обработки опций. Это особенно важно, если опции имеют необязательные аргументы.

Вот простой пример использования:

require 'getoptlong'

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'
      puts <<-EOF
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.
      EOF
    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

Пример командной строки:

hello -n 6 --name -- /tmp

Константы

ARGUMENT_FLAGS

Флаги аргументов.

ORDERINGS

Порядки.

STATUS_TERMINATED
VERSION

Версия.

Атрибуты

error[R]

Проверка на ошибку при обработке опций.

error?[R]

Проверка на ошибку при обработке опций.

ordering[R]

Возвращает порядок.

quiet[RW]

Включение/выключение режима «безмолвия».

quiet?[RW]

Включение/выключение режима «безмолвия».

Открытые методы класса

new(*arguments) Показать исходный код
# File lib/getoptlong.rb, line 132
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

Настройка обработки опций.

Опции для поддержки передаются в new() в виде массива массивов. Каждый подмассив содержит любое количество String имён опций, которые имеют одинаковое значение, и один из следующих флагов:

GetoptLong::NO_ARGUMENT

Опция не принимает аргумент.

GetoptLong::REQUIRED_ARGUMENT

Опция всегда принимает аргумент.

GetoptLong::OPTIONAL_ARGUMENT

Опция может принимать или не принимать аргумент.

Первое имя опции считается предпочтительным (каноническим). Помимо этого, элементы каждого подмассива могут быть в любом порядке.

Открытые методы экземпляра

each() { |option_name, option_argument| ... } Показать исходный код
# File lib/getoptlong.rb, line 604
def each
  loop do
    option_name, option_argument = get_option
    break if option_name == nil
    yield option_name, option_argument
  end
end

Итератор для метода `get'.

Блок вызывается многократно с двумя аргументами: первый — имя опции, второй — аргумент, который за ней следует (если есть). Пример: ('–opt', 'value')

Имя опции всегда преобразуется в первое (предпочтительное) имя, указанное в исходных опциях для GetoptLong.new.

Также алиас: each_option
each_option()

`each_option' — псевдоним для `each'.

Псевдоним для: each
error_message() Показать исходный код
# File lib/getoptlong.rb, line 415
def error_message
  return @error_message
end

Возвращает соответствующее сообщение об ошибке в формате, определённом POSIX. Если ошибок нет, возвращает nil.

get() Показать исходный код
# File lib/getoptlong.rb, line 430
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

Получение следующего имени опции и её аргумента, как массива из двух элементов.

Имя опции всегда преобразуется в первое (предпочтительное) имя, указанное в исходных опциях для GetoptLong.new.

Пример: ['–option', 'value']

Возвращает nil, если обработка завершена (определяется STATUS_TERMINATED).

Также алиас: get_option
get_option()

`get_option' — псевдоним для `get'.

Псевдоним для: get
ordering=(ordering) Показать исходный код
# File lib/getoptlong.rb, line 241
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

Установка обработки порядка опций и аргументов. Если обработка опций уже началась, возбуждается исключение RuntimeError.

Переданное значение должно быть членом GetoptLong::ORDERINGS. Оно изменяет обработку опций следующим образом:

REQUIRE_ORDER :

Опции должны предшествовать не-опциям.

Обработка опций завершается, как только встречается слово, не предваряемое соответствующим флагом опции.

Например, если -a и -b — опции без аргументов, при анализе командной строки '-a one -b two' в ARGV останутся 'one', '-b', 'two', а только ('-a', '') будет обработано как пара опция/аргумент.

Это порядок по умолчанию, если переменная окружения POSIXLY_CORRECT установлена. (Это для совместимости с GNU getopt_long.)

PERMUTE :

Опции могут встречаться в любой части командной строки. Это поведение по умолчанию.

Каждая последовательность слов, которая может быть интерпретирована как опция (с аргументом или без), рассматривается как опция; слова, не являющиеся опциями, пропускаются.

Например, если -a не требует аргумента, а -b — необязательно принимает аргумент, при анализе командной строки '-a one -b two three' будут обработаны пары опция/аргумент ('-a','') и ('-b', 'two'), а 'one','three' останутся в ARGV.

Если порядок установлен на PERMUTE, но переменная окружения POSIXLY_CORRECT установлена, используется REQUIRE_ORDER. Это для совместимости с GNU getopt_long.

RETURN_IN_ORDER :

Все слова в командной строке обрабатываются как опции. Слова, не предваряемые коротким или длинным флагом опции, передаются как аргументы с опцией '' (пустая строка).

Например, если -a требует аргумента, а -b — нет, для командной строки '-a one -b two three' будут обработаны пары опция/аргумент ('-a', 'one') ('-b', ''), ('', 'two'), ('', 'three').

set_options(*arguments) Показать исходный код
# File lib/getoptlong.rb, line 274
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

Установка опций. Принимает такие же аргументы, как и GetoptLong.new.

Возбуждает исключение RuntimeError, если обработка опций уже началась.

terminate() Показать исходный код
# File lib/getoptlong.rb, line 361
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?() Показать исходный код
# File lib/getoptlong.rb, line 381
def terminated?
  return @status == STATUS_TERMINATED
end

Возвращает true, если обработка опций завершена, и false в противном случае.

Защищённые методы экземпляра

set_error(type, message) Показать исходный код
# File lib/getoptlong.rb, line 388
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

Установка ошибки (защищённый метод).

Ruby Core © 1993–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API