2015-10-02 4 views
1

Как я могу десериализации JSON строку в Struct вместо значения по умолчанию (который является Hash, что-то, где хэш-ключи являются доступными в качестве методов на объекте, используя что-то вроде attr_accessor с, в основном.Deserialize JSON в Struct?

Другими словами, Я действительно хочу, чтобы иметь возможность написать obj.my_json_property для доступа к данным

ответ

1

Если OpenStruct приемлемо (который все еще позволяет использовать-структуру, как obj.my_json_property, т.е. удовлетворяет исходное требование), использовать этот подход:.

require 'json' 
obj = JSON.parse(json_text, object_class: OpenStruct) 
puts obj.my_json_property 

Вместо этого я попытался использовать object_class: Struct, но он дает мне «TypeError: allocator undefined for Struct». Однако для большинство (но не все) практических целей, OpenStruct просто отлично. Главный недостаток заключается в том, что если вы неправильно назовете одно из ваших имен свойств, ваш код будет работать нормально, значение будет просто нулевой/пустой строкой (в зависимости от контекста) ... что может быть немного раздражающим и вводящим в заблуждение.

Немного похоже на Hash#[] vs Hash#fetch (для справки см.: http://devblog.avdi.org/2009/03/16/go-fetch/).

+0

Но зачем вы хотите это делать? «Хэш» намного быстрее, чем «OpenStruct» для доступа к данным. – engineersmnky

+0

Иногда скорость - это не самая важная цель. На самом деле, если это так, зачем писать код в Ruby в первую очередь? ;) Мне нравятся реальные объекты; код более ясный, более красивый таким образом. –

+0

«Хэш» - это реальный объект, но каждому есть свои. Если вы действительно хотите, чтобы «Struct» дал мой ответ, попробуйте – engineersmnky

1

Вот достаточно быстрый способ превратить Hash в Struct:

class Hash 
    def to_struct 
     s = Struct.new(*self.keys.map(&:to_sym)) 
     construct = map do |k,v| 
      v.is_a?(Hash) ? v.to_struct : v.is_a?(Array) ? v.join(", ") : v 
     end 
     s.new(*construct) 
    end 
end 

Тогда вы можете делать такие вещи, как:

h = {hello: 'world',foo: {bar: 'baz'}} 
m = h.to_struct 
#=> #<struct hello="world", foo=#<struct bar="baz">> 
m.hello 
#=> "world" 
m.foo 
#=> #<struct bar="baz"> 
m.foo.bar 
#=> "baz" 

Так что в вашем случае:

require 'json' 
obj = JSON.parse(json_text).to_struct 

Будет работать нормально, и он также обрабатывает вложенные объекты (с некоторыми ob Мне очень не нравилась эта часть, поскольку это не было частью вопроса)