yield.
Una de las características de los bloques es su carácter anónimo.
Tampoco son pasados al método en la forma tradicional: no figuran en la lista de argumentos.
En vez de eso, son invocados por medio de yield.
Por ejemplo:
~/rubytesting$ cat -n iter.rb
1 def seq(n,m,c)
2 i=0
3 while (i < n)
4 yield i*m+c
5 i += 1
6 end
7 end
8
9 seq(5,2,2) { |x| puts x }
Que usamos así:
~/rubytesting$ ruby iter.rb 2 4 6 8 10
Si se prefiere tener un mayor control sobre el bloque (por ejemplo, se desea pasar el bloque
como argumento a otro método)
lo añadiremos como argumento final a nuestro método, prefijado por un ampersand &.
Dentro del método, el argumento asociado con el bloque pertenecerá a la clase Proc
y se podrá invocar usando el método call del objeto Proc en vez de yield:
~/rubytesting$ cat -n iter2.rb
1 def seq(n,m,c, &b)
2 i=0
3 while (i < n)
4 b.call(i*m+c)
5 i += 1
6 end
7 end
8
9 seq(5,2,2) { |x| puts x }
Nótese que el asunto afecta a la definición del método pero que la forma
de la llamada (línea 9) no cambia.
Ejecución:
~/rubytesting$ ruby iter2.rb 2 4 6 8 10
También podemos contruir un objeto Proc y pasarlo explícitamente
al método. En este caso se trata de un objeto ordinario y ni usamos el &
ni la llamada tiene la sintáxis con bloque:
# This version expects an explicitly-created Proc object, not a block
def sequence4(n, m, c, b) # No ampersand used for argument b
i = 0
while(i < n)
b.call(i*m + c) # Proc is called explicitly
i += 1
end
end
p = Proc.new {|x| puts x } # Explicitly create a Proc object
sequence4(5, 2, 2, p) # And pass it as an ordinary argument
Los siguientes dos métodos son legales:
def sequence5(args, &b) # Pass arguments as a hash and follow with a block
n, m, c = args[:n], args[:m], args[:c]
i = 0
while(i < n)
b.call(i*m + c)
i += 1
end
end
# Expects one or more arguments, followed by a block
def max(first, *rest, &block)
max = first
rest.each {|x| max = x if x > max }
block.call(max)
max
end
yield también funciona sobre un parámetro
definido con &.
yield incluso si el parámetro ha sido convertido a un objeto Proc
y pasado como un argumento.
& can be used in both method definitions and method invocations.
& prefijando un parámetro en una definición de método nos permite explicitar el bloque
asociado con la invocación y usarlo como un objeto de la clase Proc
dentro del cuerpo del método
& en una invocación/llamada prefijando un
objeto Proc trata al Proc como si fuera
un bloque que sigue la invocación
a, b = [1,2,3], [4,5] # Start with some data.
sum = a.inject(0) {|total,x| total+x } # => 6. Sum elements of a.
sum = b.inject(sum) {|total,x| total+x } # => 15. Add the elements of b in.
Al reescribirlo como sigue evitamos que el intérprete Ruby parsee dos veces el mismo código:
a, b = [1,2,3], [4,5] # Start with some data.
summation = Proc.new {|total,x| total+x } # A Proc object for summations.
sum = a.inject(0, &summation) # => 6 LLamada como argumento
sum = b.inject(sum, &summation) # => 15 ordinario
ruby-1.9.2-head :008 > def f(a,b); yield a+b; end
=> nil
ruby-1.9.2-head :009 > f(1,2) { |x| puts x }
3
=> nil
No podemos llamarlo como si fuera el bloque que sigue:
ruby-1.9.2-head :010 > qq = lambda { |x| puts x }
=> #<Proc:0x007f93e387d3d0@(irb):10 (lambda)>
ruby-1.9.2-head :011 > f(1,2) &qq
LocalJumpError: no block given (yield)
Así tampoco:
ruby-1.9.2-head :012 > f(1,2, qq) ArgumentError: wrong number of arguments (3 for 2)Es necesario hacer la conversión con
& y pasarlo como último argumento:
ruby-1.9.2-head :013 > f(1,2, &qq) 3 => nil
Realmente, la invocación con & puede usarse con cualquier objeto que disponga de un método to_proc.
En Ruby 1.9 la clase Symbol dispone de un método to_proc, lo que permite a los símbolos ser prefijados
con & y ser pasados a los iteradores:
pry(main)> words = ['and', 'but', 'car'] # An array of words => ["and", "but", "car"] pry(main)> uppercase = words.map &:upcase # Convert to uppercase with String.upcase => ["AND", "BUT", "CAR"]Este código es equivalente a:
upper = words.map {|w| w.upcase } # This is the equivalent code with a block
Casiano Rodriguez León 2015-01-07