liveBook · Manning

Block

As explained in The Well-Grounded Rubyist, Fourth Edition

A block is a fragment of Ruby code supplied with a method call that the method can execute.

A block is a fragment of Ruby code attached to a method call. For example, `5.times { puts "Hello" }` supplies code that `times` runs five times. Blocks can use braces or `do` and `end`; braces are customary for one line, and `do/end` for multiple lines. section 6.2.1 section 6.3.5

def my_loop
  while true
    yield
  end
end

A homemade loop shows the method’s side of the arrangement: each `yield` runs the caller’s block, then control returns to the still-running method. section 6.3.2

The block belongs to the method-call syntax, but it is not an ordinary argument. A call may have arguments, a block, both, or neither. A method can yield zero or more times before it returns once. It can also ignore a supplied block. Values passed through `yield` become block parameters, written between pipes: `5.times { |i| puts i }` receives 0 through 4. section 6.3.3 section 6.3.5

What comes back from a block?

`[1, 2, 3].map { |n| n * 10 }` produces `[10, 20, 30]`. On each iteration, `map` yields an element; the block’s result becomes the value of `yield` inside `map`. The method collects those results into a new array. By contrast, `each` returns its original receiver. section 6.3.7 section 6.3.4

Blocks can read and change local variables already in scope. A block parameter with the same name is a separate variable, however, so assigning to that parameter does not change the outer variable. Watch the delimiter when a call is nested: `puts array.map { |n| n * 10 }` gives the block to `map`, while `puts array.map do |n| n * 10 end` gives it to `puts` because `do/end` has different precedence. In the latter case, `map` runs without a block. section 6.3.8 section 6.3.4

A block need not drive an ordinary iteration:

  • `Hash.new { |hash, key| hash[key] = 0 }` runs the block for a missing key and stores a value for it. section 9.3.3
  • `File.open("records.txt") do |f| ... end` supplies an open file and closes it when the block ends; reading its lines still requires explicit code. section 12.2.7
  • `scan` can yield successive matches to a block instead of accumulating them in a returned array. section 11.7.1

A block itself is syntax, not an object. `Proc.new { ... }` makes its code the body of a callable `Proc` object. A method can capture its block as a proc with an `&block` parameter; conversely, a call such as `each(&p)` uses a proc in place of a block. section 14.1.1 section 14.1.3

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Explains yielding, parameters, return values, scope, precedence, and proc conversion through small implementations and contrasts.
Examples
Builds homemade loop, times, and map methods and contrasts block-based file access with an explicit read loop.
What it assumes
Assumes familiarity with method calls and local variables while introducing yield and block behavior through examples.
What you can do after
Build it from scratch in simple iterators, then apply it to collection processing and scoped file access.
How it connects
Connects blocks to iterators, local scope, enumerators, file I/O, hash defaults, and Proc objects.

Also explained in

Compare how 5 books explain block →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.