O excelente blog Code Commit publicou um artigo interessante sobre linguagens de programação: como podemos definir se uma linguagem é de baixo, médio ou alto nível?

O post apresenta as principais características de cada nível e as dificuldades de se classificar as linguagens num nível específico, e inclui um gráfico apontando a classificação de algumas das linguagens mais populares, de acordo com a experiência do autor. Muito interessante.


Esta semana me deparei com uma situação no projeto em Rails em que estou trabalhando, onde necessitei acessar um banco de dados de outra aplicação, para fazer algumas consultas simples. Eu poderia simplesmente fazer a conexão com o banco e as querys em SQL. Porém, eu obviamente queria aproveitar as facilidades que o Rails proporciona ao abstrair estes detalhes com a classe ActiveRecord::Base.

Quando criamos um novo model em Rails, a nova classe criada, derivada de ActiveRecord::Base, é mapeada por padrão em uma tabela no banco de dados da aplicação - o Rails assume o nome da classe no plural, mas permite que você especifique um nome diferente. Na migration que também é criada automaticamente, a tabela correspondente é definida. Porém, neste caso, eu não queria criar uma tabela, pois ela já existe. Além disso, é um servidor de banco de dados diferente, com usuário e senha diferentes.

Após alguma pesquisa, descobri como resolver este problema. Suponha que você queira acessar uma base de usuários para compartilhar login e senha:

  1. especificar a nova conexão no arquivo config/database.yml. No exemplo abaixo, defini o nome autenticacao_development, supondo que tenhamos outras conexões para teste e produção:
autenticacao_development:
  adapter: mysql
  host: autenticacao_dev
  username: login
  password: senha
  database: autenticacao
  1. criar uma classe abstrata (model), derivada de ActionRecord::Base, e usar o método establish_connection para referenciar a conexão. O parâmetro autenticacao_#{RAILS_ENV} usa a variável RAILS_ENV para especificar a conexão relativa ao ambiente (autenticacao_development, autenticacao_test ou autenticacao_production):
class AutenticacaoDatabase < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "autenticacao_#{RAILS_ENV}"
end
  1. para cada tabela deste banco de dados que será acessada, criar uma nova classe (model) derivada da classe AutenticacaoDatabase recém-criada. Caso o nome da tabela seja diferente do padrão (o nome da classe no plural), use o método set_table_name para especificar o nome correto. E se a primary key não for id, use set_primary_key para definir o nome correto deste campo.
class Usuario < AutenticacaoDatabase
  set_table_name 'usuario_tb'
  set_primary_key 'usuario_id'
end

Feitas as configurações acima, o banco de dados externo ficará acessível como o da aplicação, com todos os métodos usados normalmente. Por exemplo:

Usuario.find(:all)
Usuario.find_by_usuario_id(1)
Usuario.create

Detalhe importante: com esta configuração, é necessário fazer uma série de alterações nos unit tests para que estes funcionem. Em breve farei outro post detalhando estes passos.

Seguem abaixo os links que eu usei como base:


Uma das principais características do Ruby é ser uma linguagem dinâmica, o que significa que a tipagem é dinâmica, ou seja, a linguagem permite que uma variável seja usada sem ser previamente declarada, assuma um valor de uma classe qualquer e depois possa ter seu valor alterado para um objeto de outra classe.

Apesar da simplicidade que esta característica traz, frequentemente precisamos verificar o tipo de classe de uma variável, para termos certeza de que em uma chamada de função não é passada uma variável contendo um objeto de uma classe diferente da esperada, por exemplo. Isto não é necessário em linguagens como C e Java, onde cada variável precisa ser declarada antes do uso, e na declaração é necessário especificar o tipo de variável.

Este artigo apresenta um módulo Ruby chamado Types, que simplifica bastante o trabalho de verificação do tipo de classe passado em cada parâmetro de uma função. É possível, inclusive, verificar se a classe passada implementa um método específico. Qualquer tipo de verificação é feito acrescentando-se uma linha antes da definição da função, eliminando a necessidade de verificarmos o tipo de cada parâmetro no código da função. Não cheguei a testar o módulo ainda, porém, de acordo com o artigo, parece ser uma solução muito simples e flexível para problemas de tipagem.


Um dos princípios do desenvolvimento em Rails é o DRY (don’t repeat yourself). A idéia é que você nunca repita o código que já escreveu uma vez, procurando reaproveitar sempre que possível.

No caso das views, por exemplo, isso é bem simples de implementar, através do uso de partials. Você deve criar um arquivo de view começando com “_” (ex: _item.rhtml) e usar o comando render em outra view para carregar o partial dentro do layout (ex: render :partial => 'item').

Outro dia descobri uma maneira muito interessante de usar essa técnica no arquivo database.yml. Esse arquivo mantém as configurações de banco de dados para cada um dos ambientes - development, test e production. Porém, geralmente alguns destes parâmetros de configuração são iguais. O adapter, por exemplo, muito provavelmente é o mesmo; o username, senha e host também podem se repetir.

Segue abaixo um exemplo de como definir estas configurações sem repetições:

login: &login
  adapter: mysql
  username: username
  password: password
  host: mysql.example.com

development:
  <<: *login
  database: app_dev

test:
  <<: *login
  database: app_test

production:
  <<: *login
  database: app_prod

Só encontrei um problema: se você usar o Aptana RadRails para desenvolver, usando essa técnica, o modo “Data perspective”, que permite analisar a estrutura do banco de dados e executar querys, retorna uma mensagem de erro (“Invalid YML syntax”). Fora isso, está tudo funcionando bem. No NetBeans não há este problema.


Um detalhe muito incômodo no Ubuntu é que as configurações de rede realizadas através da opção “Network” (no menu System -> Administration) não são permanentes. Qualquer alteração realizada no endereço IP, gateway, DNS ou domínios é perdida após um reboot. Se você editar as configurações de uma interface de rede via ifconfig, o mesmo problema ocorrerá. Não sei se isso é um bug ou uma característica desejada, mas eu acho muito inconveniente.

Para tornar as configurações de rede permanentes, você deve editar os seguintes arquivos (como root ou sudo):

  • Configurações de DNS: arquivo /etc/dhcp3/dhclient.conf. Para definir servidores DNS, retire o comentário da linha prepend domain-name-servers e acrescente os IPs após 127.0.0.1, separados por espaço. Para definir domínios de busca, retire o comentário da linha supersede domain-name e digite os domínios entre aspas, separados por espaço;

  • Configurações de interface de rede: arquivo /etc/network/interfaces. Para configurar a interface eth0, por exemplo, acrescente as seguintes linhas no final do arquivo, substituindo os endereços IP pelos valores correspondentes:

auto eth0
iface eth0 inet static
address 192.168.254.3
netmask 255.255.255.0
gateway 192.168.254.254

Após concluir as alterações, reinicie o serviço de rede com o comando /etc/init.d/networking restart.