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

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

|

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”.

Lo sentimos, pero los comentarios están cerrados