Control Flow in Ruby
Learn conditionals, case statements, loops, and loop control in Ruby with practical Docker-ready examples
Control flow is how a program decides what to do and how many times to do it. Ruby gives you the familiar tools—if, else, loops—but wraps them in syntax that reads almost like English. As a multi-paradigm language with strong object-oriented and functional leanings, Ruby often encourages you to iterate over collections with blocks rather than write manual counter loops.
Ruby’s design philosophy of “least surprise” shines in its control flow. It adds expressive touches you won’t find everywhere: unless for negated conditions, statement modifiers that put the condition after the action, and a powerful case statement that matches on ranges, types, and patterns. Almost everything in Ruby is an expression that returns a value, so even an if or case can be assigned directly to a variable.
In this tutorial you’ll learn how to branch with if/elsif/else and unless, match values with case/when, repeat work with while/until and iterators, and control loops using break, next, and loop.
Conditionals: if, unless, and the Ternary Operator
The if/elsif/else chain is Ruby’s basic branching tool. Ruby also offers unless (an if with the condition negated) and concise statement modifiers that place the condition at the end of a line.
Create a file named control_flow.rb:
| |
Notice that if and unless blocks end with end—Ruby uses no curly braces or significant indentation for these. The ternary operator is a compact one-line alternative when you just need to pick between two values.
Case Statements: Ruby’s Powerful Switch
The case statement is far more capable than a typical C-style switch. Each when clause uses the === operator under the hood, which lets you match against ranges, classes, and more—not just literal equality. A case is also an expression, so it can return a value directly.
Create a file named case_when.rb:
| |
The range 80...90 uses three dots to exclude its upper bound, while 80..90 (two dots) would include it. Matching on Integer and String works because a class responds to === by checking whether the value is an instance of it.
Loops: while, until, and Iterators
Ruby supports classic while and until loops, but idiomatic Ruby usually iterates over collections and ranges using blocks. Methods like each, times, and ranges replace most manual counter loops you’d write in other languages.
Create a file named loops.rb:
| |
Blocks can be written with do ... end (preferred for multi-line bodies) or with curly braces { ... } (preferred for one-liners). The block parameter—like |color| or |i|—receives each value in turn. Note that 3.times counts from 0 to 2.
Loop Control: break, next, and loop
Inside any loop or iterator you can change the flow: break exits immediately, while next skips to the following iteration. Ruby also has a bare loop keyword that runs forever until a break stops it.
Create a file named loop_control.rb:
| |
Here break if n > 5 reads naturally as a statement modifier, and next if n.even? skips even numbers without an explicit else. The accumulator stops at 60 because the loop only checks the threshold after adding the current value.
Running with Docker
You can run every example without installing Ruby locally by using the official Alpine image.
| |
Expected Output
Running control_flow.rb:
It's a pleasant day
Please log in to continue
Access granted
Warning!
You are an adult
Running case_when.rb:
Grade: B
Got a string of length 5
Good afternoon
Running loops.rb:
while: 1
while: 2
while: 3
until: 3
until: 2
until: 1
Color: red
Color: green
Color: blue
times: 0
times: 1
times: 2
range: 1
range: 2
range: 3
Running loop_control.rb:
break demo: 1
break demo: 2
break demo: 3
break demo: 4
break demo: 5
odd: 1
odd: 3
odd: 5
Sum stopped at: 60
Total attempts: 3
Key Concepts
unlessisifnegated — use it when a positive condition reads more clearly as “do this unless something is true,” but avoid pairing it withelsefor readability.- Statement modifiers — appending
iforunlessto the end of a line (puts "ok" if valid) is idiomatic Ruby for short, single-action conditions. casematches with===— this lets a singlecasematch ranges (90..100), classes (Integer,String), and more, making it far more flexible than a C-style switch.- Everything is an expression —
if,unless, andcaseall return a value, so you can assign their result directly to a variable. - Prefer iterators over manual loops —
each,times, and ranges with blocks are the idiomatic Ruby way to repeat work, whilewhile/untilremain available for condition-driven loops. breakandnext—breakleaves the loop entirely;nextjumps to the following iteration. Both pair naturally with statement modifiers.- Ranges use
..and...— two dots include the end value, three dots exclude it; this distinction matters in bothcaseclauses and iteration.
Comments
Loading comments...
Leave a Comment