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
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.
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?
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
Dzięki dla aktualizacji, Matt. Zmieniłem swoją odpowiedź, aby odzwierciedlić to dla przyszłych przechodniów. –
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 .
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