37

APIラッパーgemを構築しようとしています.APIが返すJSONからハッシュキーをよりRubyっぽい形式に変換する際に問題があります。

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

再帰が間違っています。私が試したこの種のソリューションのすべてのバージョンは、最初のレベルを超えてシンボルを変換しないか、船外に出て、値を含むハッシュ全体を変換しようとします。

可能であれば、実際のハッシュ関数と文字列関数を変更するのではなく、ヘルパー クラスでこれらすべてを解決しようとしています。

前もって感謝します。

4

7 に答える 7

52

Railsを使用する場合:

ハッシュの例: camelCase から 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

于 2016-10-17T19:15:19.747 に答える
42

配列とハッシュを別々に扱う必要があります。また、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

ハッシュにシンボルまたは文字列ではないキーがある場合は、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
于 2012-01-03T02:15:48.303 に答える
5

「mu is too short」で受け入れられた回答は、gem、futurechimp の Plissken に変換されました。

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

アンダースコア機能が含まれているため、これはRailsの外でも動作するはずです。

于 2014-02-20T15:14:21.137 に答える
0

active_support ライブラリを使用している場合は、deep_transform_keys を使用できます。そのようです:

hash.deep_transform_keys! do |key|
  k = key.to_s.snakecase rescue key
  k.to_sym rescue key
end
于 2018-01-24T09:22:43.863 に答える