La última moda en programación Web se llama Ruby on Rails. No descubro nada a estas alturas, Ruby on Rails es un entorno perfecto para desarrollar proyectos web, como intentan copiar otros frameworks con mayor o menor éxito.
Me incita a escribir esta entrada (y de ahí el título del post) una comparativa que me viene a la cabeza con la época hippie de los años 60. La revolución sexual de aquellos años contrastaba con el régimen conservador y se reveló contra él, de la misma forma casi que Ruby se revela contra otros lenguajes más “estrictos”. La comparativa viene al caso porque al igual que los abusos de aquellos años de droga, sexo y rock’n'roll con Ruby también se pueden cometer excesos.
Ruby introduce no sólo un lenguaje de programación, sino toda una forma de hacer las cosas, “The Ruby Way” que llaman los entendidos. Esto es cierto, sin llegar a ser un cambio de paradigma, se tiene que pensar de forma diferente en Ruby. Todos los manuales existentes insisten en que el propio lenguaje te fuerza a hacer las cosas de forma diferente, pero continuamente veo que no es así.
Por ejemplo, continuamente veo código Ruby que mantiene los mismos patrones de programación de… pongamos PHP. Por ejemplo:
def temp_dirname chars = %w{a b c d e f g h i j k l m n o p q r s t u v w x y z} rand_max = chars.size ret = "" 16.times { ret << chars[rand(rand_max)] } ret end
El método anterior devuelve una cadena aleatoria para ser usada como nombre en un fichero temporal. Evidentemente, desde la primera línea se ve que se ha programado con la intención de seguir un patrón no-ruby, creando una variable temporal “ret” como cadena para ir concatenando caracteres aleatoriamente de la tabla abecedario creada anteriormente. Lo único “Ruby-Way” del código anterior es el uso de 16.times, pero seguro que si Ruby tuviera un for(x;x<y;x++) se usaría.
Esto no se tiene que hacer así. Ruby da para más. El problema de lo anterior es que no queda “claro” desde un primer momento lo que hace el método. Si, seguro que gastando 5 minutos de tiempo se llega a la conclusión de lo que hace, y tienes que ser un programador medio avezado para ver instantáneamente lo que hace la operación chars[rand(rand_max)].
Lo anterior podría haberse escrito de esta forma:
require 'digest/md5' def temp_dirname (Digest::MD5.hexdigest rand.to_s)[0..15] end
De acuerdo, aquí hemos introducido la librería “digest/md5″ para crear una cadena hash a partir de un número aleatorio, y luego extraemos los 16 primeros carácteres. Pero aún así, es más fácil de entender que las 5 líneas anteriores.
Podemos evolucionar más y hacerlo aún más “Rubyist” usando varios conceptos exclusivos de Ruby. Vamos a eliminar la dependencia de la librería de MD5 y volvemos al array abecedario, pero vamos a hacerlo DRY (Don’t Repeat Yourself) y KISS (Kept It Simple, Stupid):
class Array def any self.[] rand(length) if length end end class String @@temptemp = %w{a b c d e f g h i j k l m n o p q r s t u w x y z} def tempname! 16.times { self << @@temptemp.any } self end end
OK, nos aprovechamos de poder “extender” los objetos nativos de Ruby para añadir dos métodos a las clases “Array” y “String”. En “Array”, añadimos el método “any” que nos devuelve, aleatoriamente cualquier elemento de un array. por ejemplo:
>> [1, 2, 3, 4].any => 1 >> [1, 2, 3, 4].any => 2 >> [1, 2, 3, 4].any => 4
Esto es DRY, hemos ampliado la clase Array para devolver cualquier elemento aleatorio de cualquier array. Por ejemplo:
>> String.methods.any => "display" >> String.methods.any => "untaint" >> String.methods.any => "private_class_method"
Después, hemos ampliado la clase String para añadir un método llamado “tempname” que nos añade, a cualquier string, una cadena aleatoria (basada en el Array#any anterior). Por ejemplo:
>> "".tempname! => "tyhbijuqhhjednmr" >> "/tmp/".tempname! => "/tmp/nykfurjyunojqykj" >> "/var/lib/temp/".tempname! => "/var/lib/temp/rdysjeymslkqwfar"
Lo de incluir una exclamación al final de tempname! es un consenso que usa Ruby de incluir una exclamación al final de los métodos que modifican de alguna forma el objeto sobre el que actua (vamos, que no devuelve nada, sino que modifica el propio objeto). Por otra parte, es como otro carácter y forma parte del nombre del método.
La conclusión de este post es que si te propones aprender Ruby, intentes mirar más allá de la sintaxis. “Code is Poetry”, como dirían algunos, y esto es mucho más verdad en Ruby.