我有一个命令行工具,可以生成一个扁平的json doc。想象一下:
$ 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]视为一个空字符串终止的C字符串。
答案 0 :(得分:3)
命令行参数始终字符串。您需要使用哨兵来表示您想要处理的参数。
答案 1 :(得分:1)
我很确定你字面不能做你提出的建议。这是您正在使用的shell的基本限制。您只能将字符串参数传递给脚本。
在评论中已经提到过,但你尝试使用\ 0方法得到的输出非常有意义。 null终止符在技术上是一个空字符串。
还要考虑访问尚未定义的数组的任何元素将始终为nil。
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
这是否适用于您的目的? :)
答案 2 :(得分:0)
Ruby将除nil
和false
之外的所有内容视为true
。因此,任何空字符串都将评估为true(以及0
或0.0
)。
你可以通过这样的方式强制零行为:
ARGV.map! do |arg|
if arg.empty?
nil
else
arg
end
end
这样,任何空字符串都将在对nil
的引用中进行转换。
答案 3 :(得分: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
所以,你还需要一个替补