在Ruby中将嵌套的哈希键从CamelCase转换为snake_case

And*_*art 29 ruby hash camelcasing key hash-of-hashes

我正在尝试构建一个API包装器gem,并且在将API返回的JSON转换为更多Rubyish格式时遇到问题.

JSON包含多层嵌套,包括哈希和数组.我想要做的是递归地将所有键转换为snake_case以便于使用.

这是我到目前为止所得到的:

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
Run Code Online (Sandbox Code Playgroud)

上面调用此方法将字符串转换为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
Run Code Online (Sandbox Code Playgroud)

理想情况下,结果类似于以下内容:

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

convert_hash_keys(hash)
# => {:hash_key => {:nested_hash_key => [{:key => "value"}]}}
Run Code Online (Sandbox Code Playgroud)

我得到的递归是错误的,我试过的这种解决方案的每个版本都不会将符号转换为超出第一级别,或者过度使用并尝试转换整个哈希值,包括值.

尝试在辅助类中解决所有这些问题,而不是修改实际的Hash和String函数(如果可能).

先感谢您.

mu *_*ort 39

您需要单独处理Array和Hash.而且,如果你在Rails中,你可以使用underscore而不是你的自制软件to_snake_case.首先是帮助减少噪音的小帮手:

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
Run Code Online (Sandbox Code Playgroud)

如果您的哈希值具有非符号或字符串的键,则可以进行underscore_key适当的修改.

如果你有一个数组,那么你只想递归地应用于convert_hash_keys数组的每个元素; 如果你有一个哈希,你想要修复键underscore_key并应用于convert_hash_keys每个值; 如果你有其他的东西,那么你想要通过它原来:

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
Run Code Online (Sandbox Code Playgroud)


Hub*_*der 35

如果你使用Rails:

hash的示例:camelCase到snake_case:

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

hash.transform_keys { |key| key.to_s.underscore }
# => { "camel_case" => "value1", "change_me" => "value2" }
Run Code Online (Sandbox Code Playgroud)

来源:http: //apidock.com/rails/v4.0.2/Hash/transform_keys

对于嵌套属性,请使用deep_transform_keys而不是transform_keys,例如:

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"}}}
Run Code Online (Sandbox Code Playgroud)

来源:http://apidock.com/rails/v4.2.7/Hash/deep_transform_keys


Ale*_*nko 6

我使用这个简短的形式:

hash.transform_keys(&:underscore)
Run Code Online (Sandbox Code Playgroud)

而且,正如@Shanaka Kuruwita 指出的那样,深度转换所有嵌套的哈希:

hash.deep_transform_keys(&:underscore)
Run Code Online (Sandbox Code Playgroud)


A F*_*kly 5

'mu is too short' 接受的答案已转换为宝石,futurechimp 的 Plissken:

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

这看起来应该在 Rails 之外工作,因为包含下划线功能。