2011-02-03 24 views
6

Tengo una cadena JSON serializada (definición de rol de chef en realidad) y tiene una clave json_class, haciendo que el analizador rubsen JSON intente forzarlo a ser un objeto Chef :: Role. ¿Cómo puedo hacer que el analizador ignore esta clave y simplemente deserialice en una Hash normal?¿Cómo hacer que el analizador de Ruby JSON ignore json_class?

Respuesta

14

yo sólo tenía el mismo problema, y ​​encontró la respuesta mediante la lectura de la fuente de la gema JSON - simplemente desarmar JSON.create_id antes de tratar de hacer el análisis sintáctico:

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

EDIT: Nota que desde la versión 1.7 de la gema (1.8.0 es actual mientras escribo esta actualización), el truco anterior ya no es necesario. JSON#parse ahora ignora json_class, y JSON#load se debe utilizar en su lugar para deshabilitar objetos volcados.

+1

Guau, eso parece un truco, pero realmente es la API documentada: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#create_id – jes5199

0

podría hacer un gsub en la cadena antes del análisis, y cambiar esa clave en particular a otra cosa.

¿Qué le parece mostrar una muestra de JSON antes y después?

6

La clave "json_class" está allí para indicar en qué objeto se debe desasignar el json. Es agregado por JSON.dump. En versiones más recientes de JSON, JSON.parse ignorará "json_class", desmarcando a Hash. Mientras JSON.load se desmarcará al Objeto indicado (en su caso, un Chef :: Rol).

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

Gracias para la actualización, Matt. He editado mi respuesta para reflejar eso para los transeúntes en el futuro. –

0

De acuerdo con los documentos, la solución de Mark Reed sin duda debería funcionar. Pero cuando he intentado esto en un 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 

la vagrant_json.class era un hash, pero todavía conserva el valor json_class internamente cada vez que el archivo node.json contenía el "json_class" : "Chef :: Nodo " entrada. Luego, al usar el hash para establecer el valor chef.json en la última línea, se interpretó de nuevo usando la clase json (y el resultado fue, curiosamente, una lista de ejecución vacía)

Esto es lo que funcionó. La misma idea, pero un poco menos finura:

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 

Este código trabajaron para establecer tanto los atributos JSON y la lista de ejecución de un archivo de nodo Chef, con o sin el "json_class" : "Chef :: nodo" entrada.

En resumen, la respuesta anterior parece completamente correcta en relación con obtener un hash de JSON.parse, pero si no quita el par json_class de ese hash, aún puede haber problemas más adelante, como en este caso .

Cuestiones relacionadas