如何在散列中指定参数

How to specify params in a hash

我有一本用于安装 JRuby 的 Community Chef 食谱。我在指定要安装的 Gem 版本时遇到问题。我已经尝试了所有我能想到的散列、键、字符串等的组合。

以下是代码的相关部分:

default[:jruby][:gems] = ["some-gem", "another-one"]

是的,这是一个字符串数组,但散列数组应该是可能的。

这是由以下片段读取的:

node[:jruby][:gems].each do |gem|
  Chef::Log.info "Installing Jruby Gem #{gem}"
  if gem.is_a? Hash
    name = gem.delete(:name)
  else
    name = gem
    gem = nil
  end
  jruby_gem name, gem || {}
end

并最终落入此定义之手:

define :jruby_gem, :source => nil, :version => nil do
  gem_package params[:name] do
    gem_binary "#{node[:jruby][:install_path]}/bin/gem"
    source params[:source] if params[:source]
    version params[:version] if params[:version]
  end
end

给定该代码,什么样的哈希将填充生成的定义中的 :name:version 值?

我尝试过的东西在以下领域...

[
  {:name => "some-gem", :version => "0.1.2"},
  {:name => "another-one"} # I don't need to constrain every Gem to a version
]

编辑:

所以感谢完全正确的 Ruby-esque 响应,但实际上我在转向 SO 之前确实尝试了一些变体的哈希数组方法。疲劳使我打错了最初出现在我问题中的结构。

我看到的问题似乎与 Chef 和您在上面看到的定义有关。我得到的错误如下...

Node attributes are read-only when you do not specify which precedence level to set. To set an attribute use code like `node.default["key"] = "value"'

  Cookbook Trace:
  ---------------
    /var/chef/cache/cookbooks/jruby/recipes/default.rb:48:in `block in from_file'
    /var/chef/cache/cookbooks/jruby/recipes/default.rb:45:in `each'
    /var/chef/cache/cookbooks/jruby/recipes/default.rb:45:in `from_file'

  Relevant File Content:
  ----------------------
  /var/chef/cache/cookbooks/jruby/recipes/default.rb:

   41:    notifies :create_if_missing, "file[/etc/profile.d/jruby.sh]"
   42:  end
   43:
   44:  # install all gems defined in the module
   45:  node[:jruby][:gems].each do |gem|
   46:    Chef::Log.info "Installing Jruby Gem #{gem}"
   47:    if gem.is_a? Hash
   48>>     name = gem.delete(:name)
   49:    else
   50:      name = gem
   51:      gem = nil
   52:    end
   53:    jruby_gem name, gem || {}
   54:  end
   55:

尝试:

[
  {:name => "some-gem", :version => "0.1.2"},
  {:name => "another-one"} # I don't need to constrain every Gem to a version
]

注意内部数据结构是用花括号定义的,而不是方括号。

  • [] 组成一个数组
  • {} 的哈希

您正在创建一个数组的数组,但您真正想要的是一个哈希数组。

编辑

文档似乎表明您可以按照以下方式尝试:

default[:jruby].set[:gems] = ["some-gem", "another-one"]

这是我从以下内容的简短浏览中得到的: https://www.chef.io/blog/2013/02/05/chef-11-in-depth-attributes-changes/

不幸的是,这里的问题不是你的属性而是你的实际食谱。

您(和我,今天!)正在使用的 jruby cookbook 的实现与 Chef 11+ 不兼容。看到这个 link:

https://www.chef.io/blog/2013/02/05/chef-11-in-depth-attributes-changes/

Now you must specify which precedence level you want to write to when setting attributes; accessing attributes on the node directly is only for reading.

此处出错的行正是这样做的:

if gem.is_a? Hash
  name = gem.delete(:name) <- This is modifying node.jruby.gems.some_gem!

因此,如果你想使用它,你必须采取以下几种方法之一:

  1. fork jruby cookbook 并修复它。它非常古老,none 现有的直接分支支持 Chef 11,所以如果你想接管它,你可以变得像一个小神。
  2. 完全使用单独的说明书进行 gem 安装(这是我们到目前为止一直在做的事情)。
  3. 创建一个包含 jruby cookbook without setting jruby.gems 的 wrapper cookbook,并添加一个属性和你自己的 Ruby 块来设置'right' 方式。

一个例子是:

my_gems = node['jruby']['my_gems'].dup

my_gems.each do |gem|
  if gem.is_a? Hash
    name = gem.delete('name')
  else
    name = gem
    gem = nil
  end
  jruby_gem name, gem || {}
end

如果进行适当的调整,这实际上会起作用。使用这个确切块的示例厨师客户端输出将是:

> Recipe: mycompany-jruby::default 
> * gem_package[some-package] action install 
> - install version #.#.# of package some-package