This chapter explores ruby-loops-iterators-and-blocks, which allow for dynamic execution of code multiple times based on conditions, collections, or custom logic. These tools form the backbone of iteration and modular behavior in Ruby.
Chapter Goals
- Understand the purpose and usage of loops, iterators, and blocks in Ruby.
- Learn about while, until, for, iterators like each, times, and map, and custom blocks.
- Explore how blocks work with methods and how to create reusable patterns.
- Implement best practices for writing efficient and clear iterative logic with blocks.
Key Characteristics of Ruby Loops, Iterators, and Blocks
- Iteration: Repeat code execution over a range, array, or condition.
- Block Modularity: Use blocks to encapsulate reusable logic passed to methods.
- Flexible Constructs: Includes both condition-based loops and iterator-based constructs.
- Control Statements: Supports break, next, and redo for managing loop and block flow.
Basic Rules for Loops, Iterators, and Blocks
- Use loops (while, until) for condition-based iterations.
- Prefer iterators (each, map, times) for iterating over collections.
- Use blocks for passing reusable code chunks to methods.
- Test loops and blocks with edge cases to ensure correct behavior.
Best Practices
- Write descriptive block variable names to improve clarity.
- Avoid deeply nested blocks; refactor logic into methods if necessary.
- Document the purpose and structure of blocks for maintainability.
- Use iterators and blocks to make code more Ruby-idiomatic.
- Avoid overusing loops where iterators or block methods are more concise.
Syntax Table
| Serial No | Type | Syntax/Example | Description |
| 1 | while Loop | while condition end | Executes code while the condition is true. |
| 2 | until Loop | until condition end | Executes code until the condition becomes true. |
| 3 | for Loop | for variable in collection | Iterates over a range or collection. |
| 5 | times Iterator | number.times do end | Executes code a specified number of times. |
| 6 | map Iterator | `collection.map { | item |
| 7 | Block with Method | `method_name do | param |
Syntax Explanation
Blocks with Methods
What are Blocks in Ruby?
Blocks are anonymous chunks of code passed to methods for execution.
Syntax
method_name do |parameter|
code
end
# Alternatively
method_name { |parameter| code }
Detailed Explanation
- A block can be defined using either do…end or {}.
- Blocks are executed within the context of the method they are passed to.
- They can take parameters and are commonly used with iterators.
Example
[1, 2, 3].each do |num|
puts num * 2
end
Example Explanation
- The block takes num as a parameter and outputs its double for each element in the array.
Yielding to Blocks
What is yield?
The yield keyword executes the block passed to a method.
Syntax
def my_method
puts "Before block"
yield
puts "After block"
end
my_method do
puts "Inside block"
end
Detailed Explanation
- The yield keyword transfers control to the block provided during the method call.
- Code execution returns to the method after the block completes.
- Parameters can be passed to the block using yield.
Example
def greet
yield "Alice"
end
greet do |name|
puts "Hello, \#{name}!"
end
Example Explanation
- The method greet calls the block with the argument “Alice”.
- The block prints “Hello, Alice!”.
Proc and Lambda Blocks
What are Procs and Lambdas?
Procs and lambdas are objects that encapsulate blocks for reuse and flexibility.
Syntax
my_proc = Proc.new { |x| x * 2 }
puts my_proc.call(5)
my_lambda = ->(x) { x * 2 }
puts my_lambda.call(5)
Detailed Explanation
- Procs are created using Proc.new or proc.
- Lambdas are created using the -> syntax.
- Both allow blocks to be stored in variables and passed as arguments to methods.
Example
def execute(proc_or_lambda)
puts proc_or_lambda.call(10)
end
my_proc = Proc.new { |x| x + 5 }
my_lambda = ->(x) { x + 10 }
execute(my_proc) # Outputs 15
execute(my_lambda) # Outputs 20
Example Explanation
- Demonstrates passing a Proc and a lambda to the execute method.
- Outputs the transformed results of their respective logic.
Real-Life Project
Project Name: Custom Iterator with Blocks
Project Goal
Create a custom iterator method that yields to a block for flexible operations.
Code for This Project
def custom_each(array)
i = 0
while i < array.length
yield array[i]
i += 1
end
end
custom_each(["apple", "banana", "cherry"]) do |fruit|
puts "Fruit: \#{fruit}"
end
Steps
- Define a method custom_each that takes an array as input.
- Use a while loop to iterate over the array.
- Use yield to pass each element to the provided block.
- Call the method with a block that operates on each element.
Expected Output
Fruit: apple
Fruit: banana
Fruit: cherry
Project Explanation
- Demonstrates creating a custom iterator with blocks.
- Highlights the power and flexibility of blocks for iteration.
Insights
Ruby blocks, combined with loops and iterators, provide a powerful mechanism for modular and reusable code. Understanding their usage enables cleaner and more expressive Ruby programs.
Key Takeaways
- Use loops for condition-based iteration and iterators for collection traversal.
- Leverage blocks for passing reusable logic to methods.
- Utilize Procs and lambdas for encapsulating and reusing blocks.
- Write clear and concise loop, iterator, and block logic for better readability.
