ruby command-line optionparser

¿Cómo manejo un argumento obligatorio que falta en Ruby OptionParser?



command-line (4)

En OptionParser puedo hacer una opción obligatoria, pero si omito ese valor tomará el nombre de cualquier opción siguiente como valor, arruinando el resto del análisis de la línea de comandos. Aquí hay un caso de prueba que refleja los valores de las opciones:

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

Ahora deja de lado el valor de la primera opción:

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

¿Hay alguna manera de evitar que tome otro nombre de opción como un valor? ¡Gracias!

Aquí está el código de caso de prueba:

#!/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


En este caso, --output opción --output obligatoria, así que ¡haga esto después de llamar a parse! :

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


Lo que quieres hacer no es una buena idea. ¿Qué pasa si realmente tiene un archivo llamado "--output"? Este es un nombre de archivo perfectamente válido en Unix. El análisis de cada opción de Unix funciona de la manera en que lo está haciendo el rubí, por lo que no debe cambiarlo, porque entonces su programa será arbitrariamente diferente de todo lo demás, lo que confunde y viola el "principio de la menor sorpresa".

La verdadera pregunta es: ¿por qué tienes este problema en primer lugar? Quizás esté ejecutando su programa desde otro programa, y ​​el programa principal está proporcionando un nombre de archivo en blanco como parámetro para --input, lo que hace que vea --output como el parámetro para --input. Puede solucionar esto siempre citando los nombres de archivos que pasa en la línea de comando:

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

Entonces, la entrada estará en blanco, y eso es fácil de detectar.

También tenga en cuenta que si --input se establece en --output (y --output no es un archivo real), puede intentar abrir el archivo --input. Si falla, imprima un mensaje como:

can''t open input file: --output: file not found

Y eso debería dejarle claro al usuario lo que hizo mal.


OK - esto funciona - la expresión regular en la llamada on () permite cualquier cadena siempre que no comience con un ''-''

Si no le paso un argumento a --input y hay otra opción en sentido descendente, tomará esa clave de opción como argumento para --input. (por ejemplo, --input --output). La expresión regular detecta eso y luego verifico el mensaje de error. Si el argumento que informa comienza con ''-'', se genera el mensaje de error correcto, es decir, falta un argumento. No es bonita pero parece funcionar.

Aquí está mi caso de prueba de trabajo:

#!/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


prueba esto:

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