Fusionerende hashes i YAML conf filer

31 Juli 2009 ved Prashant · Kommentarer
Filed under: teknologi

YAML er ganske praktisk til at skrive konfigurationsfiler. Primære fordel er, at den læser som tekstfil. Det fungerer rigtig godt, hvis din config fil er flad (ingen hierarki) og har ingen gentagelser.
Hvis din konfigurationer filen har gentagelser så giver det mening at udskille disse elementer og genbruge dem. Hvad jeg mener er dette - lad os sige, at 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 

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

 #! / Usr / bin / env python
 fra pprint indførsel pprint som pp
 # I debian nødt til at installere python-YAML
 fra YAML import belastning, load_all, dump
 hash = belastning (åben ('/ tmp / test.yml'))
 pp (hash ['udvikling']) 


$ cat readyml.rb

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

her er en handy en liner for 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 konsol.

Bemærk, at i ovenstående kodestykke, er alt andet end output placering er den samme i udvikling og produktion del. Det er her yml node id kommer til at redde. Ideen er enkel have et sæt standardværdier og tilsidesætter dem på andet sted.
Du kan trække det ud som følger:

  standarder: og standarder
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAMEs: afsender
     smtp_server: din_server
     login: your_login
     Password: top_secret
 udvikling:
   <<: * Standard
 produktion:
   <<: * Standard
   output_location: prod_location 


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

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

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

  standarder: og standarder
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAMEs: afsender
     smtp_server: din_server
     login: your_login
     Password: top_secret
 udvikling:
   <<: * Standard
   mail:
     SENDER_NAMEs: sender_dev
 produktion:
   <<: * Standard
   output_location: prod_location
   mail:
     SENDER_NAMEs: sender_prod 

Lad os kontrollere

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

Ups, noget gik galt, problem, som nævnt ovenfor er, at hash fletningen ikke er rekursiv, og samtidig lægge det erstattet post af misligholdelse af post produktion, som kun har en nøgle. Løsning / arbejde omkring at oprulle en mere niveau:

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

 standarder: og standarder
   <<: * Common_settings
   mail:
     <<: * Mail_defaults
 udvikling:
   <<: * Standard
 produktion:
   <<: * Standard
   mail:
     <<: * Mail_defaults
     SENDER_NAMEs: sender_prod

Lad os se igen

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

Sagde du du har en større niveau 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øsning tårne ​​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.