Blocks are Ruby's signature feature: almost every loop, callback and DSL in Ruby is a block.
A block is a chunk of code passed to a method call, written with braces for one-liners or do ... end for multi-line code:
[1, 2, 3].each { |n| puts n }
File.open("log.txt") do |f|
puts f.readline
endThe method decides when and how often to run the block, passing values in through the |params|. Core iterators:
eachruns the block for each element and returns the receiver.mapreturns a new array of the block's results.select/filterkeeps elements where the block is truthy;rejectdrops them.findreturns the first match,any?/all?/counttest conditions.each_with_index,each_slice(2),times,upto.
Inside your own method, yield calls the block given by the caller, and block_given? checks whether there is one. Methods that set up and tear down something around a block (like File.open) are a key Ruby idiom: the cleanup happens even if the block raises.
Shorthands: map(&:upcase) calls a method on each element, and in Ruby 3.4 it refers to the single block parameter: nums.map { it * 2 }.
Blocks are closures: they can read and modify local variables from the surrounding scope. next value ends the current block call with that value; break exits the whole method call.
Example
nums = [1, 2, 3, 4, 5]
p nums.map { |n| n * n } # [1, 4, 9, 16, 25]
p nums.select(&:even?) # [2, 4]
p nums.find { it > 3 } # 4 (Ruby 3.4 `it`)
p %w[a b].map(&:upcase) # ["A", "B"]
def twice
return :no_block unless block_given?
yield 1
yield 2
end
twice { |x| puts "got #{x}" } # got 1 / got 2
p twice # :no_block
def timed(label)
start = Time.now
yield
ensure
puts "#{label} took #{(Time.now - start).round(3)}s"
end
timed("sum") { (1..1_000_000).sum } # sum took 0.0s (roughly)
total = 0
nums.each { |n| total += n } # blocks see outer locals
p total # 15Remember
- Blocks are code passed to methods; yield runs them
- map transforms, select filters, each just iterates
- &:method and it are shorthands for simple blocks
Watch out for
- Using each when you need the transformed values; each returns the original array, not the block results.