【问题标题】:How do I handle a missing mandatory argument in Ruby OptionParser?如何处理 Ruby OptionParser 中缺少的强制参数?
【发布时间】:2011-02-02 13:58:53
【问题描述】:

在 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

【问题讨论】:

    标签: ruby command-line optionparser


    【解决方案1】:

    你想做的不是一个好主意。如果你真的有一个名为“--output”的文件怎么办?这是 Unix 上完全有效的文件名。每个 Unix 程序的选项解析都按照 ruby​​ 的方式工作,所以你不应该改变它,因为那样你的程序将与其他程序任意不同,这会令人困惑并违反“最小意外原则”。

    真正的问题是:你为什么会遇到这个问题?也许您正在从另一个程序运行您的程序,并且父程序提供了一个空白文件名作为 --input 的参数,这使得它看到 --output 作为 --input 的参数。您可以通过始终引用您在命令行上传递的文件名来解决此问题:

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

    那么 --input 会是空白的,这很容易检测到。

    另外请注意,如果 --input 设置为 --output(并且 --output 不是真实文件),您可以尝试打开 --input 文件。如果失败,打印如下消息:

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

    这应该让用户清楚他们做错了什么。

    【讨论】:

      【解决方案2】:

      试试这个:

      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
      

      【讨论】:

        【解决方案3】:

        在这种情况下,强制的--output 选项缺失,所以在调用parse! 后执行此操作:

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

        【讨论】:

        • 是的......这解决了测试用例,但我真的希望我可以在它所属的 OptionParser.new 块中做到这一点。你应该能够在 on() 调用中包含一个 /pattern/ ,任何参数都必须匹配 - 但我还没有让这个工作。谢谢!
        【解决方案4】:

        好的 - 这有效 - on() 调用中的正则表达式允许任何字符串,只要它不以'-'开头

        如果我没有将参数传递给 --input 并且下游有另一个选项,那么它将将该选项键作为 --input 的参数。 (例如——输入——输出)。正则表达式捕获了它,然后我检查了错误消息。如果它报告的参数以“-”开头,我会输出正确的错误消息,即缺少参数。不漂亮,但它似乎工作。

        这是我的工作测试用例:

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

        【讨论】:

          猜你喜欢
          • 2016-01-01
          • 1970-01-01
          • 2012-06-28
          • 2023-03-26
          • 1970-01-01
          • 1970-01-01
          • 2022-01-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多