Как мне обработать отсутствующий обязательный аргумент в Ruby OptionParser?




command-line (3)

В OptionParser я могу сделать опцию обязательной, но если я пропущу это значение, он примет имя любой следующей опции в качестве значения, облажав оставшуюся часть анализа командной строки. Вот тестовый пример, который повторяет значения параметров:

$ ./test_case.rb --input foo --output bar
output  bar
input  foo

Теперь опустите значение для первого варианта:

$ ./test_case.rb --input  --output bar
input  --output

Есть ли какой-нибудь способ предотвратить использование в качестве значения имени другой опции? Спасибо!

Вот код теста:

#!/usr/bin/env ruby
require 'optparse'
files = Hash.new

option_parser = OptionParser.new do |opts|
  opts.on('-i', '--input FILENAME', 'Input filename - required') do |filename|
    files[:input] = filename
  end
  opts.on('-o', '--output FILENAME', 'Output filename - required') do |filename|
    files[:output] = filename
  end
end

begin
  option_parser.parse!(ARGV)
rescue OptionParser::ParseError
  $stderr.print "Error: " + $! + "\n"
  exit
end

files.keys.each do |key|
  print "#{key}  #{files[key]}\n"
end

В этом случае обязательная опция --output отсутствует, поэтому делайте это после вызова parse! :

unless files[:input] && files[:output]
  $stderr.puts "Error: you must specify both --input and --output options."
  exit 1
end

ОК - это работает - регулярное выражение в вызове on () допускает любую строку, если она не начинается с '-'

Если я не передам аргумент --input и есть другая опция в нисходящем направлении, тогда он примет этот ключ опции в качестве аргумента --input. (например, --input --output). Регулярное выражение ловит это, а затем я проверяю сообщение об ошибке. Если аргумент, который он сообщает, начинается с '-', я выводю правильное сообщение об ошибке, а именно, что отсутствует аргумент. Не красиво, но, похоже, работает.

Вот мой рабочий контрольный пример:

#!/usr/bin/env ruby
require 'optparse'
files = Hash.new

option_parser = OptionParser.new do |opts|
  opts.on('-i FILENAME', '--input FILENAME', /\A[^\-]+/, 'Input filename - required') do |filename|
    files[:input] = filename
  end
  opts.on('-o FILENAME', '--output FILENAME', /\A[^\-]+/, 'Output filename - required') do |filename|
    files[:output] = filename
  end
end

begin
  option_parser.parse!(ARGV)
rescue OptionParser::ParseError
  if $!.to_s =~ /invalid\s+argument\:\s+(\-\-\S+)\s+\-/
    $stderr.print "Error: missing argument: #{$1}\n"
  else 
    $stderr.print "Error: " + $! + "\n"
  end  
  exit
end

files.keys.each do |key|
  print "#{key}  #{files[key]}\n"
end

попробуй это:

opts.on('-i', '--input FILENAME', 'Input filename - required') do |filename|
  files[:input] = filename
end

opts.on('-o', '--output FILENAME', 'Output filename - required') do |filename|
  files[:output] = filename
end

opts.on("-h", "--help", "Show this message") do 
  puts opts
  exit
end


begin
  ARGV << "-h" if ARGV.size != 2   
  option_parser.parse!(ARGV)
rescue OptionParser::ParseError
  $stderr.print "Error: " + $! + "\n"
  exit
end




optionparser