A block is not an object until you ask for it to be one. That single fact
explains most of the syntax.
Yield
def each_pair
yield :name, "pulpmesh"
yield :kind, "generator"
end
each_pair { |key, value| puts "#{key}=#{value}" }
No parameter in the signature, no allocation, and block_given? tells you
whether anyone passed one.
The captured block
def with_retries(attempts, &block)
tries = 0
begin
tries += 1
block.call(tries)
rescue StandardError
retry if tries < attempts
raise
end
end
The ampersand converts the block into a Proc so it can be stored, passed on,
or called later. That conversion is the cost.
Passing it through
def each_post(&block)
posts.each(&block)
end
Capturing only to hand it straight on is the one case where a plain yield
inside posts.each { |post| yield post } is both faster and clearer.
Return, break, next
[1, 2, 3].each do |number|
next if number.even?
break number if number > 2
end
nextends this iterationbreakends the method that yieldedreturninside a block returns from the enclosing method, which is why a
returninside aProccreated at the top level raises
Arity is looser than you think
pair = [1, 2]
[pair].each { |a, b| puts "#{a} #{b}" } # 1 2
[pair].each { |a| puts a.inspect } # [1, 2]
Blocks destructure. Lambdas do not. If an arity mismatch should be an error,
you wanted a lambda.
last updated: