Trabe ya no escribe aquí. Puedes encontrarnos en nuestra publicación en Medium: medium.com/trabe.

4Trabes Historias de una empresa en 100 metros cuadrados

El blog de Trabe Soluciones

Ponencia de Trabe Soluciones aceptada en la Conferencia Rails 2007

| | Comentarios

Ayer, la organización de la Conferencia Rails 2007 me confirmó la inclusión de una de nuestras ponencias en el programa de las conferencias. Podéis ver la relación completa en la dirección http://ponencias.conferenciarails.org.

De las dos propuestas que enviamos aceptaron una que titulamos Proyectos de bajo coste con limitaciones severas de tiempo y recursos y dejaron fuera otra de APIs Rest y proxificación, lo cual me ha sorprendido bastante. Sin quitarle interés a la primera ponencia, creo que la segunda era mucho más interesante y amena (mucho más tecnológica y menos empresarial). En cualquier caso nos vemos en la Conferencia Rails en Noviembre.

PD: Aunque el que escribe aparece como ponente en la página web, debo decir que este punto no está confirmado y puede dar la charla cualquier otro miembro de Trabe. Más adelante os confirmo a quién le podéis tirar los tomates el día de la charla.

Extensiones al core de Ruby, copia profunda de objetos con el API de marshalling (serializando, vamos)

| | Comentarios

Una necesidad típica a la hora de programar es copiar o clonar objetos. Los métodos de Ruby Object#clone y Object#dup realizan copias superficiales (shallow_), es decir, si el objeto contiene referencias a otros objetos se duplican las referencias pero no los objetos apuntados. Si la copia fuese profunda (_deep), también se duplicarían los objetos referenciados. Ejemplo:

1
2
3
4
5
6
7
h = { 1 => ['a','b'], 2 => ['c'] }
h1 = h.clone
h2 = h.deep_clone
h1[1].shift    # => "a"
h   # =>  {1=>["b"], 2=>["c"]}
h1  # =>  {1=>["b"], 2=>["c"]}
h2  # =>  {1=>["a", "b"], 2=>["c"]}

Lo primero que se nos puede ocurrir es crear un método deep_clone específico para cada objeto (o incluso uno más genérico que, mediante introspección del objeto supiese que copiar). Ésto es tedioso y tiene sus problemas (básicamente el meanejo de referencias cruzadas), además, eso no es DRY. Por fortuna Ruby tiene soporte para serialización (módulo Marshal). El truco es sencillo: serializo, deserializo.

1
2
3
4
5
6
class Object
  def deep_clone
    # Abracadabra !!!
    Marshal::load(Marshal::dump(self))
  end
end

Sencillo, bello, y todas esas cosas que tanto gustan de Ruby.

A esta técnica sólo podemos ponerle dos pegas: 1) si una parte de la clase no es serializable no podremos copiarla, y 2) es cierto que una implementación ad hoc de copia puede ser más rápida (pero yo, al menos, estoy dispuesto a perder esa velocidad).

PD: Por cierto, esta técnica tan sencilla es trasladable directamente a cualquier otro lenguaje/plataforma con soporte para serialización: Java, .NET, etc.

Symbol#to_proc de rails y otras alternativas (o locuras, según se mire)

| | Comentarios

Este post es consecuencia directa de un comentario de Sergio Gil a mi post anterior: Extensiones al core de Ruby, pequeños pedazos de código que harán tu vida más sencilla. Hoy Enumerable.pluck y Enumerable.invoke.

Sergio, acertadamente comenta:

ActiveSupport añade a each y a collect/map una versión abreviada de la sintaxis (realmente lo que hace es definir Symbol#to_proc, si no me equivoco) que la deja muy parecida a lo que habéis creado, que dejaría el ejemplo así:

objects.collect(&:key)

a lo que nosotros respondemos:

Tienes razón Sergio, existe esa posibilidad, aunque aquí en Trabe consideramos que es una construcción un poco oscura. Por otro lado la versión que utilizamos nosotros, permite hacer alguna cosa adicional fácilmente, por ejemplo, utilizar una cadena como parámetro en lugar de un símbolo (que puede considerarse algo menor) o más interesante, pasar parámetros a la función que se invoca (que como pone el post, queda como ejercicio para el lector ;)

Ejemplo práctico:

%w(un ejemplo).pluck(’*’,2) => [“unun”, “ejemploejemplo”]

Aprovecho ahora para resolver el ejercicio de programación que os propuse:

1
2
3
4
5
6
7
8
module Enumerable
  def invoke(method_name, *args)
    self.each { |i| i.send(method_name, *args) }
  end
  def pluck(method_name, *args)
    self.collect { |i| i.send(method_name, *args) }
  end
end

Hasta aquí todo bien. Lo que pasa, es que cuando se escribe en un blog y se reciben comentarios uno se ve obligado a realizar un ejercicio mental y reflexionar mucho sobre lo que escribe. Así que me he tomado un ratito para investigar algo más sobre este tema.

La primera carencia que apuntamos acerca de la solución con Symbol#to_proc es fácilmente superable, sólo necesitamos definir nuestro propio String#to_proc. La falta de parámetros en el método es algo que me llama especialmente la atención. Estuve haciendo unas pruebas en la consola, y no conseguí pasar nigún parametro, así que me fui al código fuente y esto es lo que pone:

1
2
3
def to_proc
  Proc.new { |*args| args.shift.__send__(self, *args) }
end

Dado que no soy un gurú ni un semidios de Ruby no puedo afirmar esto con rotundidad, pero, a primera vista parece que to_proc devolvería un Proc capaz de recibir un número variable de argumentos.

Ante la duda, Google, porque no estamos sólos en el mundo.

Lo que descubrí, a parte de confirmar que Symbol#to_proc no puede recibir argumentos, es la Methodphitamine (algo así como la método-fetamina), una suerte de locura sintáctica que permite hacer algo como:

1
2
(1..100).select &it % 2 == 0
User.find(:all).map &its.contacts.map(&its.last_name.capitalize)

¡Qué locura!, ¿Efectos de la droga?, ¿Tendrá este hombre que mear en un vaso y pasar un anti-dopping? en fin. Yo, personalmente, comulgo con un comentario de Sam Aaron aparecido en The Methodphitamine: A Better Symbol#to_proc?.

I’m not a big fan of the to_proc hack in the first place. To my eyes, it’s ugly, and Methodphitamine is even more ugly. I believe that there’s a balance to be struck between readability and succinctness. I think that the Ruby philosophy (or way) leans more towards the readability side of the spectrum. Check out Matz’s essay in the new O’Reilly book ‘Beautiful Code’ where he likens code to an essay. i.e. essays generally have messages, but the message is mostly meaningless unless it can be read and understood by other people. It’s a good read.

Beautiful Code es un libro que tengo en casa en la cola de lectura, cuando le eche un vistazo os comento.

De todos modos, quién este interesado en este tipo de syntactic sugar también puede echarle un ojo a Array#to_proc – Nested properties for to_proc hack, que es una solución para el encadenamiento más legible y en la línea de Symbol#to_proc o bien New magical version of Symbol.to_proc que permite escribir algo como list.map &:to_i elegantemente como list.to_is con una extensión que sólo puede considerarse como “code hell”.