Carregar dinamicamente tokens de configuração usando a mágica de metaprogramação do Ruby

Então, digamos que você precise usar tokens em seu aplicativo para acessar uma API de terceiros (como Twitter, Instagram ou Facebook). Em tutoriais de gemas Ruby, é muito comum ver o seguinte código de exemplo para carregar esses tokens:

module Facebook
CONFIG
= YAML.load_file(Rails.root.join("config/facebook.yml"))[Rails.env]
APP_ID
= CONFIG['app_id']
SECRET
= CONFIG['secret_key']
end

Ele foi extraído do wiki de gem do Koala no GitHub . Ou o seguinte, que foi extraído do arquivo README do repositório GitHub do Instagram gem.

Instagram.configure do |config|
config
.client_id = "YOUR_CLIENT_ID"
config
.client_secret = "YOUR_CLIENT_SECRET"
end

É uma prática muito feia codificar coisas como esta, IMHO.

Agora, a prática mais recomendada e usada na natureza é ter esses tokens de acesso de API em um arquivo YAML, para que possa ser carregado em nosso aplicativo, como o código de exemplo do Koala acima. O formato é o seguinte:

...
twitter
:
consumer_key
: YOUR_CONSUMER_KEY
consumer_secret
: YOUR_CONSUMER_SECRET
oauth_token
: YOUR_OAUTH_TOKEN
oauth_token_secret
: YOUR_OAUTH_TOKEN_SECRET
...

Como você deve saber, este arquivo é carregado como um arquivo Hash. Assim, podemos acessar cada chave e valor.

Agora, usando a mágica de metaprogramação do Ruby, podemos carregar cada chave do arquivo e usá-la na seção de configuração da gema. Como? Usando o método..send()

CONFIG = YAML.load_file(Rails.root.join("config", "settings.yml"))[Rails.env]

Twitter.configure do |twitter|
CONFIG
['twitter'].each_key do |key|
twitter
.send("#{key}=", CONFIG['twitter'][key])
end
end

O segredo é nomear cada chave na seção do arquivo YAML exatamente como o nome da chave de configuração da gema, para que não haja nenhum method_missingerro.

Você pode encontrar mais informações sobre o método na página de documentação Ruby ..send()