& pueda
pasarse como bloque a un iterador
# Increment an array of integers with the Fixnum.succ method [1,2,3].map(&:succ) # => [2,3,4]que es equivalente a:
[1,2,3].map {|n| n.succ }
El método to_proc podría implementarse así:
class Symbol
def to_proc
lambda {|receiver, *args| receiver.send(self, *args)}
end
end
ruby-1.9.2-head :008 > Object.instance_methods.select { |x| x =~ /send/ }
=> [:send, :public_send, :__send__]
send.
También podríamos implementar to_proc usando el método methodde la clase
Object:
class Symbol
def to_proc
lambda {|receiver, *args| receiver.method(self)[*args]}
end
end
[] en la clase Module
para que podamos escribir:
String[:reverse].bind("hello").call # olleh
Para ello basta con hacer un alias [] instance_method
[~/srcLPP/rubytesting/TheRubyProgrammingLanguage/Chapter6MethodsProcsLambdasAndClosures]$ cat -n method_index1.rb
1 class Module
2 alias [] instance_method
3 end
4
5 puts String[:reverse].bind("hello").call # olleh
El método retornado por instance_method es un UnboundMethod.
Puesto que el método retornado no tiene Binding,
es necesario llamar al método bind
sobre un objeto para ligarlo.
Es posible llevar esta analogía, usando el UnboundMethod a su vez como hash usando este alias:
7 class UnboundMethod
8 alias [] bind
9 end
10
11 puts String[:reverse]["hello"][] # olleh
Resulta tentador definir también
el operador asignación a elementos de una colección []= para definir métodos:
[~/srcLPP/rubytesting/TheRubyProgrammingLanguage/Chapter6MethodsProcsLambdasAndClosures]$ cat -n method_index.rb
1 class Module
2
3 def []=(symbol, code)
4 define_method(symbol, code)
5 end
6
7 end
8
9 String[:chuchu] = lambda { |x| puts "Chuchu#{x}!"}
10
11 "hello".chuchu("Cham") # ChuchuCham!
El método define_method es un método privado de Module:
ruby-1.9.2-head :009 > Module.private_methods.select { |x| x =~ /define/ }
=> [:method_undefined, :define_method, :singleton_method_undefined]
En la línea 4 self es el objeto módulo sobre el que estamos definiendo el método (por ejemplo
String en la llamada de la línea 9: recuerde que toda clase es un módulo).
Con esta definición de []= podemos escribir:
Enumerable[:average] = lambda do
sum, n = 0.0, 0
self.each {|x| sum += x; n += 1 }
if n == 0
nil
else
sum/n
end
end
[] y []= en la clase Object.
El problema es que muchísimas clases redefinen [] y []= y, por tanto,
nuestra definición se perdería.
En vez de eso podemos hacerlo al revés: ver a los nombres de los métodos como colecciones y a los objetos como índices. No queda tan natural, pero tiene la ventaja de que la clase Symbol no es tan heredada como la clase Object.
Para hacerlo abrimos la clase Symbol y definimos ahí los operadores:
[~/Chapter6MethodsProcsLambdasAndClosures]$ cat -n singleton_index.rb
1 class Symbol
2 def [](obj)
3 obj.method(self)
4 end
5
6 def []=(obj,f)
7 sym = self
8 eigenclass = class << obj; self end
9 eigenclass.instance_eval do
10 define_method(sym, f)
11 end
12 end
13 end
14
15 puts :length["Jane"][] # 4
16
17 x = "hello"
18 :tutu[x] = lambda { |z| puts "#{x} #{z}"}
19 x.tutu("Jane") # hello Jane
end
Repase la sección
14.12
para recordar que para abrir la eigenclass
del objeto obj usamos la sintáxis class << obj.
Así, una forma de obtener la eigenclass es:
eigenclass = class << o; self; end
Casiano Rodriguez León 2015-01-07