Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Ruby Dictionary

  1. Home
  2. Ruby Dictionary
  3. while / until (Ruby)

while / until (Ruby)

Explains while, which repeats while a condition is true, and until, which repeats while a condition is false. Ruby also frequently uses postfix forms and the loop do idiom.

Syntax

# while: repeats while the condition is truthy.
while condition
  # body
end

# until: repeats while the condition is falsy (inverse of while).
until condition
  # body
end

# Postfix while: runs the body first, then evaluates the condition (always executes at least once).
begin
  # body
end while condition

# Postfix until: runs the body first, then repeats while the condition is falsy.
begin
  # body
end until condition

# loop do: infinite loop. Use break to exit.
loop do
  # body
  break if exit_condition
end

Differences Between while and until

SyntaxRepeats whenWhen condition is evaluatedMinimum executions
while conditionCondition is truthyBefore the block (pre-check)0 (skipped if condition is false from the start)
until conditionCondition is falsyBefore the block (pre-check)0 (skipped if condition is true from the start)
begin…end whileCondition is truthyAfter the block (post-check)1 (always executes at least once regardless of condition)
begin…end untilCondition is falsyAfter the block (post-check)1 (always executes at least once regardless of condition)
loop doAlways (infinite loop)Repeats until break exits the loop

Sample Code

while_until_basic.rb
cursed_energy = 100
target = 500

puts "=== Yuji Itadori's training ==="
while cursed_energy < target
  cursed_energy += 120
  puts "Charging cursed energy... current: #{cursed_energy}"
end
puts "Reached target level #{target}!"

is_sealed = true
wait_count = 0

puts "\n=== Satoru Gojo's seal status ==="
until !is_sealed
  wait_count += 1
  puts "Turn #{wait_count}: Gojo is sealed..."
  is_sealed = false if wait_count >= 3
end
puts "Gojo's seal has been broken!"

puts "\n=== Nobara Kugisaki's hit list ==="
curse_grades = [4, 2, 0, 1, 3, 1, 4]
index = 0

while index < curse_grades.length
  grade = curse_grades[index]
  index += 1

  if grade == 0
    puts "Special Grade curse — leaving it to Gojo!"
    next
  end

  puts "Defeated Grade #{grade} curse with Straw Doll Technique."

  break if index >= 5
end
puts "Today's mission complete."
ruby while_until_basic.rb
=== Yuji Itadori's training ===
Charging cursed energy... current: 220
Charging cursed energy... current: 340
Charging cursed energy... current: 460
Charging cursed energy... current: 580
Reached target level 500!

=== Satoru Gojo's seal status ===
Turn 1: Gojo is sealed...
Turn 2: Gojo is sealed...
Turn 3: Gojo is sealed...
Gojo's seal has been broken!

=== Nobara Kugisaki's hit list ===
Defeated Grade 4 curse with Straw Doll Technique.
Defeated Grade 2 curse with Straw Doll Technique.
Special Grade curse — leaving it to Gojo!
Defeated Grade 1 curse with Straw Doll Technique.
Defeated Grade 3 curse with Straw Doll Technique.
Today's mission complete.
post_while_until.rb
shikigami_energy = 0

puts "=== Megumi Fushiguro: shikigami energy refill ==="
begin
  shikigami_energy += 150
  puts "Injecting cursed energy into Black Dog... current: #{shikigami_energy}"
end while shikigami_energy < 400

puts "Black Dog energy refill complete: #{shikigami_energy}"

mission_accepted = false
attempt = 0

puts "\n=== Kento Nanami: mission acceptance flow ==="
begin
  attempt += 1
  puts "Reviewing mission (attempt #{attempt}): assessing conditions..."
  mission_accepted = true if attempt >= 2
end until mission_accepted

puts "Mission accepted. (accepted after #{attempt} reviews)"
ruby post_while_until.rb
=== Megumi Fushiguro: shikigami energy refill ===
Injecting cursed energy into Black Dog... current: 150
Injecting cursed energy into Black Dog... current: 300
Injecting cursed energy into Black Dog... current: 450
Black Dog energy refill complete: 450

=== Kento Nanami: mission acceptance flow ===
Reviewing mission (attempt 1): assessing conditions...
Reviewing mission (attempt 2): assessing conditions...
Mission accepted. (accepted after 2 reviews)
loop_retry.rb
puts "=== Jujutsu High Surveillance System Starting ==="

tick = 0
threat_detected = false

loop do
  tick += 1
  puts "[Tick #{tick}] Scanning for cursed spirit activity..."

  if tick == 3
    threat_detected = true
    puts "[Alert] Special Grade cursed spirit detected!"
  end

  if threat_detected
    puts "[Response] Dispatching Grade 1 sorcerer Kento Nanami."
    break
  end

  if tick >= 5
    puts "[Normal] No threats. Surveillance complete."
    break
  end
end

puts "=== Surveillance System Stopped ==="

puts "\n=== Yuji Itadori: cursed energy control training (retry pattern) ==="

attempt = 0
max_attempts = 4

