Hashes fusão em arquivos de conf yaml

31 de julho de 2009 por prashant · Comentários
Arquivado em: tecnologia

YAML é bastante útil para gravação de arquivos de configuração. Principal vantagem é que, lê-se como arquivo de texto. Isso funciona muito bem se o seu arquivo de configuração é plana (sem hierarquia) e não tem repetições.
Se o seu arquivo de configurações tem repetições então faz sentido para separar os elementos e reutilizá-los. O que quero dizer é isso - vamos dizer que você seu arquivo de configuração parecida com esta:

  desenvolvimento:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Your_Server
     login: your_login
     password: top_secret
 produção:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Your_Server
     login: your_login
     password: top_secret 

Assumindo código acima em / tmp / test.yml aqui está como você pode ler em python e ruby
$cat readyml.py

 #! / Usr / bin / env python
 de pprint pprint importação pp
 # No debian precisa instalar python-yaml
 yaml de carga de importação, load_all, despejo
 hash = carga (open ('/ tmp / test.yml'))
 pp (hash ['desenvolvimento']) 


$ cat readyml.rb

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

aqui é um forro de uma versão acessível para ruby
$ ruby -rpp -e 'pp YAML::load(File.open("/tmp/a.yml"))["development"]' ou você pode tentar o mesmo em irb ou console python.

Note-se que no trecho de código acima, tudo é diferente de local de saída é o mesmo, em parte, desenvolvimento e produção. Este é o lugar onde identificador de nó yml vem resgatar. Idéia é simples ter um conjunto de valores padrão e substituí-los em lugar diferente.
Você pode puxá-lo para além da seguinte forma:

  padrões: padrões &
   input_location: common_input
   output_location: dev_location
   mail:
     sender_name: remetente
     smtp_server: Your_Server
     login: your_login
     password: top_secret
 desenvolvimento:
   <<: * Defaults
 produção:
   <<: * Defaults
   output_location: prod_location 


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

Grande, ele funciona (tm)!.
Indiscutivelmente nós trocamos um pouco de clareza para um pouco de magia. Aqui está uma pequena explicação: &, * e <<: & que é tag de âncora pode ser entendida como identificador de nó, * é referência nó e <<: stands para fundir hash.

Para mais detalhes veja ou especificações yaml ou wikipedia
Até aqui tudo bem, mas há um problema aqui, essas fusões não são de hash recursiva. O que significa é o seguinte: digamos que você quer ter nome de remetente diferente para o correio em dois ambientes, você pode ser tentado a fazer o seguinte:

  padrões: padrões &
   input_location: common_input
   output_location: dev_location
   mail:
     sender_name: remetente
     smtp_server: Your_Server
     login: your_login
     password: top_secret
 desenvolvimento:
   <<: * Defaults
   mail:
     sender_name: sender_dev
 produção:
   <<: * Defaults
   output_location: prod_location
   mail:
     sender_name: sender_prod 

Vamos verificar

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

Oops, algo deu errado, problema, como mencionado acima é que a junção de hash não é recursivo e enquanto fundindo-substituído e-mail de incumprimento por e-mail da produção que tem apenas uma chave. Solução / solução é para desenrolar mais um nível:

  common_settings: & common_settings
 input_location: common_input
 output_location: dev_location
 mail_defaults: & mail_defaults
  sender_name: remetente
   smtp_server: Your_Server
   login: your_login
   password: top_secret

 padrões: padrões &
   <<: * Common_settings
   mail:
     <<: * Mail_defaults
 desenvolvimento:
   <<: * Defaults
 produção:
   <<: * Defaults
   mail:
     <<: * Mail_defaults
     sender_name: sender_prod

Vamos verificar novamente

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

Você disse que você tem mais um nível de aninhamento, assim você pode definitivamente desenrolar mais um nível, mas depois torna-se uma bagunça. Então, se você não está tentando escrever solução para torres de Hanói em um arquivo de conf, é melhor restucture arquivo conf de cavar yaml ou outra coisa. Mas isso é a chamada de qualquer maneira.