2015-06-15 35 views
2

我有一個紅寶石腳本,有一個散列。如何從命令行傳遞散列?

例子:

animal_sound = { 'dog' => 'bark', 'cat' => 'meow' } 

我要添加 '蛇'=> '嘶嘶'

例子:

myscript.rb --addsound "'snake' => 'hiss'" 

然後在我的劇本已經是將其添加到animal_sound。

例子:

animal_sound.merge! 'snake' => 'hiss' 
=> {"dog"=>"bark", "cat"=>"meow", "snake"=>"hiss"} 

有沒有辦法做到這一點?

這裏是整個腳本:

#!/usr/bin/env ruby 
require 'rubygems' 
require 'micro-optparse' 

options = Parser.new do |p| 

     p.option :addsound, "add sound" 
end.process! 

animal_sound = { 'dog' => 'bark', 'cat' => 'meow' } 

if options[:add_sound] 
    newsound = options[:add_sound] 
    animal_sound.merge! newsound 
end 

puts animal_sound 

當我運行我的腳本,我得到:

$ bin/myscript.rb --addsound "'snake' => 'hiss'" 
bin/myscript.rb:14:in `merge!': can't convert true into Hash (TypeError) 
    from bin/myscript.rb:14:in `<main>' 

解決: 使用PSkocik的解決方案,我拿到劇本的使用工作animal, sound = options[:addsound].split(' => '); animal_sound[animal] = sound

我還使用Simone Carletti的想法來簡化CLI命令。僅供參考,如果我想通過哈希格式,如myscript.rb --addsound "'snake' => 'hiss'"也可以。當然,拆分必須改回split(' => ')。我喜歡使用:的更簡單的CLI。

例子:

myscript.rb --addsound snake:hiss 

終極密碼:

#!/usr/bin/env ruby 
require 'rubygems' 
require 'micro-optparse' 

options = Parser.new do |p| 

     p.option :addsound, "add sound", default: "" 
end.process! 

animal_sound = { 'dog' => 'bark', 'cat' => 'meow' } 

if options[:addsound] 
    animal, sound = options[:addsound].split(':') 
    animal_sound[animal] = sound 
end 

puts animal_sound 

命令行:

$ bin/myscript.rb --addsound snake:hiss 
{"dog"=>"bark", "cat"=>"meow", "snake"=>"hiss"} 

我無法讓自己的合併工作。 每篇文章都很有幫助。謝謝。

+0

傳遞很長的命令行參數通常是一個糟糕的計劃。爲什麼不像許多其他實用程序那樣有指定文件的參數,或者從STDIN讀取? YAML和JSON都非常易於讀寫,即使是手工編寫,也可以非常乾淨地映射到本地Ruby結構。使用'YAML.load'或'JSON.load'來導入它們。 – tadman

回答

0

p.option :addsound, "add sound"

^這使得它的標誌(true或false)

你想要的是使之成爲一個開關,它的值是一個參數:

p.option :addsound, "add sound", default: ""

^這使其成爲開關,字符串值將被分配到options[:addsound]

newsound = options[:addsound]

^在這裏,您需要刪除下劃線並將字符串解析爲散列。 Eval是邪惡的。 例如,你可以在' => '拆分它,忘掉報價:(傳遞參數,像這樣--addsound snake:hiss,然後':'而不是' => '分裂是另一個不錯的選擇)

newsound = [ options[:addsound].split(' => ') ].to_h #and then merge it 

^分割上' => '應該產生一個雙成員數組。在這裏,我把它放入另一個數組(兩個成員數組的數組可以轉換成哈希),使它可以轉換成哈希。

或者你不合並,構建另一個哈希完全做到:

animal, sound = options[:addsound].split(' => ') 
animal_sound[animal] = sound 
+0

感謝您的回覆。與Simone Carletti的代碼一樣,我得到以下錯誤:'未定義的方法\'分裂'爲true:TrueClass(NoMethodError)' – ajnabi

+0

這就是爲什麼你應該選擇我的迴應。 :D – PSkocik

+0

我編輯過它,希望更容易理解。閱讀我的答案或TL的頂部; DR:「您需要將'default'部分添加到'p.option'行以將其從標誌(布爾值)變爲開關(值是下一個參數) – PSkocik

0

在問候你的錯誤

通知行if options[:add_sound]。基本上評估爲if true。由於您將newsound設置爲true,並且嘗試將布爾合併到哈希中,您正在收到錯誤。據我所知,.merge只能這樣工作:hash1.merge(hash2)

將命令行參數

而不是傳遞參數"'snake' => 'hiss'",我建議使之成爲一個逗號劃定名單,像這樣:"snake,hiss"。從那裏,在if options[:add_sound]塊中,可以使用逗號作爲分隔符將字符串拆分爲數組。最後,與使用.merge不同,您可以像在Ruby中通常那樣添加key:值。 animal_sound[arr[0]] = arr[1]

請注意,這種方法最適合單鍵:值對。我相信你可以提交多對,但你需要(通過這種方法)通過一個額外的字符分割成更多的數組(如/也許)。

1

這是一個好主意,讓從底層實現分離的CLI界面。事實上,您可能決定將來將腳本從Ruby切換到另一種語言,並且您並不想改變代碼的調用方式。

我的建議是通過序列化的值,例如

myscript.rb --addsound snake:hiss 

在代碼中,簡單地分解的內容和合並。

if options[:add_sound] 
    animal, sound = options[:add_sound].split(":") 
    animal_sound.merge!(animal => sound) 
end 
+1

好抓@PSkocik –

+0

感謝您的迅速和有益的迴應。我在你的代碼中看到了邏輯,但是我收到以下錯誤:'未定義的方法\'分裂'爲true:TrueClass(NoMethodError)'我已經搜索了一個答案,但沒有答案,我可以理解和應用。任何見解? – ajnabi

+1

我看到onebree的答案顯示我'options [:addsound]' 正在評估爲true。那就是問題所在。 – ajnabi