在Ruby中将嵌套的哈希键从CamelCase转换为snake_case [英] Converting nested hash keys from CamelCase to snake_case in Ruby

查看:154
本文介绍了在Ruby中将嵌套的哈希键从CamelCase转换为snake_case的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构建一个API包装器gem,并且存在将哈希键从API返回的JSON转换为更多Rubyish格式的问题。

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



以下是我到目前为止的内容:

  def convert_hash_keys(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

上面调用这个方法将字符串转换为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

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

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

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

我得到的递归是错误的,我试过的解决方案不会将符号转换为第一级以上,或者会过度并尝试转换整个哈希,包括值。



试图解决所有问题如果可能的话,而不是修改实际的哈希和字符串函数。



预先感谢您。

解决方案

你需要分别对待Array和Hash。而且,如果您位于Rails中,则可以使用 下划线 而不是您的自制软件 to_snake_case 。首先是帮助减少噪音:

  def underscore_key(k)
k.to_s.underscore.to_sym
#或者,如果你不在Rails中:
#to_snake_case(k.to_s).to_sym
end

如果你的Hashes的键不是符号或字符串,那么你可以适当地修改 underscore_key



如果你有一个数组,那么你只是想递归地将 convert_hash_keys 应用到数组的每个元素;如果你有一个Hash,你想用 underscore_key 修复这些键,并为每个值应用 convert_hash_keys ;如果你有其他东西,那么你想通过它不变:

  def convert_hash_keys(值)
大小写值
当Array
value.map {| v | convert_hash_keys(v)}
#或`value.map(& method(:convert_hash_keys))`
当Hash
Hash [value.map {| k,v | [underscore_key(k),convert_hash_keys(v)]}]
else
value
end
end


I'm trying to build an API wrapper gem, and having issues with converting hash keys to a more Rubyish format from the JSON the API returns.

The JSON contains multiple layers of nesting, both Hashes and Arrays. What I want to do is to recursively convert all keys to snake_case for easier use.

Here's what I've got so far:

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

The above calls this method to convert strings to 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

Ideally, the result would be similar to the following:

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

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

I'm getting the recursion wrong, and every version of this sort of solution I've tried either doesn't convert symbols beyond the first level, or goes overboard and tries to convert the entire hash, including values.

Trying to solve all this in a helper class, rather than modifying the actual Hash and String functions, if possible.

Thank you in advance.

解决方案

You need to treat Array and Hash separately. And, if you're in Rails, you can use underscore instead of your homebrew to_snake_case. First a little helper to reduce the noise:

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

If your Hashes will have keys that aren't Symbols or Strings then you can modify underscore_key appropriately.

If you have an Array, then you just want to recursively apply convert_hash_keys to each element of the Array; if you have a Hash, you want to fix the keys with underscore_key and apply convert_hash_keys to each of the values; if you have something else then you want to pass it through untouched:

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

这篇关于在Ruby中将嵌套的哈希键从CamelCase转换为snake_case的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