2012-05-03 60 views
3

我有一個命令行工具,可以生成平坦的json文檔。想象一下:在命令行參數中指定nil

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

我想是這樣工作的:

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

而不是空的,我得到一個空字符串。爲了簡化問題,甚至進一步考慮這個問題:

$ 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

附: perl的行爲方式相同 – jaybuff

+0

由於ASCII中的字符數爲0的字符串是空字符串? –

+2

ASCII代碼0是NUL,C用於終止字符串數組。所以你不能沒有C字符串。我建議Ruby解釋器應該讀取一個字符串,如果它只是NUL,那麼將var設置爲零。這可能會破壞一堆東西,因爲ARGV [0]的類型不再是String。所以我不認爲我想要的是可能的。 – jaybuff

回答

3

命令行參數是總是字符串。您將需要使用標記來指示您想要治療的參數。

+0

難道它不是一個包含一個字符的字符串 - NUL字符? – jaybuff

+0

問題是NUL在C級別是不可見的,所以它在Ruby中不可見。 –

0

除了nilfalse作爲true,紅寶石可以處理所有的事情。因此,任何空字符串將評估爲true(以及00.0)。

你可以有這樣的強制行爲零:

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

這樣,任何一個空字符串會以nil參考轉變。

+0

我想能夠區分零和一個空字符串。 – jaybuff

+0

然後我看不到您的問題在哪裏。 默認情況下,你已經在區分'nil'和一個空字符串(當你傳遞一個空字符串作爲參數時,它不會被評估爲'nil'),但是你顯然想要的不是做到這一點。 準確地說**當你想要**時,空字符串被映射到'nil'和**時,你是否希望空字符串被視爲它? –

+0

包含NUL的(ruby)字符串與空字符串不同 – jaybuff

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 

會爲你的目的的工作?:)

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 

所以,你還是需要一個替身