&
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 # ollehPara 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 # ollehEl 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 endRepase 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