🔁 Ruby Programming Language Loops: A Case Study

Loops are an essential part of any programming language—they allow developers to execute code repeatedly without redundant repetition. Ruby, being an elegant and expressive language, offers several ways to implement looping constructs. This blog post explores Ruby loops through a real-world case study and demonstrates best practices for choosing the right loop for the right situation.


🧠 Why Loops Matter in Ruby

In Ruby, loops help automate repetitive tasks and iterate over collections (arrays, hashes, ranges, etc.). Understanding the different loop types and their use cases will help you write more idiomatic, efficient, and readable Ruby code.

🧪 The Case Study: Daily Sales Report Generator

Imagine you’re building a Ruby application for a retail store (like our Design studio) that generates a daily sales report. Your data source is an array of hashes, where each hash represents a sale with attributes like product name, category, quantity, and revenue.

sales = [
  { product: "T-shirt", category: "Apparel", quantity: 3, revenue: 900 },
  { product: "Laptop", category: "Electronics", quantity: 1, revenue: 50000 },
  { product: "Shoes", category: "Footwear", quantity: 2, revenue: 3000 },
  { product: "Headphones", category: "Electronics", quantity: 4, revenue: 12000 }
]

We’ll use this dataset to explore various loop types.

In Ruby:

  • Block-based loops like each, each_with_index, and loop do do create a new scope, so variables defined inside them do not leak outside.
  • Keyword-based loops like while, until, and for do not create a new scope, so variables declared inside are accessible outside.

🔄 each Loop – The Idiomatic Ruby Way

sales.each do |sale|
  puts "Sold #{sale[:quantity]} #{sale[:product]}(s) for ₹#{sale[:revenue]}"
end
Sold 3 T-shirt(s) for ₹900
Sold 1 Laptop(s) for ₹50000
Sold 2 Shoes(s) for ₹3000
Sold 4 Headphones(s) for ₹12000
=>
[{product: "T-shirt", category: "Apparel", quantity: 3, revenue: 900},
 {product: "Laptop", category: "Electronics", quantity: 1, revenue: 50000},
 {product: "Shoes", category: "Footwear", quantity: 2, revenue: 3000},
 {product: "Headphones", category: "Electronics", quantity: 4, revenue: 12000}]

Why use each:

  • Readable and expressive
  • Doesn’t return an index (cleaner when you don’t need one)
  • Scope-safe: variables declared inside the block do not leak outside
  • Preferred for iterating over collections in Ruby

🔢 each_with_index – When You Need the Index

sales.each_with_index do |sale, index|
  puts "#{index + 1}. #{sale[:product]}: ₹#{sale[:revenue]}"
end
1. T-shirt: ₹900
2. Laptop: ₹50000
3. Shoes: ₹3000
4. Headphones: ₹12000
=>
[{product: "T-shirt", category: "Apparel", quantity: 3, revenue: 900},
 {product: "Laptop", category: "Electronics", quantity: 1, revenue: 50000},
 {product: "Shoes", category: "Footwear", quantity: 2, revenue: 3000},
 {product: "Headphones", category: "Electronics", quantity: 4, revenue: 12000}]

Use case: Numbered lists or positional logic.

  • Scope-safe like each

🧮 for Loop – Familiar but Rare in Idiomatic Ruby

for sale in sales
  puts "Product: #{sale[:product]}, Revenue: ₹#{sale[:revenue]}"
end
Product: T-shirt, Revenue: ₹900
Product: Laptop, Revenue: ₹50000
Product: Shoes, Revenue: ₹3000
Product: Headphones, Revenue: ₹12000
=>
[{product: "T-shirt", category: "Apparel", quantity: 3, revenue: 900},
 {product: "Laptop", category: "Electronics", quantity: 1, revenue: 50000},
 {product: "Shoes", category: "Footwear", quantity: 2, revenue: 3000},
 {product: "Headphones", category: "Electronics", quantity: 4, revenue: 12000}]

Caution:

  • ❌ Not scope-safe: Variables declared inside remain accessible outside the loop.
  • Though valid, for loops are generally avoided in idiomatic Ruby

🪜 while Loop – Controlled Repetition

index = 0
while index < sales.size
  puts sales[index][:product]
  index += 1
end
T-shirt
Laptop
Shoes
Headphones
=> nil

Use case: When you’re manually controlling iteration.

  • ❌ Not scope-safe: variables declared within the loop (like index) remain accessible outside the loop.

🔁 until Loop – The Inverse of while

index = 0
until index == sales.size
  puts sales[index][:category]
  index += 1
end
Apparel
Electronics
Footwear
Electronics
=> nil

Use case: When you want to loop until a condition is true.

Similar to while, variables persist outside the loop (not block scoped).

🧨 loop do with break – Infinite Loop with Manual Exit

index = 0
loop do
  break if index >= sales.size
  puts sales[index][:quantity]
  index += 1
end
3
1
2
4
=> nil

Use case: Custom control with explicit break condition.

Scope-safe: like other block-based loops, variables inside loop do blocks do not leak unless declared outside.

🧹 Bonus: Filtering with Loops vs Enumerable

#--- Loop-based filter
electronics_sales = []
sales.each do |sale|
  electronics_sales << sale if sale[:category] == "Electronics"
end
=>
[{product: "T-shirt", category: "Apparel", quantity: 3, revenue: 900},
 {product: "Laptop", category: "Electronics", quantity: 1, revenue: 50000},
 {product: "Shoes", category: "Footwear", quantity: 2, revenue: 3000},
 {product: "Headphones", category: "Electronics", quantity: 4, revenue: 12000}]

#--- Idiomatic Ruby filter
> electronics_sales = sales.select { |sale| sale[:category] == "Electronics" }
=>
[{product: "Laptop", category: "Electronics", quantity: 1, revenue: 50000},
...
> electronics_sales
=>
[{product: "Laptop", category: "Electronics", quantity: 1, revenue: 50000},
 {product: "Headphones", category: "Electronics", quantity: 4, revenue: 12000}]

Takeaway: Prefer Enumerable methods like select, map, reduce when working with collections. Loops are useful, but Ruby’s functional approach often leads to cleaner code.


✅ Summary Table: Ruby Loops at a Glance

Loop TypeScope-safeIndex AccessBest Use Case
eachSimple iteration
each_with_indexNeed both element and index
forFamiliar syntax, but avoid in idiomatic Ruby
while✅ (manual)When condition is external
until✅ (manual)Inverted while, clearer for some logic
loop do + break✅ (manual)Controlled infinite loop

🏁 Conclusion

Ruby offers a wide range of looping constructs. This case study demonstrates how to choose the right one based on context. For most collection traversals, each and other Enumerable methods are preferred. Use while, until, or loop when finer control over the iteration process is required.

Loop mindfully, and let Ruby’s elegance guide your code.

Enjoy Ruby 🚀

Unknown's avatar

Author: Abhilash

Hi, I’m Abhilash! A seasoned web developer with 15 years of experience specializing in Ruby and Ruby on Rails. Since 2010, I’ve built scalable, robust web applications and worked with frameworks like Angular, Sinatra, Laravel, Node.js, Vue and React. Passionate about clean, maintainable code and continuous learning, I share insights, tutorials, and experiences here. Let’s explore the ever-evolving world of web development together!

Leave a comment