2011-02-03 13 views
6

Mam zserializowany ciąg JSON (definicja roli szefa kuchni) i ma klucz json_class, co sprawia, że ​​parser JSON ruby ​​próbuje wymusić na nim obiekt Chef :: Role. Jak mogę uczynić parser zignorować ten klucz i po prostu deserializować w normalny Hash?Jak uczynić parser Ruby JSON ignorować json_class?

Odpowiedz

14

prostu miałem ten sam problem i znaleźć odpowiedź czytając źródło gem JSON - tylko wyłączonym JSON.create_id przed próbuje zrobić parse:

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

EDIT: pamiętać, że od wersja 1.7 klejnotu (1.8.0 jest aktualne, gdy wpisuję tę aktualizację), powyższy hack nie jest już potrzebny. JSON#parse teraz ignoruje json_class, a zamiast tego powinno się używać JSON#load do usuwania porzuconych obiektów.

+1

Wow, wygląda jak haker, ale tak naprawdę jest to udokumentowane API: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#create_id – jes5199

0

Możesz może zrobić gsub na ciąg przed analizą i zmienić ten konkretny klucz na coś innego.

Co powiesz na pokazanie próbki JSON przed i po?

6

Klawisz "json_class" służy do wskazywania, który obiekt json powinien być niezagrożony jako. Jest on dodawany przez JSON.dump. W nowszych wersjach JSON, JSON.parse zignoruje "json_class", un-marshaling do Hash. Podczas gdy JSON.load odłączy się od wskazanego obiektu (w twoim przypadku Chef :: Role).

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

Dzięki dla aktualizacji, Matt. Zmieniłem swoją odpowiedź, aby odzwierciedlić to dla przyszłych przechodniów. –

0

Zgodnie z dokumentami rozwiązanie Marka Reeda powinno z pewnością zadziałać. Ale gdy próbowałem to w 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 był Hash, ale nadal zachował wartość json_class wewnętrznie, gdy plik node.json zawierał „json_class” : „Chef :: Node "Wpis. Następnie, używając skrótu do ustawienia wartości chef.json w ostatnim wierszu, została ponownie zinterpretowana przy użyciu klasy json (a wynikiem była dziwna lista pustych przebiegów).

Oto, co zadziałało. Sam pomysł, ale nieco mniej finezji:

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 

Ten kod pracował ustawić oba atrybuty json i wykaz uruchamiane z pliku węzła Chef, z lub bez „json_class” : „Chef :: Node” pozycja.

Podsumowując, poprzednia odpowiedź wydaje się być całkowicie poprawna w odniesieniu do uzyskania skrótu od JSON.parse, ale jeśli nie usuniesz pary json_class z tego skrótu, problem może być późniejszy, jak w tym przypadku .

Powiązane problemy