我有一个序列化的 JSON 字符串(实际上是厨师角色定义),它有一个 json_class 键,使 ruby JSON 解析器尝试强制它成为 Chef::Role 对象。我怎样才能让解析器忽略这个键,只是简单地反序列化成一个普通的哈希?
4 回答
我刚刚遇到了同样的问题,并通过阅读 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
应该用于解组转储对象。
“json_class”键用于指示 json 应该作为什么对象取消编组。它由 JSON.dump 添加。在更新的 JSON 版本中,JSON.parse
将忽略“json_class”,取消编组为哈希。WhileJSON.load
将取消编组到指示的对象(在您的情况下,是 Chef::Role)。
JSON.parse('{ "json_class": "Chef::Role" }').class => Hash
JSON.load('{ "json_class": "Chef::Role" }').class => Chef::Role
您可以在解析之前对字符串执行 agsub
操作,然后将该特定键更改为其他键。
如何在之前和之后显示 JSON 样本?
根据文档,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 是一个哈希,但只要 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 对,那么以后仍然可能会遇到麻烦,就像在这种情况下一样。