Quelle est la meilleure façon de convertir une paire de valeurs de clé au format json avec un symbole en tant que clé?

Je me demande quelle est la meilleure façon de convertir une paire de valeurs de clé au format json avec un symbole comme clé: exemple:

{ 'user': { 'name': 'foo', 'age': 40, 'location': { 'city' : 'bar', 'state': 'ca' } } } ==> { :user=>{ :name => 'foo', :age =>'40', :location=>{ :city => 'bar', :state=>'ca' } } } 

Y a-t-il une méthode d’assistance qui peut faire cela?

en utilisant le json gem lors de l’parsing syntaxique de la chaîne json, vous pouvez transmettre l’option symbolize_names. Voir ici: http://flori.github.com/json/doc/index.html (regardez sous parsing)

par exemple:

 >> s ="{\"akey\":\"one\",\"bkey\":\"two\"}" >> JSON.parse(s,:symbolize_names => true) => {:akey=>"one", :bkey=>"two"} 

Leventix, merci pour votre réponse.

La méthode Marshal.load (Marshal.dump (h)) a probablement le plus d’intégrité des différentes méthodes car elle préserve les types de clé d’origine de manière récursive .

Ceci est important si vous avez un hachage nested avec un mélange de clés de chaîne et de symbole et que vous souhaitez conserver ce mélange lors du décodage (par exemple, cela peut se produire si votre hachage contient vos propres objects personnalisés et un troisième hautement complexe) -parties dont vous ne pouvez pas manipuler / convertir les clés pour une raison quelconque, comme une contrainte de temps de projet).

Par exemple:

 h = { :youtube => { :search => 'daffy', # nested symbol key 'history' => ['goofy', 'mickey'] # nested ssortingng key } } 

Méthode 1 : JSON.parse – symbolise toutes les clés récursivement => Ne conserve pas le mixage d’origine

 JSON.parse( h.to_json, {:symbolize_names => true} ) => { :youtube => { :search=> "daffy", :history => ["goofy", "mickey"] } } 

Méthode 2 : ActiveSupport :: JSON.decode – symbolise uniquement les clés de niveau supérieur => Ne conserve pas le mixage d’origine

 ActiveSupport::JSON.decode( ActiveSupport::JSON.encode(h) ).symbolize_keys => { :youtube => { "search" => "daffy", "history" => ["goofy", "mickey"] } } 

Méthode 3 : Marshal.load – préserve le mélange chaîne / symbole d’origine dans les clés nestedes. PARFAIT!

 Marshal.load( Marshal.dump(h) ) => { :youtube => { :search => "daffy", "history" => ["goofy", "mickey"] } } 

À moins d’un inconvénient que je ne connais pas, je pense que la méthode 3 est la voie à suivre.

À votre santé

Il n’y a rien de intégré pour faire le tour, mais ce n’est pas trop difficile d’écrire le code pour le faire en utilisant le joyau JSON. Il y a une méthode symbolize_keys intégrée à Rails si vous l’utilisez, mais cela ne symbolise pas récursivement les clés comme vous en avez besoin.

 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 

Comme le dit Leventix, la gemme JSON ne gère que les chaînes entre guillemets doubles (ce qui est techniquement correct – JSON devrait être formaté avec des guillemets doubles). Ce bit de code va nettoyer cela avant d’essayer de l’parsingr.

Méthode récursive:

 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 == Ssortingng || 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 

Bien sûr, il y a un joyau json , mais qui ne traite que des guillemets doubles.

Une autre façon de gérer cela consiste à utiliser la sérialisation / désérialisation YAML, qui préserve également le format de la clé:

 YAML.load({test: {'test' => { ':test' => 5}}}.to_yaml) => {:test=>{"test"=>{":test"=>5}}} 

L’avantage de cette approche semble être un format mieux adapté aux services REST …