lunes, 29 de diciembre de 2008

Código duplicado en Ruby

En mi anterior trabajo, las raras veces que entre reunión y documento y reunión me dejaban trabajar un rato, una de las herramientas imprescindibles para mi en Netbeans era PMD, tanto para detectar errores como para intentar hacer mejor código.

Netbeans da algunas sugerencias de código en Ruby, subraya las variables no usadas, pone en negrita las variables/métodos no definidos,... pero todavía le falta para llegar al nivel de PMD en Java.

He estado buscando a ver si hay algo parecido para Ruby y dentro de PMD he encontrado que tiene un módulo para detectar código duplicado: Copy paste detector que se puede ejecutar desde linea de comando o usando Java Web Start.

Dependiendo del tamaño del bloque repetido a buscar a veces da un

java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.get(Unknown Source)
at net.sourceforge.pmd.cpd.SourceCode.getSlice(SourceCode.java:133)
at net.sourceforge.pmd.cpd.MatchAlgorithm.findMatches(MatchAlgorithm.java:84)


Pero jugando un poco con el tamaño funciona y he encontrado unos cuantos trozos de código a refactorizar :-)

Y como ejemplo, la salida que da al ejecutarlo sobre el directorio rails. Con un tamaño de chunk menor de 60 da la excepción anterior, pero con un tamaño mayor funciona bien, y sólo encuentra duplicados en los test y en ficheros de zonas horarias, así que parece que por lo que respecta a código duplicado, rails está bien hecho :-)


jueves, 11 de diciembre de 2008

Curioso comportamiento de nil.id

En un trozo de código similar a este:

user_id = User.find_by_email(email).id rescue nil
if user_id.nil?
....


Me he vuelto a encontrar otra vez con un curioso comportamiento. En desarrollo funciona bien, pero en producción devuelve un user_id incorrecto en lugar de un nulo cuando el usuario no existe.

Es debido la forma de acceder del objeto nil a su atributo id. En modo desarrollo devuelve una excepción, pero en cambio en modo producción, sólo da un warning

$ ruby script/console
Loading development environment (Rails 2.1.2)
>> nil.id
RuntimeError: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
from (irb):1
>> exit
$ ruby script/console production
Loading production environment (Rails 2.1.2)
>> nil.id
(irb):1: warning: Object#id will be deprecated; use Object#object_id
=> 4


La solución es muy simple, o acceder al objeto a traves de []

user_id = User.find_by_email(email)[:id] rescue nil
if user_id.nil?
....


o acceder al id despues de comprobar el nil

user = User.find_by_email(email)
if user.nil?

Es algo trivial, pero a ver si escribiéndolo no me vuelve a pasar... :-p