如何使Ruby JSON解析器忽略json_class?

时间:2011-02-03 01:20:07

标签: ruby json chef

我有一个序列化的JSON字符串(实际上是厨师角色定义)并且它有一个json_class键,使得ruby JSON解析器试图强制它成为Chef :: Role对象。如何让解析器忽略这个键,只是简单地反序列化为普通的Hash?

4 个答案:

答案 0 :(得分:14)

我遇到了同样的问题,通过阅读JSON gem的源代码找到了答案 - 在尝试解析之前,只需取消设置JSON.create_id:

JSON.create_id = nil
JSON.parse('{ "json_class": "Chef::Role" }').class => Hash

编辑:请注意,由于gem的版本1.7(1.8.0是我输入此更新的最新版本),因此不再需要上述hack。 JSON#parse现在忽略json_class,而JSON#load应该用于取消编组转储对象。

答案 1 :(得分:6)

“json_class”键用于指示json应该取消封送的对象。它由JSON.dump添加。在更新版本的JSON中,JSON.parse将忽略“json_class”,解除对Hash的编组。虽然JSON.load将对指定的对象进行解组(在您的情况下,为Chef :: Role)。

JSON.parse('{ "json_class": "Chef::Role" }').class => Hash
JSON.load('{ "json_class": "Chef::Role" }').class => Chef::Role

答案 2 :(得分:0)

可以在解析之前对字符串执行gsub,并将该特定键更改为其他内容。

如何在前后显示JSON样本?

答案 3 :(得分:0)

根据文档,Mark Reed的解决方案当然应该有效。但是当我在Vagrantfile中尝试这个时:

JSON.create_id = nil
vagrant_json = JSON.parse(Pathname(__FILE__).dirname.join('nodes', "#{node_name}.json").read)

config.vm.provision :chef_solo do |chef|
  chef.cookbooks_path = ["cookbooks", "site-cookbooks"]
  chef.roles_path = "roles"
  chef.data_bags_path = "data_bags"
  chef.node_name = node_name
  chef.run_list = vagrant_json.delete('run_list')
  chef.json = vagrant_json
end

vagrant_json.class是一个Hash,但只要node.json文件包含“json_class”:“Chef :: Node”条目,它仍会在内部保留json_class值。然后当使用散列在最后一行中设置chef.json值时,它再次使用json类进行解释(奇怪的是,结果是一个空的运行列表。)

这是有效的。同样的想法,但一点点技巧:

vagrant_json = JSON.parse(Pathname(__FILE__).dirname.join('nodes', "#{node_name}.json").read)
vagrant_json['json_class'] = nil  # <== This worked

config.vm.provision :chef_solo do |chef|
  chef.cookbooks_path = ["cookbooks", "site-cookbooks"]
  chef.roles_path = "roles"
  chef.data_bags_path = "data_bags"
  chef.node_name = node_name
  chef.run_list = vagrant_json.delete('run_list')
  chef.json = vagrant_json
end

此代码用于设置来自Chef节点文件的json属性和运行列表,包含或不包含“json_class”:“Chef :: Node”条目。

总之,前面的答案在从JSON.parse获取哈希方面似乎完全正确,但是如果你不从该哈希中删除json_class对,那么以后仍然会有麻烦,就像在这种情况下一样。