Publicidad:
La Coctelera

Sugerencia de presentación

He nacido para vago

28 Noviembre 2007

La magia de los bloques en Ruby y lo que molan Hpricot y Ser Vago (tm)

Un truquito pequeño y rápido, que igual le vale a alguien para algo, y su explicación, que probablemente le valga a más gente.

Un compañero me preguntó si había alguna forma automática de hacer la misma edición a unos cuantos archivos HTML (se trataba de borrar un div que tenían todos en la cabecera). Que si era una cosita que no llevara trabajo guay, que si no lo hacía a mano. Esas palabras me hicieron pensar que se trataría de unos 15 o 20, por lo que claramente merecía la pena. Cuando después de prepararlo lo pusimos en marcha resultó que eran más de 500. [Nota mental: ponerle nombre al número de cosas iguales y repetitivas que estás dispuesto a hacer antes de automatizar, y usarlo como índice de vagancia].

Como es algo que en un mundo lleno de maquetadores es medio normal, tratamos de hacer algo genérico y reutilizable, y aquí está.

Ingredientes:

  • Hpricot: una librería muy chula que sirve para parsear y modificar HTML (o XML ya que estamos). La interfaz es preciosa ya que además de otro tipo de formas de buscar en el HTML, soporta selectores CSS, así que las tareas simples son triviales, y las complejas, simples
  • Los bloques, una de las features para mí más chulas de Ruby como lenguaje, que pasaremos a explicar ahora, y que dan a este sistema lo que tiene de genérico y reutilizable

Estoy seguro de que hay un montón de lenguajes que soportan bloques o cosas parecidas. Lo que mola de los bloques en Ruby es que la interfaz es muy limpia, y puedes usarlos casi sin darte cuenta.

Un bloque es un tipo de parámetro (que ha de ser el último, e ir marcado con &) que se puede pasar a un método, y que consiste en un fragmento de código, que el método podrá ejecutar cuando desee (con yield). De esta forma se puede flexibilizar un montón los métodos, dejando parte de la implementación a cargo del que llama (no del que define).

Como toda definición, es un poco críptica y seguro que se entiende mejor con un ejemplo:

 def rodear_de_asteriscos(&block)
   puts "*********"
   yield
   puts "*********"
 end
 rodear_de_asteriscos do
   puts "Esta parte la decido yo"
 end
 

Os hacéis idea de lo que hace, ¿no?

Este ejemplo es muy sencillo, simplemente ejecuta el código, una vez e incondicionalmente, pero podríamos hacer lo que quisiéramos, como eso, poner condiciones, ejecutarlo varias veces, o pasarle parámetros (ahora vemos la sintaxis para hacer esto).

En nuestro caso lo que queríamos era iterar sobre una lista de archivos, e irlos abriendo uno por uno, realizar ciertas modificaciones en cada uno de ellos, y guardarlos. Eso de realizar ciertas modificaciones es carne de bloque, porque lo normal es que quien sepa qué modificaciones se han de realizar sea quien llama al método (nuestro amigo maquetador que hace sus pinitos programando), y no quien lo define (yo).

Así que ésta es la implementación:

 require 'rubygems'
 require 'hpricot'
 def update_files(glob_expression, &block)
   Dir.glob(glob_expression).each do |file|
     puts file
     doc = open(file) { |f| Hpricot(f) }
     yield(doc)
     open(file, File::TRUNC|File::RDWR) do |f|
       f.write(doc.to_html)
     end
   end
 end
 

Como dijimos, en primer lugar buscamos los archivos que concuerden con la expresión que nos pasen como primer parámetro (cosas como *.html), e iteramos por esa lista. En cada iteración, abrimos el archivo y creamos un objecto Hpricot con el contenido, y después, ejecutamos el bloque pasándole como parámetro el objeto Hpricot. De esa forma, en la llamada al método, nuestro usuario podrá escribir código usando ese objeto. Finalmente, volveremos a abrir el archivo, esta vez para escribir en él el contenido del objeto Hpricot una vez ejecutado el código del bloque (que supuestamente lo modificará).

¿Muy complicado otra vez? Así sería un ejemplo del uso de este método:

 update_files('public/*/themes/*/example/example.html') do |doc|
   doc.search("div#theshaker_headercommunity_logo").remove
 end
 

De esta forma nuestro script diábólico que busque y abra archivos y los modifique está separado claramente en dos partes: de una, la lógica de la búsqueda, apertura, etc. (que será siempre igual y que por tanto podemos extraer a una librería), y de otra, la lógica de la modificación, que sí que será diferente cada vez.

Como ejercicio para el lector, hacer otra versión que no use Hpricot sino expresiones regulares, para que sirva para cualquier tipo de archivo (vamos, lo que es sed -i).

servido por porras 2 comentarios compártelo

2 comentarios · Escribe aquí tu comentario

Luis Villa

Luis Villa dijo

Qué manía de despreciar algo tan sano como es la búsqueda de la eficiencia... y así es como llaman a la "vagancia" los amargados que no consiguen salir de la rueda de hamster en la que están metidos y se rinden.

Repite conmigo el siguiente adagio: "La Eficiencia es la hermana inteligente de la Pereza"

28 Noviembre 2007 | 04:36

porras

porras dijo

Tienes toda la razón, Luis. Tanta apología del "ser vago" no deja de ser irónica, y de representar nuestro hartazgo de que se nos diga eso, como algo malo. Y por eso hemos decidido tomarlo a orgullo. Sí, SOY VAGO, trabajo la mitad para hacer el doble. Dándole la vuelta al famoso anuncio: "¿y a tí, te gusta trabajar?". Pues ya lo siento.

Frases como "trabajo de programador porque es lo más parecido que he encontrado a no trabajar" son claramente hiperbólicas y van por ahí. "Que lo haga otro" suele ser una frase insolidaria, egoísta y en general detestable. Pero si "el otro" es un ordenador, la cosa cambia: es inteligencia, como bien dices.

2 Diciembre 2007 | 06:18

Escribe tu comentario


Sobre mí

Avatar de porras

Sugerencia de presentación

ver perfil »
contacto »

Me llamo Sergio Gil Pérez de la Manga, y mi madre se cabrea si escribo mi nombre con un sólo apellido. Vivo, trabajo y hago casi todo lo demás en Madrid.

Trabajo como programador porque es lo más parecido que he encontrado a no trabajar. Sobre todo si lo haces bien. Y en eso estoy, en hacerlo cada vez mejor para trabajar cada vez menos. Alguno lo llamaría vagancia, y yo ahí no me meto.

Algunas de las herramientas que en este momento me llevan al Nirvana de no dar un palo al agua son Ruby, Ruby on Rails, Textmate, cualquier sabor de Unix (en este momento principalmente MacOSX pero también Ubuntu Linux) y sus herramientas, o Rake. En ocasiones hablo de ellas aquí, pienso que a alguien le pueden servir y que no puedo ser el único al que no le gusta trabajar.

Y como no sólo de tecnología vive el hombre (bueno, el hombre no sé, pero desde luego yo no), por aquí aparece de vez en cuando la punta del iceberg de mis pequeños pensamientos; al menos la parte de ellos que no cabe en Twitter.

Bienvenidos todos.

Y ahora: ¿Y tú?

Fotos

porras todavía no ha subido ninguna foto.

¡Anímale a hacerlo!

Buscar

suscríbete

Selecciona el agregador que utilices para suscribirte a este blog (también puedes obtener la URL de los feeds):

¿Qué es esto?

Crea tu blog gratis en La Coctelera