iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Blocks & Yield

A block is an anonymous chunk of code passed to a method. Blocks power Ruby’s expressive iteration: each, map, tap, open(…) { |f| … }. Procs and lambdas are blocks promoted to objects.

Blocks, yield, procs, lambdas

EXAMPLE
# 1) Blocks: do…end OR { … }
[1, 2, 3].each do |n|
    puts n * 2
end

[1, 2, 3].map { |n| n * 2 }

# 2) Yield to a block from your own method
def with_timer
    start = Time.now
    result = yield
    puts "took \#{Time.now - start}s"
    result
end

rows = with_timer { Database.query('SELECT * FROM users') }

# 3) Pass arguments to the block
def each_pair(hash)
    hash.each { |k, v| yield k, v }
end

# 4) Optional block — block_given?
def debug(msg)
    if block_given?
        yield msg     # let caller customise the format
    else
        puts msg
    end
end

debug('hi')
debug('hi') { |m| warn "[debug] \#{m.upcase}" }

# 5) Explicit block parameter — capture as a Proc
def retry_with(times, &block)
    times.times do |i|
        begin
            return block.call(i)
        rescue StandardError
            sleep(2**i)
        end
    end
end

retry_with(3) { |i| fetch_remote }

# 6) Proc vs Lambda — strictness about arguments
adder = ->(a, b) { a + b }     # lambda — strict (wrong arity raises)
adder.call(1, 2)
adder.(1, 2)                    # short form
adder[1, 2]                     # square-bracket form

loose = proc { |a, b| a.to_i + b.to_i }   # proc — lax, missing args nil
loose.call(1)

# 7) Convert blocks ⇄ symbols
[1, 2, 3, 4].map(&:to_s)                  # &:to_s == { |x| x.to_s }
logger = ->(line) { warn line }
run_pipeline(&logger)                      # pass a lambda as a block

# 8) yield_self / then — pipeline a value
result = read_file(path)
    .then { |raw| parse_csv(raw) }
    .then { |rows| reject_blanks(rows) }
    .then { |rows| index_by(&:id) }

# 9) tap — peek at a value without breaking the chain
[1, 2, 3]
    .tap { |a| puts "before: \#{a}" }
    .map { |n| n * 2 }
    .tap { |a| puts "after:  \#{a}" }

Why it matters

&:method_name is the most common Ruby shorthand. users.map(&:name) reads like English, runs as fast as a hand-written block, and keeps intent obvious.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
def repeat(n)
    n.times { yield }
end
repeat(3) { puts 'hi' }
Try it Yourself »

Exercise

Run the caller's block.

def repeat(n) n.times { } end

Test yourself

Q1. A block is yielded with the keyword…
Q2. Capture a block as a Proc parameter with…
Q3. Run a block n times via…

Discussion

Loading…