GGistDev

Blocks and Iterators in Ruby

Blocks are closures; they pair naturally with iterators for expressive collection code.

Blocks 101

Blocks use {} or do..end. They capture surrounding variables.

2.times { puts "hi" }
[1,2,3].each do |n|
  puts n * 2
end

Precedence: {} vs do..end

{} binds tighter than do..end. Use {} for single‑line function arguments, do..end for multi‑line control flow.

puts [1,2,3].map { |x| x + 1 }   # block to map
# vs
[1,2,3].each do |x|
  puts x + 1                      # multi‑line
end

yield and block_given?

Methods can yield to an optional block; block_given? checks for presence.

def around
  puts "before"
  value = yield("data") if block_given?
  puts "after"
  value
end

around { |x| x.upcase }  # prints before/after, returns "DATA"

External iterators (Enumerator)

Obtain an enumerator to step manually or chain later.

enum = [1,2,3].each   # => #<Enumerator: ...>
enum.next  # => 1
enum.next  # => 2
enum.rewind

Lazy pipelines

Process large or infinite sequences lazily.

squares = (1..).lazy.select(&:odd?).map { |n| n*n }
squares.take(5).to_a   # => [1, 9, 25, 49, 81]

Symbol‑to‑proc shorthand

["a","b"].map(&:upcase)  # => ["A","B"]

Summary

  • Blocks are closures; pass them implicitly or as Procs
  • Prefer iterator methods (each, map, select, reduce) over manual loops
  • Use enumerators (to_enum) and lazy for advanced control