result = loop do
  attempt += 1
  puts "Training attempt #{attempt}..."

  if attempt >= max_attempts
    break :failure
  end

  if attempt == 3
    puts "Cursed energy control succeeded!"
    break :success
  end

  puts "Not there yet. Trying again."
end

puts result == :success ? "Training complete!" : "Calling it a day..."
ruby loop_retry.rb
=== Jujutsu High Surveillance System Starting ===
[Tick 1] Scanning for cursed spirit activity...
[Tick 2] Scanning for cursed spirit activity...
[Tick 3] Scanning for cursed spirit activity...
[Alert] Special Grade cursed spirit detected!
[Response] Dispatching Grade 1 sorcerer Kento Nanami.
=== Surveillance System Stopped ===

=== Yuji Itadori: cursed energy control training (retry pattern) ===
Training attempt 1...
Not there yet. Trying again.
Training attempt 2...
Not there yet. Trying again.
Training attempt 3...
Cursed energy control succeeded!
Training complete!

Notes

Ruby's while repeats while the condition is truthy; until repeats while it is falsy. until is completely equivalent to while !condition, but it expresses the intent directly without negation, resulting in more readable code.

The postfix forms begin…end while and begin…end until are post-check loops. The block always executes at least once before the condition is evaluated, guaranteeing a minimum of one execution. They are useful for input validation and cases where an initial operation is mandatory.

loop do is the idiom for an explicit infinite loop. It is suited to service loops with multiple exit conditions and to retry patterns where break's return value is used to receive a result. while true can write the same infinite loop, but loop do is the idiomatic Ruby style. A loop with no break never terminates, so an exit path must always be provided. For a fixed number of repetitions, times / upto / downto is more appropriate.

Common Mistakes

Mistake 1: Forgetting break and creating an infinite loop

When writing a loop with while true or loop do, if the exit condition is not handled correctly the loop runs forever. Typical causes include forgetting to update the counter variable, or placing break in the wrong position.

ng_infinite_loop.rb
cursed_energy = 0
target = 500

while cursed_energy < target
  puts "Charging cursed energy... current: #{cursed_energy}"
  # cursed_energy is never updated, so the loop never ends.
end
puts "Target reached!"

The loop variable is never updated so the program never terminates. Always update the counter or state variable inside the loop body.

ok_infinite_loop.rb
cursed_energy = 0
target = 500

while cursed_energy < target
  cursed_energy += 120
  puts "Charging cursed energy... current: #{cursed_energy}"
end
puts "Reached target level #{target}!"
ruby ok_infinite_loop.rb
Charging cursed energy... current: 120
Charging cursed energy... current: 240
Charging cursed energy... current: 360
Charging cursed energy... current: 480
Charging cursed energy... current: 600
Reached target level 500!

Mistake 2: Wrong condition direction in begin...end while (using while where until is intended)

When a post-check loop should "repeat until the condition becomes true", begin...end until is the natural expression. Writing it as begin...end while !condition introduces a negation that makes the intent harder to read. Getting the condition direction wrong can also cause the loop to execute zero times or run forever.

ng_begin_end_while.rb
mission_accepted = false
attempt = 0

begin
  attempt += 1
  puts "Reviewing mission (attempt #{attempt})"
  mission_accepted = true if attempt >= 2
end while !mission_accepted
ruby ng_begin_end_while.rb
Reviewing mission (attempt 1)
Reviewing mission (attempt 2)

The intent "repeat until accepted" can be expressed directly with begin...end until.

ok_begin_end_until.rb
mission_accepted = false
attempt = 0

begin
  attempt += 1
  puts "Reviewing mission (attempt #{attempt})"
  mission_accepted = true if attempt >= 2
end until mission_accepted

puts "Mission accepted. (accepted after #{attempt} reviews)"
ruby ok_begin_end_until.rb
Reviewing mission (attempt 1)
Reviewing mission (attempt 2)
Mission accepted. (accepted after 2 reviews)

Mistake 3: Off-by-one error in while condition

Confusing < with <= in a while condition causes the loop to execute one time too few or one time too many. This often occurs when iterating over an array by index or when a counter crosses a boundary value.

ng_off_by_one.rb
grades = [4, 3, 2, 1, 0]
index = 0

while index < grades.length - 1
  puts "Defeated Grade #{grades[index]} curse."
  index += 1
end
puts "Total defeated: #{index}"
ruby ng_off_by_one.rb
Defeated Grade 4 curse.
Defeated Grade 3 curse.
Defeated Grade 2 curse.
Defeated Grade 1 curse.
Total defeated: 4

The last element (index 4) is not processed. Use index < grades.length to iterate over all elements of an array.

ok_off_by_one.rb
grades = [4, 3, 2, 1, 0]
index = 0

while index < grades.length
  puts "Defeated Grade #{grades[index]} curse."
  index += 1
end
puts "Total defeated: #{index}"
ruby ok_off_by_one.rb
Defeated Grade 4 curse.
Defeated Grade 3 curse.
Defeated Grade 2 curse.
Defeated Grade 1 curse.
Defeated Grade 0 curse.
Total defeated: 5

If you find any errors or copyright issues, please .