Recentemente, vi uma discussão no grupo de emails “rails-br” sobre como extender a classe String em uma aplicação Ruby on Rails. Na Tagview, costumamos utilizar muito este recurso em nossos projetos e acredito que fazemos isto de uma maneira bastante limpa e legível. Neste post vou detalhar este processo.

Vou utilizar no exemplo um código que adiciona um método à classe String. Mas, gostaria de ressaltar que podemos extender qualquer classe do Ruby ou do Rails com este mesmo procedimento. Suponha que queremos adicionar um método de instância à classe String. Este método retornará a própria string, mas sem acentos. Vamos chamo-lo de “no_accent”. Lembrando que nem Ruby nem Rails implementam algum método que faça isto.

Primeiramente, vamos definir um módulo que contenha este nosso método. Vamos chamá-lo de “StringExtensions”.

module StringExtensions
  def no_accent
    self.
        gsub(/á/,  'a').     # à => a
        gsub(/á/,  'a').     # á => a
        gsub(/â/,  'a').     # â => a
        gsub(/ã/,  'a').     # ã => a
        gsub(/é/,  'e').     # é => e
        gsub(/ê/,  'e').     # ê => e
        gsub(/í/,  'i').       # í => i
        gsub(/ó/,  'o').     # ó => o
        gsub(/ô/,  'o').     # ô => o
        gsub(/ã/,  'o').     # õ => o
        gsub(/ú/,  'u').     # ú => u
        gsub(/ü/,  'u').     # ü => u
        gsub(/ç/,  'c').      # ç => c
        gsub(/À/,  'A').     # À => A
        gsub(/Á/,  'A').     # Á => A
        gsub(/Â/,  'A').     # Â => A
        gsub(/Ã/,  'A').     # Ã => A
        gsub(/É/,  'E').      # É => E
        gsub(/Ê/,  'E').      # Ê => E
        gsub(/Í/,  'I').        # Í => I
        gsub(/Ó/,  'O').     # Ó => O
        gsub(/Ô/,  'O').     # Ô => O
        gsub(/Õ/,  'O').     # Õ => O
        gsub(/Ú/,  'U').      # Ú => U
        gsub(/Ü/,  'U').      # Ü => U
        gsub(/Ç/,  'C')       # Ç => C
  end
end

Agora, basta incluir este módulo na classe String, certo? Sim, porém isto não é tão simples. O método de classe “include” é privado. Uma técnica interessante para burlar este problema é o uso do método “send” em cima do objeto que representa a classe String. Este método não é privado e aceita como argumentos: um método a ser chamado e os parametros a serem passados para este método. Assim, podemos incluir nosso módulo StringExtensions a classe String com o seguinte código:

String.send :include, StringExtensions

Para adicionar toda esta lógica à nossa aplicação basta criarmos um arquivo string_extensions.rb na pasta “config/initializers”. Neste arquivos adicionaremos nosso módulo e na última linha o código acima. Quando a aplicação for executada os arquivos “.rb” desta pasta serão executados em ordem alfabética e para toda string de nossa aplicação poderemos chamar o método “no_accent”.

Esta é uma dica bastante simples porém muito útil. Extender classes pode ser um ótimo começo para um código mais clean, facil de manter e componentizável (imagine que em um próximo projeto RoR você pode reutilizar seus initializers).

Abraços e até a próxima!