Ruby 如何从命令行传递哈希?

Ruby 如何从命令行传递哈希?,ruby,Ruby,我有一个包含哈希的ruby脚本 例如: animal_sound = { 'dog' => 'bark', 'cat' => 'meow' } myscript.rb --addsound snake:hiss 我想添加'snake'=>'hiss' 例如: myscript.rb --addsound "'snake' => 'hiss'" animal_sound.merge! 'snake' => 'hiss' => {"dog"=>"bark"

我有一个包含哈希的ruby脚本

例如:

animal_sound = { 'dog' => 'bark', 'cat' => 'meow' }
myscript.rb --addsound snake:hiss
我想添加'snake'=>'hiss'

例如:

myscript.rb --addsound "'snake' => 'hiss'"
animal_sound.merge! 'snake' => 'hiss' 
=> {"dog"=>"bark", "cat"=>"meow", "snake"=>"hiss"}
然后在我的脚本中,将其添加到animal_sound中

例如:

myscript.rb --addsound "'snake' => 'hiss'"
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>'
最终代码:

#!/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"}
我永远无法让合并工作。
每个帖子都很有帮助。谢谢

关于您的错误

注意这行
if options[:add_sound]
。如果为真,则基本上计算为
。您得到错误是因为您正在将
newsound
设置为
true
,并试图将布尔值合并到哈希中。据我所知,
.merge
的工作原理如下:
hash1.merge(hash2)

传递命令行参数

与其传递参数“snake”=>“hiss”
,我建议将其设置为逗号分隔的列表,如下所示:
“snake,hiss”
。从这里开始,在
if options[:add_sound]
块中,可以使用逗号作为拆分器将字符串拆分为数组。最后,与使用
.merge
不同,您可以像通常对Ruby中的任何哈希一样添加key:value<代码>动物声音[arr[0]]=arr[1]

请注意,此方法在使用单个键:值对时效果最佳。我相信您可以提交多个对,但您需要(通过此方法)通过一个附加字符(如
/
可能)拆分成更多数组。

p.option:addsound,“addsound”

^这使其成为一个标志(正确或错误)

您需要将其转换为一个开关,其值是下一个参数:

p.选项:添加声音,“添加声音”,默认值:

^这使它成为一个开关,字符串值将被分配给
选项[:addsound]

newsound=options[:addsound]

^这里需要删除下划线并将字符串解析为哈希。 Eval是邪恶的。 例如,您可以在
'=>'
上拆分它,然后忘记引用:

newsound = [ options[:addsound].split(' => ') ].to_h #and then merge it
(像这样传递参数--addsound snake:hiss,然后在
':'
而不是
'=>'
上拆分是另一个好选项。)

^在
'=>'
上拆分应该会产生一个两成员数组。在这里,我将其放入另一个数组(两个成员数组的数组可转换为散列)以使其转换为散列

或者完全不合并和构建另一个哈希:

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

最好将CLI接口与底层实现分离。事实上,将来您可能会决定将脚本从Ruby切换到另一种语言,并且您并不真正想要更改代码的调用方式

例如,我的建议是传递一个序列化的值

myscript.rb --addsound snake:hiss
在代码中,只需分解内容并将其合并

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

传递长的命令行参数通常是一个糟糕的计划。为什么不像其他许多实用程序那样,有一个参数来指定文件或从STDIN读取?YAML和JSON都非常易于阅读和编写,即使是手工操作,并且非常清晰地映射到原生Ruby结构。使用
YAML.load
JSON.load
导入它们。感谢您的提示和帮助。我在你的代码中看到了逻辑,但我得到了以下错误:
未定义的方法'split'for true:TrueClass(NoMethodError)
我在谷歌上搜索了一个答案,但没有找到我能理解和应用的答案。有什么见解吗?我看到onebree的回答告诉我,
options[:addsound]
的评估结果是正确的。这就是问题所在。谢谢你的回复。与Simone Carletti的代码一样,我得到了以下错误:
未定义的方法'split'for true:TrueClass(NoMethodError)
这就是为什么您应该选择我的响应:我对它进行了编辑,希望它更容易理解。阅读我答案的顶部,或为TL;DR:“您需要将
默认值
部分添加到
p.option
行,将其从标志(布尔值)转换为开关(值是下一个参数)。好的……我使用您的
animal,sound=options[:addsound].split('=>');animal_sound[animal]=声音
谢谢!事实上,我确实试着提高投票率。显然我还没有足够的“声望点数”。