ruby hash key camelcasing hash-of-hashes

Conversión de claves hash anidadas de CamelCase a snake_case en Ruby



key camelcasing (4)

Intento crear una gema envoltura de API y tener problemas para convertir las claves hash a un formato más Rubyish del JSON que devuelve la API.

El JSON contiene múltiples capas de anidamiento, tanto Hashes como Arrays. Lo que quiero hacer es convertir recursivamente todas las claves a snake_case para facilitar su uso.

Esto es lo que tengo hasta ahora:

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

Lo anterior llama a este método para convertir cadenas a snake_case:

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

Idealmente, el resultado sería similar al siguiente:

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

Me está equivocando la recursión, y cada versión de este tipo de solución que he probado no convierte los símbolos más allá del primer nivel, o va por la borda e intenta convertir todo el hash, incluidos los valores.

Intentando resolver todo esto en una clase de ayuda, en lugar de modificar las funciones reales de Hash y String, si es posible.

Gracias de antemano.


Debe tratar Array y Hash por separado. Y, si estás en Rails, puedes usar un underscore lugar de tu homebrew to_snake_case . Primero un pequeño ayudante para reducir el ruido:

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 tus Hashes tendrán claves que no son Símbolos o Cadenas, entonces puedes modificar underscore_key apropiadamente.

Si tienes una matriz, entonces solo quieres aplicar recursivamente convert_hash_keys a cada elemento de la matriz; si tiene un Hash, quiere arreglar las claves con underscore_key y aplicar convert_hash_keys a cada uno de los valores; si tienes algo más, entonces quieres pasarlo intacto:

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 está utilizando la biblioteca active_support, puede usar deep_transform_keys! al igual que:

hash.deep_transform_keys! do |key| k = key.to_s.snakecase rescue key k.to_sym rescue key end


Si usa Rails :

Ejemplo con hash: camelCase a snake_case :

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

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

Para los atributos anidados, use deep_transform_keys en lugar de transform_keys, por ejemplo:

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"}}}

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