Blocks, Procs and Lambdas

14.1 Blocks

[1, 2, 3].each { |n| puts n }          # braces: single line (convention)
[1, 2, 3].each do |n|                  # do...end: multi-line
  puts n * 2
end

def repeat(times)
  return enum_for(:repeat, times) unless block_given?   # return an enumerator without a block
  times.times { |i| yield i }          # yield calls the block
end
repeat(3) { |i| puts "Iteration #{i}" }

def with_timing
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  result = yield
  puts "Took #{(Process.clock_gettime(Process::CLOCK_MONOTONIC) - start).round(3)}s"
  result
end
with_timing { sleep 0.1 }

[1, 2, 3].map { it * 2 }               # `it` implicit parameter (Ruby 3.4)
[1, 2, 3].map { _1 * 2 }               # numbered parameters (Ruby 2.7+)

14.2 Explicit Block Parameters

def run_callback(&callback)            # captures the block as a Proc
  callback.call(42)
end

def wrap(&block) = other_method(&block)   # pass the block along
words.map(&:upcase)                     # Symbol#to_proc

14.3 Procs and Lambdas

Lenient (missing args → nil, extras ignored) Strict (ArgumentError) Returns from the enclosing method Returns from the lambda itself Proc.new, proc, blocks lambda, ->

square = Proc.new { |x| x * x }
square = proc { |x| x * x }
double = lambda { |x| x * 2 }
triple = ->(x) { x * 3 }               # stabby lambda (preferred)
add = ->(a, b = 1) { a + b }

square.call(4); square.(4); square[4]; square.yield(4)
triple.curry; add.arity; triple.lambda?

14.4 Closures

def make_counter
  count = 0
  increment = -> { count += 1 }
  get = -> { count }
  [increment, get]
end
inc, get = make_counter
3.times { inc.call }
get.call            # 3

multiplier = ->(factor) { ->(x) { x * factor } }
times5 = multiplier.(5)
times5.(3)          # 15

14.5 Composition and Currying

add1 = ->(x) { x + 1 }
dbl = ->(x) { x * 2 }
(add1 >> dbl).call(3)   # 8  (add1 then dbl)
(add1 << dbl).call(3)   # 7  (dbl then add1)
pipeline = method(:Integer) >> add1 >> dbl
pipeline.("4")          # 10
volume = ->(l, w, h) { l * w * h }.curry
volume[2][3][4]         # 24