2009-12-29 5 views
8

Estoy tratando de crear un pequeño hacha de Ruby para hacer algo así como el reverso del Symbol # to_proc hack. Mientras que el hack símbolo # to_proc lo hace posible:Ruby to_proc hack con enlace

some_array.each(&:some_method) 

es lo mismo que

some_array.each { |obj| obj.some_method } 

Quiero que esto sea posible:

some_array.each(&[:some_method]) 

sería el mismo que

some_array.each { |obj| some_method(obj) } 

El problema es que a menos que some_method es un método kernel, lo que realmente significaría es:

some_array.each { |obj| self.some_method(obj) } 

Cuando un bloque se pasa de forma explícita, se ha creado dentro de la unión donde se escribe esta línea, por lo que la auto accesos correctamente las obras objeto y todo actuales multa. Sin embargo, si el bloque se crea en el método to_proc de la matriz, el self está dentro del enlace Array (y se refiere a la matriz en sí). Tal vez no sea posible hacer lo que estoy tratando de hacer, pero me encantaría algunas ideas de la comunidad.

Aquí está mi truco hasta el momento. Esto funciona siempre y cuando el método es un método de núcleo, y está disponible dentro de la agrupación:

class Array 
    def to_proc 
    lambda {|i| send(self.first, i)} 
    end 
end 

Con este truco, funciona de esta línea, y pone las tres símbolos:

[:foo, :bar, :bas].each(&[:puts]) 

Es útil para mí ya, porque a menudo me encuentro queriendo inspeccionar una variedad de objetos ActiveRecord dentro de la consola y me ahorra tipear {| i | pone i}. Pero sería aún más útil poder usarlo dentro de los objetos para que se llame a algún método dentro del objeto con cada elemento de la matriz pasado como parámetro.

¿Alguna idea de cómo hacer que funcione el enlace?

Por favor, no responda con "no quiere hacer esto porque hará que las cosas funcionen más despacio" o "no está guardando tantos caracteres escribiendo, pero hace que el código sea menos legible" - - Ya sé estas cosas. :) Esto es más una especie de hack de alimentación de mi curiosidad. Me pregunto si es posible.

+0

¿podría usted elegir una respuesta? : p Solo noto esto q. obtuve cierto interés, por lo que sería bueno que seleccionara la respuesta que mejor respondiera a su pregunta. – horseyguy

+0

Buen punto. Quería ver si alguien tiene una respuesta sobre cómo hacer que funcione realmente el enlace, como en mi pregunta original. Pero supongo que no es posible de la forma en que estaba tratando de hacerlo, ya que el truco to_proc está dentro de otro objeto (Array). –

+0

no sé a qué te refieres con "trabajar el enlace" pero recuperaré la respuesta que tenía, que hace algunas cosas con un enlace, pero realmente no es tan limpio y agradable como el enfoque 'method()' – horseyguy

Respuesta

10

Usted está buscando el método llamado method :)

class Example 
    def some(arg) 
    p arg.size # just as a demo 
    end 
end 

obj = Example.new 
%w{the quick brown fox jumps over the lazy dog}.each(&obj.method(:some)) 

produce

3 
5 
5 
3 
5 
4 
3 
4 
3 
+0

+1 respuesta simple y dulce :) – horseyguy

+0

Eso es ... ¡exactamente lo que estaba buscando! :) Gracias. –

+0

Me alegro de poder ayudar. – akuhn

1

Aquí hay otra forma de hacerlo sin utilizar el método method() :). Utiliza un bloque para capturar el enlace y luego invoca el método relevante en el self del enlace.

class Object 
    def apply &block 
     b = eval('self', block.binding) 
     lambda { |param| b.send block.call, param } 
    end 
end 


# use like this: 
[1, 2, 3, 4].each &apply { :puts } 

output: 1 
     2 
     3 
     4 
+0

Ooh, eso es friggin guay. Esta solución está más cerca de lo que estaba inicialmente intentando. –

3

Aunque Adrian tiene la idea correcta allí con el uso del método method, puede simplificar esto una paso más allá:

# Works on any generic method 
%w{the quick brown fox jumps over the lazy dog}.each(&method(:foo)) 

def foo(arg) 
    p arg.size 
end 

# Works on user-defined methods, too 
%w{the quick brown fox jumps over the lazy dog}.each(&method(:puts)) 

En lugar de crear una semántica incómoda con la introducción de Array # to_proc, ¿por qué no simplemente escribir sus propios métodos Enumerables que le hacen la vida más fácil? Tal vez algo como esto:

module Enumerable 
    def pass_each(method_name) 
    each(&method(method_name.to_sym)) 
    end 
end 

%w{the quick brown fox jumps over the lazy dog}.pass_each(:puts) 
+0

Esa es una muy buena idea al hacer un nuevo método de Enumerable, pero me gustaría poder utilizar este truco con todos los diversos métodos Enumerable, como cada uno, mapa, rechazo, etc. ¡Gracias! –

+0

en su ejemplo 'pass_each' ¿no se ejecutará el método' method() 'en el contexto incorrecto (el contexto del receptor) y por lo tanto no tendrá acceso a los métodos correctos? – horseyguy

+0

El método debe declararse dentro del contexto principal o no será muy útil, sí. De lo contrario, es un gran desastre hacer que esa llamada a método funcione en el contexto activo. – tadman

Cuestiones relacionadas