Merging-Hashes in yaml conf-Dateien

31. Juli 2009 von prashant
Filed under: Technik

YAML ist sehr nützlich für das Schreiben von Konfigurationsdateien. Primärer Vorteil ist, dass, liest es wie Text-Datei. Das funktioniert wirklich gut, wenn deine config-Datei ist flach (keine Hierarchie) und hat keine Wiederholungen.
Wenn Ihre Konfigurationsdatei hat Wiederholungen dann macht es Sinn zu trennen diejenigen Elemente und wiederverwendet werden. Was ich meine ist diese - sagen wir mal du deine config-Datei wie folgt aussieht:

  Entwicklung:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Ihr_Server
     login: your_login
     Kennwort: top_secret
 Produktion:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Ihr_Server
     login: your_login
     Kennwort: top_secret 

Angenommen obigen Code in / tmp / test.yml hier, wie Sie in Python und Ruby zu lesen
$cat readyml.py

 #! / Usr / bin / env python
 von pprint Import pprint als pp
 # In debian müssen python-yaml installieren
 von yaml import laden, load_all, dump
 hash = load (open ('/ tmp / test.yml'))
 pp (hash ["Entwicklung"]) 


$ cat readyml.rb

  #! / Usr / bin / env ruby
 require 'pp'
 hash = YAML:: load (File.open ('/ tmp / test.yml') zu lesen.)
 pp hash ["Entwicklung"] 

Hier ist eine praktische Einzeiler für die Ruby-Version
$ ruby -rpp -e 'pp YAML::load(File.open("/tmp/a.yml"))["development"]' oder Sie können das gleiche in irb oder Python-Konsole ausprobieren.

Beachten Sie, dass in den obigen Code-Schnipsel, alles andere als Ausgang Standort gleichen in der Entwicklung und Produktion Teil ist. Dies ist, wo yml Knoten-ID kommt zu retten. Idee ist einfach eine Reihe von Standardwerten und überschreiben sie an anderer Stelle.
Sie ziehen konnte es auseinander wie folgt:

  Standardeinstellungen: & defaults
   input_location: common_input
   output_location: dev_location
   mail:
     sender_name: Absender
     smtp_server: Ihr_Server
     login: your_login
     Kennwort: top_secret
 Entwicklung:
   <<: * Defaults
 Produktion:
   <<: * Defaults
   output_location: prod_location 


$ ruby -rpp -e 'pp YAML::load(File.open("/tmp/a.yml"))["development"]["mail"]["login"]'
"your_login"
$

Große, es funktioniert (tm)!.
Wohl haben wir gehandelt Klarheit für ein bisschen Magie. Hier eine kleine Erläuterung: &, * und <<: & das Anker-Tag als Knoten-ID verstanden werden kann, ist * Knoten-Referenz und <<: steht für Hash verschmelzen.

Weitere Details finden Sie entweder yaml specs oder wikipedia
So weit so gut, aber es gibt einen Haken hier, sind diese Hash geht nicht rekursiv. Was es bedeutet, ist dies: Angenommen, Sie möchten verschiedene Absender-Namen für E-Mail in beiden Umgebungen haben, könnten Sie versucht, die Folgendes leistet:

  Standardeinstellungen: & defaults
   input_location: common_input
   output_location: dev_location
   mail:
     sender_name: Absender
     smtp_server: Ihr_Server
     login: your_login
     Kennwort: top_secret
 Entwicklung:
   <<: * Defaults
   mail:
     sender_name: sender_dev
 Produktion:
   <<: * Defaults
   output_location: prod_location
   mail:
     sender_name: sender_prod 

Lets prüfen

$ ruby -rpp -e 'pp YAML::load(File.open("/tmp/a.yml"))["development"]["mail"]["login"]'
nil
$

Hoppla, ist etwas schief gelaufen, Problem wie oben erwähnt ist, dass die Hash-merge nicht rekursiv ist und während der Zusammenführung es ersetzt mail des Ausfalls mail der Produktion, die nur einen Schlüssel hat. Lösung / Umgehung ist zu entrollen eine weitere Ebene:

  common_settings: & common_settings
 input_location: common_input
 output_location: dev_location
 mail_defaults: & mail_defaults
  sender_name: Absender
   smtp_server: Ihr_Server
   login: your_login
   Kennwort: top_secret

 Standardeinstellungen: & defaults
   <<: * Common_settings
   mail:
     <<: * Mail_defaults
 Entwicklung:
   <<: * Defaults
 Produktion:
   <<: * Defaults
   mail:
     <<: * Mail_defaults
     sender_name: sender_prod

Lets prüfen Sie erneut

$ ruby -rpp -e 'pp YAML::load(File.open("/tmp/a.yml"))["development"]["mail"]["login"]'
"your_login"
$

Haben Sie sagen, Sie haben eine weitere Ebene der Verschachtelung, gut man kann definitiv entrollen eine weitere Ebene, aber dann wird es ein Durcheinander. Also, wenn Sie nicht versuchen, Lösung der Türme von Hanoi in einer conf-Datei zu schreiben, ist es besser, conf-Datei als Graben in yaml oder etwas anderes restucture. Aber das ist Ihr Anruf trotzdem.

Kommentare

  • Der vollständige 453-seitige Dokument listet auch potenzielle Bereiche für
    Konsolidierung, einschließlich Privatisierung Müllabfuhr, die Zusammenlegung der Stadt-und
    Wayne County Gesundheitsämter und die Zusammenarbeit mit Detroit Public Schools auf
    Erholung. Der Vorschlag enthielt keine ...
  • Eine Person mit dem Deal, sagte der beiden Seiten noch Hashing einen Namen für einen fusionierten Unternehmens. Aber diese Person sagte, eine Idee in Betracht gezogen wird die Auswahl eines Namens, der nicht das Wort "Deutsche" oder die Abkürzung "NYSE" in ihm. ...
  • Ja ärgerlich es ist nicht rekursiv verschmelzen. Ich konnte einen Workaround in meinem balphp Bibliothek zu machen.
Blog-Kommentare von Disqus angetrieben