ruby on rails - rails - ¿Cuál es la mejor manera de convertir un par de valores clave formateados json a hash ruby con símbolo como clave?
ruby read json (6)
Leventix, gracias por tu respuesta.
El método Marshal.load (Marshal.dump (h)) probablemente tenga la mayor integridad de los diversos métodos, ya que conserva los tipos de clave originales recursivamente .
Esto es importante en caso de que tenga un hash anidado con una combinación de cadenas y teclas de símbolos y desea conservar esa mezcla en la decodificación (por ejemplo, esto podría suceder si su hash contiene sus propios objetos personalizados además del tercero altamente complejo / anidado) - objetos de partes cuyas claves no se pueden manipular / convertir por cualquier razón, como una restricción de tiempo del proyecto).
P.ej:
h = {
:youtube => {
:search => ''daffy'', # nested symbol key
''history'' => [''goofy'', ''mickey''] # nested string key
}
}
Método 1 : JSON.parse: simboliza todas las teclas recursivamente => No conserva la mezcla original
JSON.parse( h.to_json, {:symbolize_names => true} )
=> { :youtube => { :search=> "daffy", :history => ["goofy", "mickey"] } }
Método 2 : ActiveSupport :: JSON.decode: simboliza las claves de nivel superior solamente => No conserva la mezcla original
ActiveSupport::JSON.decode( ActiveSupport::JSON.encode(h) ).symbolize_keys
=> { :youtube => { "search" => "daffy", "history" => ["goofy", "mickey"] } }
Método 3 : Marshal.load - conserva la mezcla original de cadena / símbolo en las claves anidadas. ¡PERFECTO!
Marshal.load( Marshal.dump(h) )
=> { :youtube => { :search => "daffy", "history" => ["goofy", "mickey"] } }
A menos que haya un inconveniente que desconozco, creo que el Método 3 es el camino a seguir.
Aclamaciones
Me pregunto cuál es la mejor manera de convertir un par de valores clave formateados json a hash ruby con símbolo como clave: ejemplo:
{ ''user'': { ''name'': ''foo'', ''age'': 40, ''location'': { ''city'' : ''bar'', ''state'': ''ca'' } } }
==>
{ :user=>{ :name => ''foo'', :age =>''40'', :location=>{ :city => ''bar'', :state=>''ca'' } } }
¿Hay algún método auxiliar que pueda hacer esto?
Método recursivo:
require ''json''
def JSON.parse(source, opts = {})
r = JSON.parser.new(source, opts).parse
r = keys_to_symbol(r) if opts[:symbolize_names]
return r
end
def keys_to_symbol(h)
new_hash = {}
h.each do |k,v|
if v.class == String || v.class == Fixnum || v.class == Float
new_hash[k.to_sym] = v
elsif v.class == Hash
new_hash[k.to_sym] = keys_to_symbol(v)
elsif v.class == Array
new_hash[k.to_sym] = keys_to_symbol_array(v)
else
raise ArgumentError, "Type not supported: #{v.class}"
end
end
return new_hash
end
def keys_to_symbol_array(array)
new_array = []
array.each do |i|
if i.class == Hash
new_array << keys_to_symbol(i)
elsif i.class == Array
new_array << keys_to_symbol_array(i)
else
new_array << i
end
end
return new_array
end
No hay nada integrado para hacer el truco, pero no es demasiado difícil escribir el código para hacerlo utilizando la joya JSON. Existe un método symbolize_keys
integrado en Rails si lo está usando, pero eso no simboliza las claves recursivamente como usted lo necesita.
require ''json''
def json_to_sym_hash(json)
json.gsub!(''/''', ''"'')
parsed = JSON.parse(json)
symbolize_keys(parsed)
end
def symbolize_keys(hash)
hash.inject({}){|new_hash, key_value|
key, value = key_value
value = symbolize_keys(value) if value.is_a?(Hash)
new_hash[key.to_sym] = value
new_hash
}
end
Como dijo Leventix, la gema JSON solo maneja cadenas de comillas dobles (lo que es técnicamente correcto - JSON debe formatearse con comillas dobles). Este pequeño código lo limpiará antes de intentar analizarlo.
Otra forma de manejar esto es usar la serialización / deserialización YAML, que también conserva el formato de la clave:
YAML.load({test: {''test'' => { '':test'' => 5}}}.to_yaml)
=> {:test=>{"test"=>{":test"=>5}}}
El beneficio de este enfoque parece ser un formato que se adapta mejor a los servicios REST ...
Por supuesto, hay una http://flori.github.com/json/doc/index.html , pero solo maneja comillas dobles.
usando la gema json al analizar la cadena json, puedes pasarla en la opción symbolize_names. Ver aquí: http://flori.github.com/json/doc/index.html (mira en el análisis sintáctico)
p.ej:
>> s ="{/"akey/":/"one/",/"bkey/":/"two/"}"
>> JSON.parse(s,:symbolize_names => true)
=> {:akey=>"one", :bkey=>"two"}