厨师长11:有没有办法把属性转换成ruby哈希?

厨师长11:有没有办法把属性转换成ruby哈希?,ruby,hash,attributes,chef-infra,Ruby,Hash,Attributes,Chef Infra,我正在厨师属性中为我的服务生成配置。然而,在某个时候,我需要将属性mash转换成一个简单的ruby哈希。这在厨师长10中很好地发挥了作用: node.myapp.config.to_hash 然而,从厨师长11开始,这是行不通的。只有属性的顶层被转换为散列,然后嵌套的值仍然是不可变的mash对象。修改它们会导致如下错误: Chef::异常::ImmutableAttributeModification ----------------------------------------------

我正在厨师属性中为我的服务生成配置。然而,在某个时候,我需要将属性mash转换成一个简单的ruby哈希。这在厨师长10中很好地发挥了作用:

node.myapp.config.to_hash
然而,从厨师长11开始,这是行不通的。只有属性的顶层被转换为散列,然后嵌套的值仍然是不可变的mash对象。修改它们会导致如下错误:

Chef::异常::ImmutableAttributeModification ------------------------------------------------如果未指定要设置的优先级,则节点属性为只读。到 使用类似“node.default[“key”]=“value””的代码设置属性

我已经尝试了很多方法来解决这个问题,但都不起作用:

node.myapp.config.dup.to_hash
JSON.parse(node.myapp.config.to_json)
json解析黑客看起来应该很有效,结果是:

JSON::ParserError
unexpected token at '"#<Chef::Node::Attribute:0x000000020eee88>"'
JSON::parserror
“#”处出现意外标记

除了在每本食谱中都包含嵌套的解析函数之外,还有什么切实可靠的方法可以将属性转换为简单、普通、好的ruby哈希吗?

在这里和opscode chef邮件列表中都没有答案之后,我最终使用了以下破解方法:

class Chef
  class Node
   class ImmutableMash
      def to_hash
        h = {}
        self.each do |k,v|
          if v.respond_to?('to_hash')
            h[k] = v.to_hash
          else
            h[k] = v
          end
        end
        return h
      end
    end
  end
end
我把它放在我的食谱里;现在我可以在chef 10和chef 11中使用attribute.to_散列(它已经正常工作,并且不受这个猴子补丁的影响)。我还向opscode报告了一个bug:

如果你不想对你的厨师进行恶作剧,就直说这个问题:


更新:猴子补丁票被

标记为关闭。上面的答案有点不必要。您可以这样做:

json = node[:whatever][:whatever].to_hash.to_json
JSON.parse(json)

我也有同样的问题,经过多次黑客攻击后,我想到了这个:

json_string = node[:attr_tree].inspect.gsub(/\=\>/,':')
my_hash = JSON.parse(json_string, {:symbolize_names => true})

inspect完成了其他建议方法中缺少的深度解析,我最终得到了一个可以根据需要修改和传递的散列。

我希望我加入该方不会太晚,但将节点对象与空散列合并为我做到了:

chef (12.6.0)> {}.merge(node).class
 => Hash

这一问题已经解决了很长一段时间:

[1] pry(main)> require 'chef/node'
=> true
[2] pry(main)> node = Chef::Node.new
[....]
[3] pry(main)> node.default["fizz"]["buzz"] = { "foo" => [ { "bar" => "baz" } ] }
=> {"foo"=>[{"bar"=>"baz"}]}
[4] pry(main)> buzz = node["fizz"]["buzz"].to_hash
=> {"foo"=>[{"bar"=>"baz"}]}
[5] pry(main)> buzz.class
=> Hash
[6] pry(main)> buzz["foo"].class
=> Array
[7] pry(main)> buzz["foo"][0].class
=> Hash
[8] pry(main)>

可能是在Chef 12.x或Chef 13.x前后修复的,在Chef 15.x/16.x/17.x中肯定不再是问题了,我不需要它——我可以随时退出!但说真的,我正在用许多不同的属性构建一个配置文件,在将它们写入配置文件之前,我需要修改它们。将属性转换成散列,对其进行变异,然后使用散列,这真的很有帮助;我还没有克服嵌套数组的问题,但这肯定是个问题。厨师问题已经解决了。(我使用的是12.4.1版)希望我不会太晚,但我的回答可能会有所帮助#inject将更倾向于重建哈希。现在是2021年,任何人都不应该在回答中使用此monkeypatch或任何其他建议的解决方法。现在就行了。看起来它是在2015年修复的。这不是真的;由于
to_hash
是浅层的,因此最终将
ImmutableMash
对象作为值。to_json函数不知道如何处理此类对象,因此会呕吐。这就是这个问题的全部要点。对于一行程序,
JSON.parse(hash.to\u JSON,symbol\u names:true)
。相当邪恶,但比更复杂的解决方案更容易维护。如果节点散列中有ruby对象,则会失败。