case/when Conditionals

Reviewed & published by Brayan K

A case expression is Ruby's multi-branch conditional: it tests a subject against each when clause using the === operator and runs the first branch that matches.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

Because === is defined by ranges, classes, and regexes, one case can switch on numeric ranges, types, and patterns — and it returns a value you can assign.

What You'll Learn in This Lesson

1️⃣ Basic case/when & Returning a Value

Write case subject, then one when per option. Ruby checks each in order and runs the first match — no break needed, because there's no fall-through. List several values with commas, and remember the whole expression returns a value you can assign.

# case/when compares the subject against each "when" using ===
grade = 85
case grade
when 90..100 then puts "A"
when 80..89  then puts "B"     # 80..89 === 85 is true
when 70..79  then puts "C"
else              puts "F"
end

# case returns a value, so you can assign it
day = "Sat"
kind =
  case day
  when "Sat", "Sun" then "weekend"   # multiple values in one when
  else "weekday"
  end
puts kind

2️⃣ Matching Classes & Regexes

Since every class defines === as an instance check, you can branch on type with when Integer, when String, and so on. A regex's === tests for a match, so when /\d+/ matches any string containing a digit.

# === is what makes when so powerful: Class, Range, and Regexp all define it
def describe(x)
  case x
  when Integer then "an integer"     # Integer === 42
  when String  then "a string"       # String  === "hi"
  when Array   then "an array"
  when Range   then "a range"
  else "something else"
  end
end

puts describe(42)
puts describe("hi")
puts describe([1, 2])
puts describe(1..5)
puts describe(3.14)
# Regexp in when: /pattern/ === string tests for a match
def classify(code)
  case code
  when /\Ayes\z/i  then "affirmative"   # whole string "yes" (any case)
  when /\Ano\z/i   then "negative"
  when /\d+/        then "contains digits"
  else "unknown"
  end
end

puts classify("YES")
puts classify("no")
puts classify("order 42")
puts classify("maybe")

3️⃣ case Without a Subject

Leave the subject off after case and each when becomes a full boolean test — an elegant stand-in for a long if/elsif chain when your conditions don't share a single value.

# case with NO subject acts like an if/elsif chain — each when is a full test
temp = 30
label =
  case
  when temp < 0   then "freezing"
  when temp < 15  then "cold"
  when temp < 25  then "mild"
  else "hot"
  end
puts label

Your turn. Fill in each ___ blank, then run it.

# 🎯 YOUR TURN — fill in the blanks, then run with: ruby ticket.rb

def ticket_price(age)
  ___ age                  # 👉 keyword that starts the multi-branch check
  when 0..5   then "free"
  when 6..17  then "$8"
  when 65___  then "$10"   # 👉 an open-ended range: 65 and up
  else "$15"
  end
end

puts ticket_price(3)
puts ticket_price(12)
puts ticket_price(70)
puts ticket_price(30)

# ✅ Expected output:
#    free
#    $8
#    $10
#    $15

Mini-Challenge: HTTP Status Classifier

Combine exact values, comma-separated values, and ranges in one case. Run with ruby status.rb.

# 🎯 MINI-CHALLENGE: an HTTP status classifier.
# Save as status.rb and run with: ruby status.rb
#
# Write http_status(code) using case/when with ranges:
#   200          -> "OK"
#   301 or 302   -> "Redirect"   (two values in one when)
#   400..499     -> "Client Error"
#   500..599     -> "Server Error"
#   anything else-> "Unknown"
# Then print "<code>: <label>" for [200, 302, 404, 503, 100].
#
# ✅ Example output:
#    200: OK
#    302: Redirect
#    404: Client Error
#    503: Server Error
#    100: Unknown

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — case/when

ConceptRuby Syntax
Match a valuewhen 5 then ...
Several valueswhen 1, 2, 3
Match a rangewhen 80..89
Match a typewhen Integer
Match a patternwhen /\d+/
No subjectcase; when x < 0; ...

🎉 Lesson Complete!

Practice quiz

Which operator does case/when use to test each branch?

  • ==
  • <=>
  • ===
  • eql?

Answer: ===. case/when matches using the case-equality operator === (when_value === subject).

