Ruby on Rails Inflector en español

lunes, junio 22, 2009

El módulo Inflectors de Ruby on Rails transforma palabras de singular a plural, nombres de clases a nombres de tablas, nombres de clases a claves foráneas, entre otros. Sin embargo éste módulo no soporta pluralización en español.

Si quieremos reemplazar la pluralización que trae por defecto Rails (inglés) y crear la nuestra en español solo debemos agregar estas reglas al final del archivo config/environment.rb:

# Limpiamos todas las inflecciones existentes
Inflector.inflections.clear

# Agregamos las reglas de inflección
Inflector.inflections do |inflect|
inflect.plural /([taeiou])([A-Z]|_|\$)/, '\1s\2'
inflect.plural /([rlnd])([A-Z]|_|$)/, '\1es\2'
inflect.singular /([taeiou])s([A-Z]|_|$)/, '\1\2'
inflect.singular /([rlnd])es([A-Z]|_|$)/, '\1\2'
end

La primera regla dice algo como: "Todas las palabras que terminen en t, a, e, i, o, u y que luego tengan una letra mayúscula, un underscore o un fin de línea entonces se pluralizan con S", mientras que la segunda regla dice: "Todas las palabras que terminen en r, l, n, d y que luego tengan una letra mayúscula, un underscore o un fin de línea entonces se pluralizan con ES". Las reglas tres y cuatro se interpretan siguiendo el mismo criterio pero de forma inversa. Así, "casa" se pluraliza como "casas" y "canción" se pluraliza como "canciones".

Dejaré como tarea para el lector estudiar de manera detallada las expresiones regulares usadas en las reglas, pero les dejaré una pista:
Es necesario recordar que en una expresión regular los paréntesis son signos de agrupación y cada expresión entre paréntesis corresponde a un grupo. Se puede hacer referencia a la expresión asociada a un grupo mediante una barra invertida "\" y el número del grupo. Es por eso que en la expresión regular del Inflector se usa el \1 y el \2

Con el código anterior ya tenemos configurada nuestra pluralización en español. Podemos probarla agregando el código a un proyecto existente y abriendo una consola de Rails:
$ cd proyecto_existente_de_rails
$ script/console
Loading development environment.
>>'prueba'.pluralize
=> "pruebas"

Observamos que ahora el string 'prueba' está en plural. Sin embargo existe un bug en la versión 1.2.6 de Rails (quizás esté corregido en las versiones posteriores pero aún no lo he confirmado) y es que si intentamos pluralizar un string que contenga expresiones que cumplan ambos patrones del inflector entonces obtendremos una sola palabra pluralizada, por ejemplo:
>>'prueba_cancion'.pluralize
=> "prueba_canciones"

Se debe extender la clase Inflector y modificar los métodos pluralize y singularize. El código lo podemos insertar en el mismo archivo config/environment.rb y sería algo como:

# Extender la clase Inflector
module Inflector
def pluralize(word)
result = word.to_s.dup

if word.empty? || inflections.uncountables.include?(result.downcase)
result
else
inflections.plurals.each { |(rule, replacement)| result.gsub!(rule, replacement) }
result
end
end

def singularize(word)
result = word.to_s.dup
if inflections.uncountables.include?(result.downcase)
result
else
inflections.singulars.each { |(rule, replacement)| result.gsub!(rule, replacement) }
result
end
end
end

Si revisamos el código fuente de los métodos pluralize y singularize veremos que la diferencia está en la instrucción break if en las líneas 112 y 132 respectivamente:
112:   inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
...
132: inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }

Solo debemos eliminar ese par de instrucciones para que entonces la regla sea aplicable a más de un patrón al mismo tiempo.

Por los momentos es todo. Espero sea de utilidad este pequeño pero interesante tip