Conditionals, loops and case

Ruby · Essentials · 10 min

Ruby's conditionals are expressions, and its idioms (modifiers, unless, case with ranges) read almost like English.

if/elsif/else/end and unless (the negation of if) work as expected. In Ruby these are expressions: they return the value of the branch taken, so label = if score > 50 then "pass" else "fail" end is valid. The ternary cond ? a : b covers short cases.

Modifier forms put the condition after a single statement: return if list.empty?, retry_later unless connected?. They are idiomatic for guard clauses. Avoid unless with else or with negations; it gets hard to read.

case/when compares using ===, the "case equality" operator, so a when can be a value, a class, a range or a regex:

case input
when Integer then "number"
when 1..5 then "small"     # Range#=== checks inclusion
when /\A\d+\z/ then "digits" # Regexp#=== matches
else "other"
end

Loops: while cond ... end, until cond ... end and loop do ... end (exit with break). In practice Rubyists rarely write for; they use iterators: 3.times { |i| ... }, 1.upto(5), array.each. Inside blocks and loops, next skips to the next iteration and break exits.

&&, || and ! are the logical operators. The words and, or and not exist but have very low precedence; use them only for control flow like save or raise "failed", never in conditions.

Example

def classify(x)
  case x
  when Integer then x.negative? ? "negative" : "integer"
  when 0.0..1.0 then "fraction"
  when /\A\w+@\w+\.\w+\z/ then "email"
  when nil then "missing"
  else "unknown"
  end
end

[5, -2, 0.5, "a@b.io", nil, :x].each { |v| puts classify(v) }
# integer negative fraction email missing unknown (one per line)

grade = if 72 >= 70 then "pass" else "fail" end
puts grade                   # pass

3.times { |i| print i, " " } # 0 1 2
puts
n = 0
n += 1 until n * n > 50
puts n                       # 8

Remember

  • if, unless and case are expressions that return a value
  • case/when uses ===, so classes, ranges and regexes all work
  • Prefer iterators like times and each over for loops

Watch out for

  • Using and/or in assignments: x = true and false sets x to true because = binds tighter.

Check yourself

  1. Why does when Integer match 5 in a case statement?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.ruby-lang.org/en/3.4/syntax/control_expressions_rdoc.html