2009-08-04 8 views
2

J'ai une classe de configuration dans Ruby qui avait des clés comme "core.username" et "core.servers", qui étaient stockées dans un fichier YAML comme ça.Modifier les valeurs dans un hachage imbriqué

Maintenant j'essaye de le changer pour être imbriqué, mais sans devoir changer tous les endroits qui se rapportent aux clés dans l'ancienne manière. Je l'ai réussi avec le lecteur méthode:

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

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

    target 
end 

Mais quand j'ai essayé la même chose avec l'écrivain classe, qui fonctionne, mais il est pas défini dans la @config -hash. @config est réglé avec juste un appel à YAML.load_file

J'ai réussi à le faire fonctionner avec eval, mais ce n'est pas quelque chose que je voudrais garder longtemps.

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

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

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

Y a-t-il un moyen décent d'y parvenir, de préférence sans modifier les plugins et le code?

Répondre

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

Édition: Correction du fractionnement. PS: Vous pouvez également remplacer l'injection par une boucle comme dans la méthode [] si vous préférez. L'important est que vous n'appeliez pas [] avec la dernière clé, mais plutôt [] = pour définir la valeur.

+0

Vous avez oublié de diviser le "" au lieu des espaces, mais à part ça, ça fonctionne comme un charme. Merci! –

0

J'utilisé récursion:

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 
Questions connexes