Ruby Blocks

Anonymous chunks of code passed to methods

🧱 What are Ruby Blocks?

Blocks are anonymous pieces of code enclosed in do...end or curly braces {}. They're passed to methods and executed within them, enabling powerful iteration and custom behavior patterns.


# Block with curly braces
[1, 2, 3].each { |num| puts num }

# Block with do...end
[1, 2, 3].each do |num|
  puts num * 2
end
                                    

Output:

1

2

3

2

4

6

Key Block Concepts

{ }

Syntax

Use {} for one line, do...end for multiple

5.times { puts "Hi" }
5.times do
  puts "Hello"
end
📊

Parameters

Blocks can accept parameters

[1, 2].each do |n|
  puts n
end
🔄

Iteration

Perfect for looping through data

arr.each { |item|
  puts item
}
âš¡

Yield

Methods call blocks with yield

def run
  yield
end

🔹 Block Syntax

Ruby offers two ways to write blocks: curly braces for single-line blocks and do...end for multi-line blocks. Both work identically, but convention suggests using braces for short, simple operations.

# Curly braces - single line
3.times { puts "Hello" }

# do...end - multiple lines
3.times do
  puts "Hello"
  puts "World"
end

# With parameters
[1, 2, 3].each { |num| puts "Number: #{num}" }

# Multi-line with parameters
["apple", "banana"].each do |fruit|
  puts "I like #{fruit}"
  puts "It's delicious!"
end

Output:

Hello

Hello

Hello

Hello

World

Hello

World

Hello

World

Number: 1

Number: 2

Number: 3

I like apple

It's delicious!

I like banana

It's delicious!

🔹 Common Block Methods

Ruby's enumerable methods use blocks extensively for iteration and transformation. These built-in methods make working with collections intuitive and expressive, reducing the need for traditional loops in most cases.

# each - iterate through items
[1, 2, 3].each { |n| puts n * 2 }

# map - transform each item
doubled = [1, 2, 3].map { |n| n * 2 }
puts doubled.inspect

# select - filter items
evens = [1, 2, 3, 4, 5].select { |n| n.even? }
puts evens.inspect

# times - repeat n times
5.times { |i| puts "Iteration #{i}" }

# upto - count up
1.upto(3) { |n| puts "Count: #{n}" }

Output:

2

4

6

[2, 4, 6]

[2, 4]

Iteration 0

Iteration 1

Iteration 2

Iteration 3

Iteration 4

Count: 1

Count: 2

Count: 3

🔹 Creating Methods with Blocks

You can create your own methods that accept blocks using the yield keyword. This allows you to build custom iteration patterns and reusable code structures that execute caller-provided logic at specific points.

# Simple yield
def greet
  puts "Before block"
  yield
  puts "After block"
end

greet { puts "Inside block!" }

# Yield with parameters
def repeat(n)
  n.times { |i| yield(i) }
end

repeat(3) { |num| puts "Number: #{num}" }

# Conditional yield
def maybe_run
  yield if block_given?
  puts "Method complete"
end

maybe_run { puts "Block executed" }
maybe_run  # No block provided

Output:

Before block

Inside block!

After block

Number: 0

Number: 1

Number: 2

Block executed

Method complete

Method complete

🔹 Block Parameters

Blocks can receive multiple parameters from the calling method. These parameters are defined between pipe characters and allow blocks to access iteration values, indices, or any data the method wants to share.

# Single parameter
[10, 20, 30].each { |num| puts num }

# Multiple parameters
hash = { name: "Alice", age: 25 }
hash.each { |key, value| puts "#{key}: #{value}" }

# With index
["a", "b", "c"].each_with_index do |letter, index|
  puts "#{index}: #{letter}"
end

# Custom method with multiple yields
def calculate(a, b)
  yield(a, b, a + b)
end

calculate(5, 3) { |x, y, sum| puts "#{x} + #{y} = #{sum}" }

Output:

10

20

30

name: Alice

age: 25

0: a

1: b

2: c

5 + 3 = 8

🔹 Practical Block Examples

Blocks shine in real-world scenarios like data processing, file operations, and custom iterations. These examples demonstrate how blocks make Ruby code elegant, readable, and powerful for everyday programming tasks.

# Data transformation
prices = [10, 20, 30]
discounted = prices.map { |price| price * 0.9 }
puts "Discounted: #{discounted.inspect}"

# Filtering data
numbers = [1, 2, 3, 4, 5, 6]
evens = numbers.select { |n| n.even? }
odds = numbers.reject { |n| n.even? }
puts "Evens: #{evens.inspect}"
puts "Odds: #{odds.inspect}"

# Custom iterator
def countdown(from)
  from.downto(1) { |n| yield(n) }
  puts "Blast off!"
end

countdown(3) { |n| puts n }

# Accumulation
total = [1, 2, 3, 4].reduce(0) { |sum, n| sum + n }
puts "Total: #{total}"

Output:

Discounted: [9.0, 18.0, 27.0]

Evens: [2, 4, 6]

Odds: [1, 3, 5]

3

2

1

Blast off!

Total: 10

🧠 Test Your Knowledge

What keyword is used to execute a block inside a method?