Unione di hash in conf YAML

31 luglio 2009 da Prashant · Comments
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 è flat (senza gerarchia) e non ha ripetizioni.
Se il file di configurazione ha ripetizioni allora ha senso per separare gli 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: Your_Server
     Login: login_personale
     password: top_secret
 produzione:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Your_Server
     Login: login_personale
     password: top_secret 

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

 #! / Usr / bin / env python
 dal pprint import pprint come pp
 # In debian è necessario installare python-YAML
 da YAML carico importazione, 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'). leggere)
 pp hash ['sviluppo'] 

ecco un pratico uno di linea per la versione ruby
$ 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 percorso di output è lo stesso in fase di sviluppo e parte della produzione. Questo è dove identificatore di nodo yml viene in soccorso. Idea è semplice avere un insieme di valori predefiniti e li modifichi in luogo diverso.
Si può scomporre come segue:

  default: default e
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAME: mittente
     smtp_server: Your_Server
     Login: login_personale
     password: top_secret
 sviluppo:
   <<: * Le impostazioni predefinite
 produzione:
   <<: * Le impostazioni predefinite
   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 po 'di chiarezza per un po' di magia. Ecco una piccola spiegazione: &, * e <<: e che è tag di ancoraggio può essere inteso come identificatore di nodo, * è il nodo di riferimento e <<: sta per unione 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. Che cosa significa è 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: Your_Server
     Login: login_personale
     password: top_secret
 sviluppo:
   <<: * Le impostazioni predefinite
   mail:
     SENDER_NAME: sender_dev
 produzione:
   <<: * Le impostazioni predefinite
   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 di come si è detto è che l'unione hash non è ricorsiva e, mentre la fusione ha sostituito posta elettronica di default per posta di produzione che ha una sola chiave. Soluzione / lavoro intorno è quello di svolgere 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: Your_Server
   Login: login_personale
   password: top_secret

 default: default e
   <<: * Le common_settings
   mail:
     <<: * Le mail_defaults
 sviluppo:
   <<: * Le impostazioni predefinite
 produzione:
   <<: * Le impostazioni predefinite
   mail:
     <<: * Le 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 di avere un altro livello di nidificazione, e si può sicuramente svolgere un livello di più, ma poi diventa un casino. Quindi, se non si tenta di scrivere la soluzione alle torri di Hanoi in un file di configurazione, è meglio restucture file di configurazione che scavare in yaml o qualcos'altro. Ma questa è la chiamata comunque.