Conversion des clés de hachage imbriquées de CamelCase en cas de serpent dans Ruby

J'essaie de construire une gem wrapper API, et j'ai des problèmes avec la conversion des clés de hachage en un format plus Rubyish à partir du JSON que l'API renvoie.

Le JSON contient plusieurs couches d'imbrication, à la fois des hachages et des tableaux. Ce que je veux faire est de convertir récursivement toutes les clés en snake_case pour une utilisation plus facile.

Voici ce que j'ai jusqu'à présent:

def convert_hash_keys(value)
  return value if (not value.is_a?(Array) and not value.is_a?(Hash))
  result = value.inject({}) do |new, (key, value)|
    new[to_snake_case(key.to_s).to_sym] = convert_hash_keys(value)
    new
  end
  result
end

Ce qui précède appelle cette méthode pour convertir les chaînes en snake_case:

def to_snake_case(string)
  string.gsub(/::/, '/').
  gsub(/([A-Z]+)([A-Z][a-z])/,'1_2').
  gsub(/([a-zd])([A-Z])/,'1_2').
  tr("-", "_").
  downcase
end

Idéalement, le résultat serait similaire à suivant:

hash = {:HashKey => {:NestedHashKey => [{:Key => "value"}]}}

convert_hash_keys(hash)
# => {:hash_key => {:nested_hash_key => [{:key => "value"}]}}

J'ai mal la récursivité, et chaque version de ce genre de solution que j'ai essayé ne convertit pas les symboles au-delà du premier niveau, ou va trop loin et essaie de convertir le hachage entier, y compris les valeurs.

Essayer de résoudre tout cela dans une classe d'aide, plutôt que de modifier les fonctions de hachage et de chaîne réelles, si possible.

Merci d'avance.

22
demandé sur Andrew Grimm 2012-01-03 05:13:02

4 réponses

Vous devez traiter Array et Hash séparément. Et, si vous êtes dans les Rails, vous pouvez utiliser underscore au lieu de votre homebrew to_snake_case. D'abord un peu d'aide pour réduire le bruit:

def underscore_key(k)
  k.to_s.underscore.to_sym
  # Or, if you're not in Rails:
  # to_snake_case(k.to_s).to_sym
end

Si vos hachages ont des clés qui ne sont pas des symboles ou des chaînes, vous pouvez modifier underscore_key de manière appropriée.

Si vous avez un tableau, alors vous voulez juste appliquer récursivement convert_hash_keys à chaque élément du tableau; si vous avez un hachage, vous voulez fixer les clés avec underscore_key et appliquer convert_hash_keys à chacun des valeurs; si vous avez autre chose, vous voulez le passer à travers intact:

def convert_hash_keys(value)
  case value
    when Array
      value.map { |v| convert_hash_keys(v) }
      # or `value.map(&method(:convert_hash_keys))`
    when Hash
      Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] }]
    else
      value
   end
end
35
répondu mu is too short 2013-08-09 16:31:18

Si vous utilisez Rails:

Exemple avec hachage: camelCase pour snake_case:

hash = { camelCase: 'value1', changeMe: 'value2' }

hash.transform_keys { |key| key.to_s.underscore }
# => { "camel_case" => "value1", "change_me" => "value2" }

Source: http://apidock.com/rails/v4.0.2/Hash/transform_keys

Pour les attributs imbriqués, utilisez deep_transform_keys au lieu de transform_keys, exemple:

hash = { camelCase: 'value1', changeMe: { hereToo: { andMe: 'thanks' } } }

hash.deep_transform_keys { |key| key.to_s.underscore }
# => {"camel_case"=>"value1", "change_me"=>{"here_too"=>{"and_me"=>"thanks"}}}

Source: http://apidock.com/rails/v4.2.7/Hash/deep_transform_keys

24
répondu Hubert Olender 2017-03-10 20:12:28

La réponse acceptée par 'mu est trop courte' a été convertie en une gemme, futurechimp's Plissken:

Https://github.com/futurechimp/plissken/blob/master/lib/plissken/ext/hash/to_snake_keys.rb

Cela semble fonctionner en dehors de Rails car la fonctionnalité de soulignement est incluse.

3
répondu A Fader Darkly 2014-02-20 15:14:21

Si vous utilisez la bibliothèque active_support, vous pouvez utiliser deep_transform_keys! comme ça:

hash.deep_transform_keys! do |key|
  k = key.to_s.snakecase rescue key
  k.to_sym rescue key
end
0
répondu JayJay 2018-01-24 09:49:37