厨师从配方中的另一个命名空间重新分配属性会导致4个级别数组

时间:2017-12-01 06:15:55

标签: ruby chef

我从食谱中依赖社区领事食谱  因为我有服务器和客户端模式的领事,我想分隔名称空间 在这种情况下,我可以在我的食谱中使用以下构造:

node.default['consul']['config']['server'] = node['consul-server']['config']['server'] if node['consul-server']['config']['server']
node.default['consul']['config']['ui'] = node['consul-server']['config']['ui'] if node['consul-server']['config']['ui']
node.default['consul']['config']['ports']['http'] = node['consul-server']['config']['ports']['http'] if node['consul-server']['config']['ports']['http']
node.default['consul']['config']['ports']['https'] = node['consul-server']['config']['ports']['https'] if node['consul-server']['config']['ports']['https']

按预期方式前两行,但最后两行产生以下错误:

   ================================================================================
   Recipe Compile Error in /tmp/kitchen/cache/cookbooks/eax-consul-cluster/recipes/default.rb
   ================================================================================

   NoMethodError
   -------------
   undefined method `[]' for nil:NilClass

为什么这种情况发生在相同的构造上,它们之间的唯一区别是阵列更深一层?

3 个答案:

答案 0 :(得分:0)

这是因为在某种程度上,[]方法会返回nil。例如,假设node.default['consul']返回nil,那么node.default['consul']['config']会引发您看到的错误。

如果node.default是散列哈希值的哈希值,那么对于读取值,您可以尝试Hash#dig,例如:

h = {'a' => {'b' => 'c'} }
h.dig('a', 'b')  #=> c
h.dig('x', 'y')  #=> nil

要设置值,您必须确保已设置父级别。

答案 1 :(得分:0)

将其切换为if if node.read('consul-server', 'config', 'ports', 'http')。这会以与nil类似的方式自动检查干预密钥中的Hash#dig

答案 2 :(得分:0)

另一方面,由于您的命名约定恰好低于第一级,因此合并它们似乎更合适并避免所有条件,深度检查等。

例如:

# Essentially a railsesque #deep_merge!
merge_proc = Proc.new do |_k,old,new|
   if old.is_a?(Hash) && new.is_a?(Hash)
     old.merge(new,&merge_proc)
   else
     new
   end
end

node.default['consul'].merge!(node['consul-server'], &merge_proc)

Hash#merge!因为MashHash的主厨的子类)仍然是Hash