Mesclando hashes em 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 esses 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
     senha: top_secret
 produção:
   input_location: common_input
   output_location: dev_location
   mail:
     smtp_server: Your_Server
     login: your_login
     senha: top_secret 

Supondo que o 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 em pp
 # No debian precisa instalar python-yaml
 yaml de importação, despejo load_all carga,
 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)
 de hash pp ['desenvolvimento'] 

aqui é um forro de uma mão para a versão 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 do local de saída é a mesma no desenvolvimento e na parte de produção. Este é o lugar onde identificador do 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 e padrões:
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAME: remetente
     smtp_server: Your_Server
     login: your_login
     senha: top_secret
 desenvolvimento:
   <<: * Os padrões
 produção:
   <<: * Os padrões
   output_location: prod_location 


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

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

Para mais detalhes veja tanto especificações yaml ou wikipedia
Até aí tudo bem, mas há um problema aqui, estas fusões de hash não são recursivas. O que isso 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 e padrões:
   input_location: common_input
   output_location: dev_location
   mail:
     SENDER_NAME: remetente
     smtp_server: Your_Server
     login: your_login
     senha: top_secret
 desenvolvimento:
   <<: * Os padrões
   mail:
     SENDER_NAME: sender_dev
 produção:
   <<: * Os padrões
   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
$

Opa, algo deu errado, como já mencionado problema é 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 / trabalho em torno é 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
   senha: top_secret

 padrões e padrões:
   <<: * Common_settings
   mail:
     <<: * Mail_defaults
 desenvolvimento:
   <<: * Os padrões
 produção:
   <<: * Os padrões
   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"
$

Será que você diz que tem um nível de aninhamento mais, bem, 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 conf, é melhor restucture arquivo conf de cavar yaml ou qualquer outra coisa. Mas isso é a chamada de qualquer maneira.