2009-08-04 19 views
2

Ich habe eine Konfigurationsklasse in Ruby, die Schlüssel wie "core.username" und "core.servers" hatte, die in einer YAML-Datei einfach so gespeichert wurde.Ändern von Werten in einem verschachtelten Hash

Jetzt versuche ich es zu verschachteln, aber ohne alle Orte, die auf die Schlüssel auf die alte Weise beziehen, zu ändern. Ich habe es mit der Leser-Methode verwaltet:

def [](key) 
    namespace, *rest = key.split(".") 

    target = @config[namespace] 
    rest.each do |k| 
    return nil unless target[k] 
    target = target[k] 
    end 

    target 
end 

Aber als ich versuchte, das gleiche mit der Schriftsteller-Klasse, die funktioniert, ist aber in dem @config -hash nicht gesetzt. @config wird mit nur einem Anruf YAML.load_file

eingestellt Ich schaffte es mit eval arbeiten, aber das ist etwas, was ich nicht gerne lange behalten würde.

def []=(key, value) 
    namespace, *rest = key.split(".") 

    target = "@config[\"#{namespace}\"]" 
    rest.each do |key| 
    target += "[\"#{key}\"]" 
    end 

    eval "#{target} = value" 
    self[key] 
end 

Gibt es einen vernünftigen Weg dies zu erreichen, vorzugsweise ohne Plugins und Code zu ändern?

Antwort

1
def []=(key, value) 
    subkeys = key.split(".") 
    lastkey = subkeys.pop 
    subhash = subkeys.inject(@config) do |hash, k| 
    hash[k] 
    end 
    subhash[lastkey] = value 
end 

Bearbeiten: Die Aufteilung behoben. PS: Sie können den inject auch durch eine each-Schleife wie in der [] -Methode ersetzen, wenn Sie bevorzugen. Wichtig ist, dass Sie [] nicht mit dem letzten Schlüssel aufrufen, sondern stattdessen [] =, um den Wert festzulegen.

+0

Sie haben vergessen zu spalten auf "" anstelle von Räumen, aber ansonsten wirkt es wie ein Zauber. Vielen Dank! –

0

I verwendet Rekursion:

def change(hash) 
    if hash.is_an? Hash 
    hash.inject({}) do |acc, kv| 
     hash[change(kv.first)] = change(kv.last) 
     hash 
    end 
    else 
    hash.to_s.split('.').trim # Do your fancy stuff here 
    end 
end 
Verwandte Themen