wake-up-neo.net

Konvertieren verschachtelter Hash-Schlüssel von CamelCase in snake_case in Ruby

Ich versuche, ein API-Wrapper-Gem zu erstellen, und habe Probleme beim Konvertieren von Hash-Schlüsseln in ein Rubyish-Format aus dem von der API zurückgegebenen JSON.

Der JSON enthält mehrere Verschachtelungsebenen, sowohl Hashes als auch Arrays. Was ich tun möchte, ist, alle Schlüssel zur einfacheren Verwendung rekursiv in snake_case zu konvertieren.

Folgendes habe ich bisher:

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

Oben wird diese Methode aufgerufen, um Zeichenfolgen in snake_case zu konvertieren:

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

Im Idealfall sieht das Ergebnis wie folgt aus:

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

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

Ich verstehe die Rekursion falsch und jede Version dieser Art von Lösung, die ich versucht habe, konvertiert entweder keine Symbole über die erste Ebene hinaus oder geht über Bord und versucht, den gesamten Hash, einschließlich der Werte, zu konvertieren.

Versuchen Sie, all dies in einer Hilfsklasse zu lösen, anstatt, wenn möglich, die eigentlichen Hash- und String-Funktionen zu ändern.

Danke im Voraus.

24
Andrew Stewart

Sie müssen Array und Hash separat behandeln. Und wenn Sie sich in Rails befinden, können Sie underscore anstelle Ihres Homebrew-Codes to_snake_case verwenden. Zuerst ein kleiner Helfer, um den Lärm zu reduzieren:

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

Wenn Ihre Hashes Schlüssel enthalten, die keine Symbole oder Zeichenfolgen sind, können Sie underscore_key entsprechend ändern.

Wenn Sie über ein Array verfügen, möchten Sie nur convert_hash_keys rekursiv auf jedes Element des Arrays anwenden. Wenn Sie einen Hash haben, möchten Sie die Schlüssel mit underscore_key reparieren und convert_hash_keys auf jeden der Werte anwenden. Wenn Sie etwas anderes haben, möchten Sie es unberührt weitergeben:

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
38
mu is too short

Wenn Sie Rails verwenden:

Beispiel mit Hash: camelCase to snake_case :

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

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

quelle: http://apidock.com/Rails/v4.0.2/Hash/transform_keys

Verwenden Sie für verschachtelte Attribute deep_transform_keys anstelle von transform_keys, Beispiel:

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

quelle: http://apidock.com/Rails/v4.2.7/Hash/deep_transform_keys

25
Hubert Olender

Die akzeptierte Antwort von 'mu is too short' wurde in ein Juwel umgewandelt, futurechimp's Plissken:

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

Dies sollte anscheinend außerhalb von Rails funktionieren, da die Unterstreichungsfunktion enthalten ist.

3
A Fader Darkly

Wenn Sie die active_support-Bibliothek verwenden, können Sie deep_transform_keys verwenden! wie so:

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