Hash fusione nei file YAML conf

31 lug 2009 da Prashant · Commenti
Archiviato in: Tecnologia

YAML è abbastanza comoda per la scrittura di file di configurazione. Vantaggio principale è che, si legge come file di testo. Questo funziona molto bene se il vostro file di configurazione è piatto (senza gerarchia) e non ha ripetizioni.
Se il file di configurazione è ripetizioni allora ha senso separare quegli elementi e riutilizzarli. Quello che voglio dire è questo - diciamo che il file di configurazione simile a questa:

  sviluppo:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Nome_server
     Login: login_personale
     password: top_secret
 produzione:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Nome_server
     Login: login_personale
     password: top_secret 

Supponendo che il codice sopra in / tmp / test.yml ecco come si può leggere in Python e Ruby
$cat readyml.py

 #! / Usr / bin / env python
 da pprint importazione pprint come pp
 # In debian è necessario installare python-YAML
 dal carico importazione YAML, load_all, discarica
 hash = carico (open ('/ tmp / test.yml'))
 pp (hash ['sviluppo']) 


$ cat readyml.rb

  #! / Usr / bin / env ruby
 require 'pp'
 hash = YAML:: Load (File.open ('/ tmp / test.yml') leggi.)
 pp hash ['sviluppo'] 

ecco un pratico rivestimento per uno rubino versione
$ ruby -rpp -e 'pp YAML::load(File.open("/tmp/a.yml"))["development"]' o si può provare lo stesso in irb o console python.

Si noti che nel frammento di codice di cui sopra, tutto è diverso da luogo di uscita è lo stesso in parte, sviluppo e produzione. Questo è dove identificatore nodo yml viene in soccorso. Idea è semplice avere un insieme di valori predefiniti e sostituire a loro posto diverso.
Si può scomporre come segue:

  default: default e
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAME: mittente
     smtp_server: Nome_server
     Login: login_personale
     password: top_secret
 sviluppo:
   <<: * Default
 produzione:
   <<: * Default
   output_location: prod_location 


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

Grande, funziona (tm)!.
Probabilmente abbiamo scambiato qualche chiarezza per un po 'di magia. Ecco una piccola spiegazione: &, * e <<: e che è tag di ancoraggio può essere inteso come identificativo del nodo, * è il nodo di riferimento e <<: sta per fondersi hash.

Per maggiori dettagli vedere sia le specifiche YAML o wikipedia
Fin qui tutto bene ma c'è un fermo qui, queste si fonde hash non sono ricorsivi. Cosa vuol dire è questo: diciamo che si desidera avere altro nome del mittente per la posta in due ambienti, si può essere tentati di fare quanto segue:

  default: default e
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAME: mittente
     smtp_server: Nome_server
     Login: login_personale
     password: top_secret
 sviluppo:
   <<: * Default
   mail:
     SENDER_NAME: sender_dev
 produzione:
   <<: * Default
   output_location: prod_location
   mail:
     SENDER_NAME: sender_prod 

Consente di controllare

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

Oops, qualcosa è andato storto, il problema come detto sopra è che l'unione hash non è ricorsiva e, mentre la fusione che ha sostituito posta elettronica di default per posta di produzione che ha una sola chiave. Soluzione / risolvere è quello di srotolare un livello di più:

  common_settings: & common_settings
 input_location: common_input
 output_location: dev_location
 mail_defaults: & mail_defaults
  SENDER_NAME: mittente
   smtp_server: Nome_server
   Login: login_personale
   password: top_secret

 default: default e
   <<: * Common_settings
   mail:
     <<: * Mail_defaults
 sviluppo:
   <<: * Default
 produzione:
   <<: * Default
   mail:
     <<: * Mail_defaults
     SENDER_NAME: sender_prod

Consente di controllare di nuovo

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

Hai detto che hai un ulteriore livello di nidificazione, così si può sicuramente svolgere un livello di più, ma poi diventa un casino. Quindi, se non si sta cercando di dare soluzione alle torri di Hanoi in un file di configurazione, è meglio restucture file di conf che scavare in yaml o qualcos'altro. Ma questa è la tua chiamata comunque.