来自 Ruby 的这个 optparse 示例的简单解释

Simple explanation for this optparse example from Ruby

require 'optparse'

options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
end.parse!

p options
p ARGV

我从 optparse 文档页面 here 找到了这个。有人可以用外行的术语解释这个例子吗?我阅读了文档,但有些部分我不明白。即end.parse!和方法parsepermute之间的区别。

end.parse! 不是某种神奇的 end 如果那是你的想法。可以这样写:

option_parser = OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
end

option_parser.parse!

正如 所解释的那样,end.parse! 正在创建一个匿名对象并对其调用 parse!。但是,您还询问了 parsepermute.

通过阅读文档,似乎有两种方法可以使用命令行参数数组:严格按顺序或按任何合法排列。 OptionParserclass上有3个相关方法:

  • order! - 按顺序解析参数,直到得到位置参数
  • permute! - 解析所有参数,跳过位置参数
  • parse! - 如果设置了 POSIXLY_CORRECT 环境变量,则调用 order!,否则调用 permute!

这三个都将未使用的参数留在 ARGV 或您传入的任何数组中,并返回未使用的参数。还有三个等效的方法,去掉了感叹号。这些在数组的副本上工作,因此原始数组没有改变。

这是您在 example.rb 中的原始脚本,在位置参数前后使用可选参数调用:

$ ruby example.rb -v foo bar
{:verbose=>true}
["foo", "bar"]
$ ruby example.rb foo -v bar
{:verbose=>true}
["foo", "bar"]
$ POSIXLY_CORRECT=1 ruby example.rb foo -v bar
{}
["foo", "-v", "bar"]
$

现在,我将 end.parse! 更改为 end.order!:

$ ruby example.rb -v foo bar
{:verbose=>true}
["foo", "bar"]
$ ruby example.rb foo -v bar
{}
["foo", "-v", "bar"]
$

将其更改为 end.permute!:

$ ruby example.rb -v foo bar
{:verbose=>true}
["foo", "bar"]
$ ruby example.rb foo -v bar
{:verbose=>true}
["foo", "bar"]
$

这也会影响脚本何时会抱怨未知选项。您的脚本只有 -v 选项,没有 -x 选项,因此如果它尝试解析 -x,它会报错。如果你不想让它抱怨,你有几个选择:

  • 捕获脚本中的错误并进行处理。
  • -x放在位置参数之后,并按顺序解析参数。
  • -- 放在命令行 -x 之前的某处。 -- 告诉解析器停止解析选项并将所有其余部分作为位置参数传递。

这是您的原始脚本的另一个示例:

$ ruby example.rb -v foo -x bar
Traceback (most recent call last):
example.rb:10:in `<main>': invalid option: x (OptionParser::InvalidOption)
example.rb:10:in `<main>': invalid option: -x (OptionParser::InvalidOption)
$ POSIXLY_CORRECT=1 ruby example.rb -v foo -x bar
{:verbose=>true}
["foo", "-x", "bar"]
$ ruby example.rb -v -- -x foo bar
{:verbose=>true}
["-x", "foo", "bar"]
$