класс 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
Атрибуты
Проверить, произошла ли ошибка при обработке параметров.
Проверить, произошла ли ошибка при обработке параметров.
Возвращает порядок.
Установить/снять режим «тихо».
Установить/снять режим «тихо».
Публичные методы класса
# File lib/getoptlong.rb, line 128
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
-
Параметр может или не может иметь аргумент.
Первое имя параметра считается предпочтительным (каноническим). Кроме этого, элементы каждого подмассива могут быть в любом порядке.
Публичные методы экземпляра
# File lib/getoptlong.rb, line 600
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')
Имя параметра всегда преобразуется в первое (предпочтительное) имя, указанное в исходных параметрах для ::new.
# File lib/getoptlong.rb, line 411 def error_message return @error_message end
Возвращает соответствующее сообщение об ошибке в формате, определенном POSIX. Если ошибок не было, возвращает nil.
# File lib/getoptlong.rb, line 426
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 Получить имя следующего параметра и его аргумент в виде массива из двух элементов.
Имя параметра всегда преобразуется в первое (предпочтительное) имя, указанное в исходных параметрах для ::new.
Пример: ['–option', 'value']
Возвращает nil, если обработка завершена (как определено STATUS_TERMINATED).
# File lib/getoptlong.rb, line 237
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' результатом будет 'one', '-b', 'two', оставшиеся в ARGV, и только ('-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').
# File lib/getoptlong.rb, line 270
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 Установить параметры. Принимает те же аргументы, что и ::new.
Генерирует RuntimeError, если обработка параметров уже началась.
# File lib/getoptlong.rb, line 357
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 Явно завершить обработку параметров.
# File lib/getoptlong.rb, line 377 def terminated? return @status == STATUS_TERMINATED end
Возвращает true, если обработка параметров завершена, иначе false.
Защищенные методы экземпляра
# File lib/getoptlong.rb, line 384
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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.