Как заставить анализатор Ruby JSON игнорировать json_class? - PullRequest
6 голосов
/ 03 февраля 2011

У меня есть сериализованная строка JSON (фактически определение роли chef), и у нее есть ключ json_class, благодаря чему анализатор ruby ​​JSON пытается заставить его быть объектом Chef :: Role. Как я могу заставить анализатор игнорировать этот ключ и просто десериализовать в обычный хэш?

Ответы [ 4 ]

14 голосов
/ 30 июня 2011

У меня была та же проблема, и я нашел ответ, прочитав источник гема JSON - просто сбросьте JSON.create_id перед попыткой разбора:

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

РЕДАКТИРОВАТЬ: Обратите внимание, что начиная с версии 1.7 гема (1.8.0 является текущей, когда я набираю это обновление), вышеупомянутый взлом больше не нужен. JSON#parse теперь игнорирует json_class, и вместо него следует использовать JSON#load для демаршалинга сброшенных объектов.

6 голосов
/ 29 марта 2013

Клавиша "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
0 голосов
/ 12 марта 2014

Согласно документам, решение Марка Рида, безусловно, должно работать. Но когда я попробовал это в 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, но он все равно сохранял значение json_class внутри всякий раз, когда файл node.json содержал запись "json_class": "Chef :: Node" . Затем при использовании хэша для установки значения 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

Этот код работал для установки как атрибутов json, так и списка выполнения из файла узла Chef, с или без "json_class": "Chef :: Node" запись.

Таким образом, предыдущий ответ кажется совершенно правильным в отношении получения хеша из JSON.parse, но если вы не удалите пару json_class из этого хеша, позже могут возникнуть проблемы, как в этом случае.

0 голосов
/ 03 февраля 2011

Вы могли бы сделать gsub в строке перед синтаксическим анализом и заменить этот ключ на что-то другое.

Как насчет показа образца JSON до и после?

...