You cannot assign blocks to a variable.
Blocks aren't really objects. They are special syntax for passing code to a higher-order method. If you want a piece of executable code that you can assign to a variable, pass around and manipulate, you need to use a Proc
object.
There are two kinds of Proc
s: lambdas and regular procs. They behave differently in two aspects: argument binding semantics and return
semantics. lambdas bind arguments like methods and return
returns from the lambda, just like return
in a method returns from the method. Regular procs bind arguments like blocks and return
returns from the enclosing method, not the proc, just like return
in a block.
Regular procs can be created by passing a block to Proc.new
or alternatively to Kernel#proc
. Lambdas can be created by passing a block to Kernel#lambda
or with the "stabby lambda" literal syntax:
lambda_object = ->param { puts param**2 }
In order to convert Proc
s to blocks and the other way around, Ruby has the unary prefix &
modifier. This modifier is only valid in parameter lists and argument lists. When used in a parameter list, it means "wrap the block in a proc and bind it to this variable". When used in an argument list. it means "unwrap this proc into a block (and if it's not a proc already, call to_proc
on it first) and pass it as a block argument".
(1..10).each(&lambda_object)
I'm surprised that you haven't already seen the unary prefix &
modifier used in this way, it is actually fairly common, e.g. in something like ['1', '2'].map(&:to_s)
.
Another kind of object that also represents a piece of executable code is a Method
object. It supports some of the same interface as Proc
s do, in particular #call
, #to_proc
, #arguments
, #arity
etc. There are two ways to get a Method
object: either grab a method that is bound to a receiver from that receiver using the Object#method
method or grab an UnboundMethod
object from a class or module (e.g. using Module#instance_method
) and bind it to a receiver using UnboundMethod#bind
which will return a Method
object.
Since Method
implements to_proc
, you can pass it to a method as a block using the unary prefix &
modifier, e.g.:
# Warning: extremely silly example :-)
ary = []
(1..10).each(&ary.method(:<<))
ary
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ary = []
(1..10).each(&Array.instance_method(:<<).bind(ary))
ary
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]