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.
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
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
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.
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