For when 80..89 matching subject 85, which comparison does Ruby actually evaluate?

  • (80..89) === 85
  • 85 === (80..89)
  • 85 == 80..89
  • (80..89) <=> 85

Answer: (80..89) === 85. The when value is on the LEFT of ===, so Ruby tests (80..89) === 85, which is true.

Given grade = 85, what does this print? case grade; when 90..100 then puts "A"; when 80..89 then puts "B"; else puts "F"; end

  • A
  • F
  • Nothing
  • B

Answer: B. 85 falls in the 80..89 range, so the second branch runs and prints B.

Why does when Integer match the value 42?

  • Because 42.is_a?(when) is true
  • Because Integer === 42 returns true (Class#=== is an instance check)
  • Because 42 == Integer
  • It does not match

Answer: Because Integer === 42 returns true (Class#=== is an instance check). Class defines === as an instance check, so Integer === 42 is true and the branch matches.

Does Ruby's case/when fall through to later branches like C's switch?

  • No — only the first matching branch runs, no break needed
  • Yes, you need break to stop it
  • Only for string subjects
  • Only inside a loop

Answer: No — only the first matching branch runs, no break needed. There is no fall-through in Ruby; only the first matching when runs, so break is unnecessary.

How do you make several values share one branch?

  • when "Sat" or "Sun"
  • when ["Sat" && "Sun"]
  • when "Sat", "Sun" (comma-separated)
  • Use two separate case statements

Answer: when "Sat", "Sun" (comma-separated). List multiple values with commas: when "Sat", "Sun" then ... matches either.

What does a case with NO subject behave like?

  • An infinite loop
  • An if/elsif chain where each when is a full boolean test
  • A method definition
  • It is a syntax error

Answer: An if/elsif chain where each when is a full boolean test. Subject-less case turns each when into a standalone boolean condition, like if/elsif.

A case expression itself:

  • Returns nil always
  • Cannot be assigned to a variable
  • Returns the subject
  • Returns the value of the branch that ran, so you can assign it

Answer: Returns the value of the branch that ran, so you can assign it. case is an expression returning the matched branch's value, so label = case x ... end works.

What does when /\d+/ match against a string?

  • Strings that are exactly digits
  • Strings that contain at least one digit
  • Only the number zero
  • Empty strings

Answer: Strings that contain at least one digit. Regexp#=== tests for a match, so /\d+/ matches any string containing one or more digits.

Why does when Numeric match both an Integer and a Float?

  • Numeric is a special keyword
  • Ruby converts everything to Numeric
  • Class matching with === respects inheritance, and both subclass Numeric
  • It only matches Integer, not Float

Answer: Class matching with === respects inheritance, and both subclass Numeric. Integer and Float both descend from Numeric, and === honors inheritance, so both match.

Continue this course

Frequently asked questions

How does case/when actually decide which branch matches?

Ruby evaluates when_value === subject for each branch, in order, and runs the first one that returns true. The triple-equals === is called the 'case equality' operator and each class defines it to mean something useful: for a Range it asks 'does this range include the value?', for a Class it asks 'is this an instance?', and for a Regexp it asks 'does the string match?'. That single mechanism is why one case statement can switch on ranges, types, and patterns all at once.

Can I match on a value's type or class with case?

Yes, and it's idiomatic. Because Class === object returns true when object is an instance of that class, you can write when Integer, when String, when Array and branch on type. It even respects inheritance, so when Numeric matches both Integers and Floats. This is a clean alternative to a chain of obj.is_a?(...) checks, though if you find yourself type-switching often it can be a hint to use polymorphism instead.

What's the difference between case with and without a subject?

case subject ... when X compares X === subject for each branch. case with NO subject — just case on its own line — turns each when into a standalone boolean test, exactly like an if/elsif/else chain. The subject-less form is handy when your conditions involve different variables or comparisons (when temp < 0, when name.empty?) that don't share a single value to switch on.

Does case/when fall through like switch in C or JavaScript?

No — and that's a feature. In Ruby only the first matching when runs, and there's no implicit fall-through, so you never need break statements. To make several values share a branch you list them with commas: when "a", "b", "c". And because the whole case expression returns the value of the branch that ran, you can assign its result directly to a variable, which is cleaner than setting a variable inside each branch.