私はAPIラッパーgemを作成しようとしていますが、ハッシュキーをAPIが返すJSONからよりルビーな形式に変換する際に問題があります。
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
上記はこのメソッドを呼び出して文字列を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"}]}}
私は再帰を間違えています。私が試したこの種のソリューションのすべてのバージョンは、最初のレベルを超えてシンボルを変換しないか、または行き過ぎて値を含むハッシュ全体を変換しようとします。
可能であれば、実際のハッシュ関数と文字列関数を変更するのではなく、ヘルパークラスでこれをすべて解決しようとします。
前もって感謝します。
配列とハッシュを別々に扱う必要があります。また、Railsを使用している場合は、自作のto_snake_case
の代わりに underscore
を使用できます。まず、ノイズを減らすための小さなヘルパー:
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
ハッシュに記号でも文字列でもないキーがある場合は、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
Railsを使用する場合:
ハッシュの例:camelCase to snake_case:
hash = { camelCase: 'value1', changeMe: 'value2' }
hash.transform_keys { |key| key.to_s.underscore }
# => { "camel_case" => "value1", "change_me" => "value2" }
ソース: http://apidock.com/Rails/v4.0.2/Hash/transform_keys
ネストされた属性の場合、transform_keysの代わりにdeep_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"}}}
ソース: http://apidock.com/Rails/v4.2.7/Hash/deep_transform_keys
'mu is too short'によって受け入れられた回答は、gem、futurechimpのPlisskenに変換されました。
https://github.com/futurechimp/plissken/blob/master/lib/plissken/ext/hash/to_snake_keys.rb
これは、アンダースコア機能が含まれているため、Rails以外でも機能するはずです。
Active_supportライブラリを使用している場合は、deep_transform_keysを使用できます。そのようです:
hash.deep_transform_keys! do |key|
k = key.to_s.snakecase rescue key
k.to_sym rescue key
end