2015-10-13 15 views
5

Ho un OpenStruct che è annidato con molti altri OpenStructs. Qual è il modo migliore per convertirli tutti in JSON?Deep Convert OpenStruct to JSON

Idealmente:

x = OpenStruct.new 
x.y = OpenStruct.new 
x.y.z = OpenStruct.new 
z = 'hello' 

x.to_json 
// {y: z: 'hello'} 

Realtà

{ <OpenStruct= ....> } 

risposta

7

Non ci sono metodi predefiniti per realizzare tale compito, perché il built-in #to_hash restituisce la rappresentazione Hash ma non profonda converte i valori.

Se un valore è OpenStruct, viene restituito come tale e non viene convertito in Hash.

Tuttavia, questo non è così complicato da risolvere. È possibile creare un metodo che attraversa ogni chiave/valore in un'istanza OpenStruct (ad esempio utilizzando each_pair), discende in modo ricorsivo negli OpenStruct nidificati se il valore è OpenStruct e restituisce un Hash di tipi di base solo Ruby.

Tale Hash può quindi essere serializzato facilmente utilizzando .to_json o JSON.dump(hash).

Questo è un esempio molto breve

def openstruct_to_hash(object, hash = {}) 
    object.each_pair do |key, value| 
    hash[key] = value.is_a?(OpenStruct) ? openstruct_to_hash(value) : value 
    end 
    hash 
end 

openstruct_to_hash(OpenStruct.new(foo: 1, bar: OpenStruct.new(baz: 2))) 
# => {:foo=>1, :bar=>{:baz=>2}} 
+0

Grazie per la risposta dettagliata! Mi sento illuminato ora! Sembra che 'to_json' sia piuttosto zoppo in questo aspetto dal momento che si spera che tu possa convertire ricorsivamente in JSON. E perché 'OpenStruct' ha un metodo' to_json'? – Breedly

+0

'to_json' è un'abitudine (cattiva?) Resa popolare dalla pigrizia dei programmatori. È molto semplice chiamare '.to_json', così semplice che spesso si dimentica che avere tali metodi globali richiede che ogni possibile oggetto lo implementa o cada all'implementazione standard. Ogni volta che si usano oggetti complessi, è meglio essere espliciti (o usare direttamente JSON o per oggetti più complessi come i modelli ActiveRecord usare un serializzatore). –

+0

Puoi indicarmi ulteriori informazioni su questo? – Breedly

4

correzioni alla soluzione precedente per gestire array

def open_struct_to_hash(object, hash = {}) 
    object.each_pair do |key, value| 
    hash[key] = case value 
        when OpenStruct then open_struct_to_hash(value) 
        when Array then value.map { |v| open_struct_to_hash(v) } 
        else value 
       end 
    end 
    hash 
end