1

我正在努力使 CLI ruby​​ 工具更加健壮,并对工具的 CLI 组件进行错误处理。我正在使用 optparse 并且文档显示标志可以具有强制和可选参数。我只是看到一些奇怪/烦人的行为。

对于标志的参数是强制性的(使用等号)的一种情况,我试图让它失败但它仍然有效,它只是抓住了下一个标志('-u')作为该标志的参数,而不是导致其余的解析以不太理想的方式失败。我想这还不错,因为'-....' 可能是有效的,但是因为我使用等号来设置开关的值,所以我假设'space' 样式分配不起作用.

op = OptionParser.new do |x|
  x.on("-u", "--user=USER", "user flag") do |user|  options[:user] = user end
  x.on("-d", "--db=DATABASE", "database flag") do |db|  options[:db] = db end
end

如果我通过以下 CLI 输入:

myprog -u -d mydb positionalarg

然后在解析过程中,它将 options[:user] 设置为 -d,并且 options[:db] 为 nil,因为它没有遇到并且有 2 个位置参数而不是 1。显然这是一个用户错误,但我想抓住它并显示一个真正的错误,而不仅仅是返回一个错误(在工具的情况下),应该从以下列表中只传递一个位置参数:......真正的问题是 -u 标志缺少它的必需参数所以鉴于 optparse 有一个 ArgumentMissing 异常,我假设这就是 .parse!会扔。

但是,对于具有可选参数(使用等号)的标志,如果您这样做,它实际上是可选的:-a -b=something 但这不起作用:-a something -b=somethingelse。强制该值的唯一方法是使用等号:-a=something -b=somethingelse。鉴于先前带有等号的强制性参数的行为,我认为不会是这种情况。例子:

op = OptionParser.new do |x|
  x.on("-u", "--user[=USER]", "user flag") do |user|  options[:user] = user unless user.nil? end
  x.on("-d", "--db=DATABASE", "database flag") do |db|  options[:db] = db end
end

所以通过解析:

myprog -u -d mydb positionalarg

那么 options[:user] 是 nil (ok) 并且 options[:db] 是 mydb 并且剩下一个位置参数。

通过此解析:

myprog -u myuser -d mydb positionalarg

然后 options[:user] 为 nil (不正常), options[:db] 为 mydb 并且剩下两个位置参数:myuser 和 positionalarg (不正常)。我的错误检查再次与位置 arg 计数有关。似乎如果使用强制标志参数,如果空格和 = 都有效,那么对于可选标志参数,它应该是相同的,但事实并非如此。

另一个问题是带有可选参数(使用空格)的标志很好,除非它们位于命令的末尾,然后将位置参数作为标志参数。

例子:

op = OptionParser.new do |x|
  x.on("-u", "--user [USER]", "user flag") do |user|  options[:user] = user unless user.nil? end
  x.on("-d", "--db=DATABASE", "database flag") do |db|  options[:db] = db end
end

所以通过解析:

myprog -d mydb -u positionalarg

然后 options[:db] 是 mydb (ok) 并且 options[:user] 是 positionalarg 并且没有剩余的位置参数。请注意, -d mydb 与空间一起使用,即使我用等号指定它也是如此。

似乎很多人通过执行 optparse .parse 来执行 ruby​​ CLI!并将 ARGV 中的剩余条目作为位置参数,但我认为在将 ARGV 传递给 optparse 之前先将位置参数从远端剥离可能会更好(除非在位置参数数量可变的情况下失败。

我相信我可以围绕所有这些进行编程,但如果我不知道在 optparse 中有方法可以做到这一点,我不希望这样做。

也许最好的办法是避免带有可选参数的标志:),但任何建议都会受到赞赏。

4

1 回答 1

1

为什么=在选项的定义中使用?文档中的示例不使用它们。

如果我将此 MWE 定义为test.rb

require 'optparse'

puts "\n=Call with #{ARGV.inspect}"
options = {}

op = OptionParser.new do |x|
  x.on("-u", "--user [USER]", "user flag") do |user|  options[:user] = user unless user.nil? end
  x.on("-d", "--db DATABASE", "database flag") do |db|  options[:db] = db end
end

op.parse!

puts "Options: #{options.inspect}"
puts "ARGV     #{ARGV.inspect}"

并用这个 batfile 调用它(Windows,删除@echo offLinux 的):

@echo off
test.rb -h
test.rb -u -d mydb positionalarg
test.rb -u myuser -d mydb positionalarg
test.rb --user=myuser -d mydb positionalarg

我得到:

=Call with ["-h"]
Usage: test [options]
    -u, --user [USER]                user flag
    -d, --db DATABASE                database flag

=Call with ["-u", "-d", "mydb", "positionalarg"]
Options: {:db=>"mydb"}
ARGV     ["positionalarg"]

=Call with ["-u", "myuser", "-d", "mydb", "positionalarg"]
Options: {:user=>"myuser", :db=>"mydb"}
ARGV     ["positionalarg"]

=Call with ["--user=myuser", "-d", "mydb", "positionalarg"]
Options: {:user=>"myuser", :db=>"mydb"}
ARGV     ["positionalarg"]
于 2014-01-04T20:36:11.057 回答