Как сериализовать / десериализовать хэши / структуры ruby ​​с объектами в качестве ключей к json - PullRequest
0 голосов
/ 14 сентября 2018

Я хотел бы выгрузить вложенную структуру данных в ruby ​​в json (мне известен модуль Marshal, но мне нужен стандартный формат) и иметь возможность снова загружать / анализировать структуру данных.Поймай: я использую структуры (или проще для примера: хэши) в качестве ключей хэшей.Пример:

require 'json'
h = {{hello: 123} => 123}
JSON.parse(JSON.generate(h)) #=> {"{:hello=>123}"=>123}

Итак, проблема в том, что JSON.generate (h) сериализует ключ {: hello => 123} в виде строки, и когда я снова анализирую результат, он остается строкой.

Как я могу решить эту проблему и восстановить первоначальную структуру после создания / анализа?

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

Мне нужен стандартный формат

YAML - это стандартный формат, которого здесь будет достаточно:

▶ h = {{hello: 123} => 123}
#⇒ {{:hello=>123}=>123}
▶ YAML.dump h
#⇒ "---\n? :hello: 123\n: 123\n"
▶ YAML.load _
#⇒ {{:hello=>123}=>123}
0 голосов
/ 15 сентября 2018

Как уже указывал мудасобва, YAML - хороший инструмент: он позволяет хранить также объекты пользовательских классов:

require 'yaml'

class MyCaptain
  attr_accessor :name, :ship
  def initialize(name, ship)
    @name = name
    @ship = ship
  end
end

kirk = MyCaptain.new('James T. Kirk', 'USS Enterprise NCC-1701')
picard = MyCaptain.new('Jean-Luc Picard', 'Enterprise NCC-1701D')

captains = [kirk, picard]

File.open("my_captains.yml","w") do |file|
   file.write captains.to_yaml
end 

p YAML.load_file('my_captains.yml')

#=> [#<MyCaptain:0x007f889d0973b0 @name="James T. Kirk", @ship="USS Enterprise NCC-1701">, #<MyCaptain:0x007f889d096b40 @name="Jean-Luc Picard", @ship="Enterprise NCC-1701D">]
0 голосов
/ 14 сентября 2018

JSON допускает только строки в качестве ключей объекта.По этой причине to_s вызывается для всех ключей.

У вас будут следующие варианты решения вашей проблемы:

  1. Лучший вариант -изменив структуру данных, чтобы ее можно было правильно сериализовать в JSON.

  2. Вам придется обрабатывать строковый ключ самостоятельно.Hash создает совершенно правильный синтаксис Ruby при преобразовании в строку, которую можно преобразовать с помощью Kernel # eval подобно В комментариях предложил Андрей Дейнеко .

    result = json.transform_keys { |key| eval(key) }
           # json.transform_keys(&method(:eval)) is the same as the above.
    

    Метод Hash # transform_keys является относительно новым (доступен начиная с Ruby 2.5.0) и в настоящее время может отсутствовать в вашей среде разработки.Вы можете заменить это на простой Enumerable # map , если необходимо.

    result = json.map { |k, v| [eval(k), v] }.to_h
    

    Примечание: Если входящий JSON содержит какой-либо созданный пользователемЯ настоятельно рекомендую вам не использовать eval , поскольку вы можете разрешить пользователю выполнять код на вашем сервере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...