Fletning hashes i yaml conf filer

Jul 31, 2009 ved Prashant · Kommentarer
Filed under: teknologi

YAML er ganske praktisk for at skrive konfigurationsfiler. Primære fordel er, at det lyder som tekstfil. Dette fungerer rigtig godt, hvis din config fil er flad (ingen hierarki) og har ingen gentagelser.
Hvis din konfigurationer fil har gentagelser så giver det mening at adskille de elementer og genbruge dem. Hvad jeg mener er dette - lad os sige, du din config fil ser sådan her ud:

  udvikling:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: din_server
     login: your_login
     Password: top_secret
 produktion:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: din_server
     login: your_login
     Password: top_secret 

Under forudsætning af ovenstående kode i / tmp / test.yml her er, hvordan du kan læse i Python og Ruby
$cat readyml.py

 #! / Usr / bin / env python
 fra pprint import pprint som pp
 # I debian skal installere python-yaml
 fra yaml import belastning, load_all, dump
 hash = belastning (open ("/ tmp / test.yml '))
 pp (hash ['udvikling']) 


$ cat readyml.rb

  #! / Usr / bin / env ruby
 kræver 'PP'
 hash = YAML:: load (File.open ('/ tmp / test.yml') læst.)
 pp hash ['udvikling'] 

her er en handy en liner til Ruby-version
$ ruby -rpp -e 'pp YAML::load(File.open("/tmp/a.yml"))["development"]' , eller du kan prøve det samme i IRB-eller Python konsollen.

Bemærk, at i ovenstående kodestykke, alt er andre end produktionen placering er ens i udvikling og produktion del. Det er her yml node identifikator kommer til undsætning. Ideen er enkel have et sæt af standardværdier og tilsidesætte dem på andet sted.
Du kan trække det fra hinanden som følger:

  standardindstillingerne: & defaults
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAME: afsender
     smtp_server: din_server
     login: your_login
     Password: top_secret
 udvikling:
   <<: * Defaults
 produktion:
   <<: * Defaults
   output_location: prod_location 


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

Fantastisk, det virker (tm)!.
Formentlig har vi handlet nogle klarhed for lidt magi. Her er en lille forklaring: &, * og <<: & som er ankerkode kan forstås som node identifikator, * er node reference og <<: står for hash fusionere.

For flere detaljer se enten yaml specs eller wikipedia
Så langt så godt men der er en fangst her, disse hash fusionerer er ikke rekursive. Hvad det betyder er dette: Lad os sige du vil have forskellige afsenderens navn for e-mails i to miljøer, kan du blive fristet til at gøre følgende:

  standardindstillingerne: & defaults
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAME: afsender
     smtp_server: din_server
     login: your_login
     Password: top_secret
 udvikling:
   <<: * Defaults
   mail:
     SENDER_NAME: sender_dev
 produktion:
   <<: * Defaults
   output_location: prod_location
   mail:
     SENDER_NAME: sender_prod 

Lad os kontrollere

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

Ups, noget gik galt, problemet som nævnt ovenfor er, at hash fletningen ikke er rekursive, og samtidig at lægge det sammen erstattet post af misligholdelse fra mail den produktion, som kun har en nøgle. Løsning / arbejde omkring er at oprulle endnu et niveau:

  common_settings: & common_settings
 input_location: common_input
 output_location: dev_location
 mail_defaults: & mail_defaults
  SENDER_NAME: afsender
   smtp_server: din_server
   login: your_login
   Password: top_secret

 standardindstillingerne: & defaults
   <<: * Common_settings
   mail:
     <<: * Mail_defaults
 udvikling:
   <<: * Defaults
 produktion:
   <<: * Defaults
   mail:
     <<: * Mail_defaults
     SENDER_NAME: sender_prod

Lets check igen

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

Vidste du siger du har en mere lige af nesting, godt du kan helt sikkert oprulle en mere lige, men så bliver det noget rod. Så hvis du ikke forsøger at skrive løsningen på tårnene i Hanoi i en conf-fil, er det bedre at restucture conf fil end at grave i yaml eller noget andet. Men det er dit opkald alligevel.