3

我有一个生成平面 json 文档的命令行工具。想象一下:

$ ruby gen-json.rb --foo bar --baz qux
{
    "foo": "bar"
    "baz": "qux"
}

我想要的是这个工作:

$ ruby gen-json.rb --foo $'\0' --baz qux
{
    "foo": null,
    "baz": "qux"
}

而不是 null 我得到一个空字符串。为了简化问题,进一步考虑:

$ cat nil-args.rb
puts "argv[0] is nil" if ARGV[0].nil?
puts "argv[0] is an empty string" if ARGV[0] == ""
puts "argv[1] is nil" if ARGV[1].nil?

我想像这样运行它并得到这个输出:

$ ruby nil-args.rb $'\0' foo
argv[0] is nil

但相反我得到

argv[0] is an empty string

我怀疑这(可以说)是 ruby​​ 解释器中的一个错误。它将 argv[0] 视为一个以 null 结尾的 C 字符串。

4

4 回答 4

3

命令行参数始终是字符串。您将需要使用哨兵来指示您要以其他方式处理的论点。

于 2012-05-03T20:31:44.520 回答
1

我很确定你真的不能按照你的提议去做。这是您使用的 shell 的一个基本限制。您只能将字符串参数传递给脚本。

它已经在评论中提到过,但是您尝试使用 \0 方法获得的输出非常有意义。空终止符在技术上是一个空字符串。

还要考虑访问尚未定义的数组的任何元素将始终为零。

a = [1, 2, 3]
a[10].nil?
#=> true

但是,一个可能的解决方案是让您的程序像这样工作:

$ ruby gen-json.rb --foo --baz qux
{
    "foo": null,
    "baz": "qux"
}

因此,当您有一个双减号参数后跟另一个双减号参数时,您推断第一个为空。不过,您将需要编写自己的命令行选项解析器来实现这一点。

这是一个非常简单的示例脚本,它似乎可以工作(但可能存在边缘情况和其他问题):

require 'pp'

json = {}

ARGV.each_cons(2) do |key, value|
  next unless key.start_with? '--'
  json[key] = value.start_with?('--') ? nil : value
end

pp json

这对你的目的有用吗?:)

于 2012-05-04T00:35:52.667 回答
0

你将不得不决定一个特殊的字符来表示零。我建议"\0"(双引号确保传入文字字符串反斜杠零)。然后,您可以在以下位置使用特殊类型转换器OptionParser

require 'optparse'
require 'json'

values = {}
parser = OptionParser.new do |opts|
  opts.on("--foo VAL",:nulldetect) { |val| values[:foo] = val }
  opts.on("--bar VAL",:nulldetect) { |val| values[:foo] = val }

  opts.accept(:nulldetect) do |string|
    if string == '\0'
      nil
    else
      string
    end
  end
end

parser.parse!

puts values.to_json

显然,这要求您明确说明您接受的标志,但是如果您想接受任何标志,您当然可以手动插入if语句以检查"\0"

作为旁注,您可以让标志是可选的,但您会将空字符串传递给块,例如

opts.on("--foo [VAL]") do |val|
  # if --foo is passed w/out args, val is empty string
end

所以,你仍然需要一个替身

于 2012-05-09T12:25:17.427 回答
0

Ruby 将除nil和之外的所有内容都false视为true. 因此,任何空字符串都将评估为真(以及0or 0.0)。

您可以通过以下方式强制执行 nil 行为:

ARGV.map! do |arg|
  if arg.empty?
    nil
  else
    arg
  end
end

这样,任何空字符串都将转换为对nil.

于 2012-05-03T20:59:33.990 回答