ZetCode

Ruby redo Keyword

last modified October 18, 2026

This tutorial explains how to use Ruby's redo keyword. It restarts the current iteration of a loop or block without checking the loop condition.

The redo keyword causes the current iteration to restart. Unlike next, it doesn't evaluate loop conditions or move to the next item.

redo is useful when you need to retry an operation without advancing the iterator. It works with while, until, for, and blocks passed to iterator methods.

Basic redo Example

This simple example demonstrates the basic behavior of redo. The loop restarts when a condition is met.

basic_redo.rb
count = 0

while count < 5
  count += 1
  puts "Count: #{count}"
  
  if count == 3
    puts "Redoing iteration"
    redo
  end
end

The loop still prints counts 1 through 5, but the redo at count 3 restarts the current iteration. Because count was already incremented, the restarted iteration increments it again, so 4 is printed next. The loop condition is not checked when redo runs.

redo with Input Validation

redo is commonly used for input validation. This example keeps asking for input until valid data is provided.

input_validation.rb
3.times do |i|
  print "Enter a positive number: "
  input = gets.chomp.to_i
  
  if input <= 0
    puts "Invalid input! Try again."
    redo
  end
  
  puts "You entered: #{input}"
end

The redo restarts the current iteration if input is invalid. The loop counter doesn't increment until valid input is received.

redo in Nested Loops

In nested loops, redo affects only the innermost loop. This example shows its behavior in nested structures.

nested_loops.rb
outer = 0
inner = 0

while outer < 2
  outer += 1
  puts "Outer: #{outer}"
  
  while inner < 3
    inner += 1
    puts "  Inner: #{inner}"
    
    if inner == 2
      puts "  Redoing inner loop"
      redo
    end
  end
  
  inner = 0
end

The redo restarts only the innermost loop; the outer loop is unaffected. Since inner is incremented before the redo, the restarted iteration moves on to 3 instead of repeating 2 forever.

redo with Retry Logic

This example implements retry logic for an unreliable operation using redo. It retries failed operations immediately.

retry_logic.rb
attempts = 0

5.times do |i|
  attempts += 1
  puts "Attempt #{attempts} (iteration #{i + 1})"
  
  # Simulate random failure
  if rand < 0.4
    puts "Operation failed! Retrying..."
    redo
  end
  
  puts "Operation succeeded"
end

Each failure triggers a redo, restarting the current iteration. The times counter advances only after a successful attempt. Output varies because failures are random.

redo vs next

This example contrasts redo with next to highlight their different behaviors in loop control.

redo_vs_next.rb
puts "Using redo:"
retried = false
3.times do |i|
  puts "Start iteration #{i}"
  
  if i == 1 && !retried
    retried = true
    puts "Redoing..."
    redo
  end
  
  puts "End iteration #{i}"
end

puts "\nUsing next:"
3.times do |i|
  puts "Start iteration #{i}"
  
  if i == 1
    puts "Skipping..."
    next
  end
  
  puts "End iteration #{i}"
end

redo restarts the current iteration, while next skips to the next iteration. The retried flag stops redo from restarting the same iteration forever; without such a guard, the loop would never advance.

redo with until Loop

redo works with until loops similarly to while loops. This example shows its behavior in negative logic.

until_loop.rb
value = 0

until value > 3
  value += 1
  puts "Value: #{value}"
  
  if value == 2
    puts "Redoing until check"
    redo
  end
end

The redo restarts the iteration without re-evaluating the until condition. The condition is checked again only after the restarted iteration reaches the end of the body.

redo in Method with Yield

This advanced example shows redo behavior in a method that yields to a block. The redo restarts the method's loop, so the block is executed again.

method_with_yield.rb
def retry_operation
  attempts = 0
  
  3.times do |i|
    attempts += 1
    puts "Attempt #{attempts}"
    
    yield i
    
    if i == 0 && attempts < 3
      puts "Retrying..."
      redo
    end
  end
end

retry_operation do |i|
  puts "Block execution #{i}"
end

The redo restarts the current iteration of the method's times block, so yield calls the block again with the same index. Once the attempt limit is reached, the loop advances to the next index.

Source

Ruby redo Documentation

This tutorial covered Ruby's redo keyword with practical examples showing input validation, retry logic, and loop control patterns.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Ruby tutorials.