Ruby Loops
Ruby Loops and Iterators: Repeating Actions
Section titled “Ruby Loops and Iterators: Repeating Actions”Loops are fundamental control structures that allow you to execute a block of code multiple times. Ruby offers traditional loop keywords and, more idiomatically, a powerful set of iterator methods.
Iterators (The Idiomatic Ruby Way):
Section titled “Iterators (The Idiomatic Ruby Way):”Rubyists often prefer using iterator methods provided by collections (like Arrays and Hashes) and other objects over traditional loop constructs. Iterators are concise, expressive, and often manage scope better.
each Iterator:
The each iterator is one of the most common. It iterates over each element of a collection.
#!/usr/bin/ruby
fruits = ["apple", "banana", "cherry"]
fruits.each do |fruit| puts "I love #{fruit}s!"end
# Short block syntax:(1..3).each { |number| puts "Number: #{number}" }Output:
I love apples!I love bananas!I love cherrys!Number: 1Number: 2Number: 3times Iterator:
Executes a block a specific number of times.
#!/usr/bin/ruby
3.times do |i| puts "Iteration number #{i + 1}"endOutput:
Iteration number 1Iteration number 2Iteration number 3Other Common Iterators: map, select, reject, upto, downto, etc. These provide powerful ways to transform and filter collections. (See the Arrays chapter for more on map, select, etc.)
Traditional Loop Constructs:
Section titled “Traditional Loop Constructs:”While iterators are often preferred, Ruby also supports traditional loop keywords.
Ruby while Statement:
Section titled “Ruby while Statement:”Executes code as long as a condition is true.
Syntax:
while condition [do] # code to executeendExample:
#!/usr/bin/ruby
count = 0limit = 3
while count < limit do puts "Inside the while loop, count = #{count}" count += 1endOutput:
Inside the while loop, count = 0Inside the while loop, count = 1Inside the while loop, count = 2Ruby while modifier (single-line while):
Section titled “Ruby while modifier (single-line while):”Syntax:
# code to execute while condition
# or more commonly for one-liners:begin # codeend while conditionExample:
#!/usr/bin/ruby
value = 0begin puts "Value is #{value}" value += 1end while value < 3Output:
Value is 0Value is 1Value is 2Ruby until Statement:
Section titled “Ruby until Statement:”Executes code as long as a condition is false (i.e., until it becomes true).
Syntax:
until condition [do] # code to executeendExample:
#!/usr/bin/ruby
counter = 5
until counter <= 0 do puts "Inside the until loop, counter = #{counter}" counter -= 1endOutput:
Inside the until loop, counter = 5Inside the until loop, counter = 4Inside the until loop, counter = 3Inside the until loop, counter = 2Inside the until loop, counter = 1Ruby until modifier (single-line until):
Section titled “Ruby until modifier (single-line until):”Syntax:
# code to execute until condition
begin # codeend until conditionExample:
#!/usr/bin/ruby
stock = 3begin puts "Processing item, stock remaining: #{stock}" stock -= 1end until stock == 0Output:
Processing item, stock remaining: 3Processing item, stock remaining: 2Processing item, stock remaining: 1Ruby for...in Statement:
Section titled “Ruby for...in Statement:”Iterates over elements of a collection (or any object that responds to each).
Syntax:
for loop_variable in expression [do] # code to executeendExample:
#!/usr/bin/ruby
for i in 0..2 # Iterates through the range 0 to 2 (inclusive) puts "Value of local variable is #{i}"end
colors = ["red", "green", "blue"]for color in colors puts "Color: #{color}"endOutput:
Value of local variable is 0Value of local variable is 1Value of local variable is 2Color: redColor: greenColor: blueNote: A for...in loop is roughly equivalent to (expression).each do |loop_variable| ... end. However, a key difference is that for...in does not create a new scope for the loop_variable, whereas each with a block does. For this reason and for consistency, each is generally preferred in modern Ruby.
Loop Control Statements:
Section titled “Loop Control Statements:”Ruby provides statements to control the flow within loops:
break Statement:
Terminates the innermost loop immediately.
#!/usr/bin/ruby
(0..4).each do |i| if i == 3 then puts "Breaking at i = #{i}" break end puts "Value of i is #{i}"endOutput:
Value of i is 0Value of i is 1Value of i is 2Breaking at i = 3next Statement:
Skips the rest of the current iteration and proceeds to the next iteration of the innermost loop.
#!/usr/bin/ruby
(0..4).each do |i| if i == 2 then puts "Skipping i = #{i}" next end puts "Value of i is #{i}"endOutput:
Value of i is 0Value of i is 1Skipping i = 2Value of i is 3Value of i is 4redo Statement:
Restarts the current iteration of the innermost loop from the beginning, without re-evaluating the loop’s condition (if any).
#!/usr/bin/ruby
attempts = 0(0..2).each do |i| puts "Attempting task for i = #{i}, attempt ##{attempts + 1}" if i == 1 && attempts < 2 then attempts += 1 puts "Redoing for i = #{i}" redo # Restarts this iteration (for i = 1) end puts "Completed task for i = #{i}" attempts = 0 # Reset for next iendOutput:
Attempting task for i = 0, attempt #1Completed task for i = 0Attempting task for i = 1, attempt #1Redoing for i = 1Attempting task for i = 1, attempt #2Redoing for i = 1Attempting task for i = 1, attempt #3Completed task for i = 1Attempting task for i = 2, attempt #1Completed task for i = 2Note: redo can easily lead to infinite loops if not used carefully. It’s less common than break or next.
retry Statement:
The retry statement is primarily used within rescue blocks to re-execute the entire begin...end block where an exception occurred. Its use directly within loops (outside a rescue clause) is rare and can be confusing, as it typically restarts the entire loop or iterator from its very beginning.
Example of retry in a rescue clause (its common use):
#!/usr/bin/ruby
retries_left = 2begin puts "Attempting operation..." # Simulate an error sometimes raise "Simulated network error" if rand(3) == 0 && retries_left > 0 puts "Operation successful!"rescue => e puts "Error: #{e.message}" if retries_left > 0 retries_left -= 1 puts "Retrying... (#{retries_left} retries left)" retry # Restart the begin block else puts "No more retries. Operation failed." endendPractical Applications:
Loops and iterators are used everywhere: processing user input, reading files line by line, iterating over database records, rendering UI components, performing calculations repeatedly, and much more. Choosing the right looping construct (often an iterator like each or map) can make your Ruby code more readable and efficient.