100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Ruby

Case Expressions

How Ruby's case/when expression uses the triple-equals operator for flexible pattern matching against classes, ranges, regexes, and values.

Control FlowBeginner8 min readJul 9, 2026
Analogies

Case Expressions

Ruby's case expression is a more powerful cousin of the switch statement found in C-family languages. Instead of comparing values strictly by equality, each when clause is evaluated using the === (triple-equals) operator, called on the when value with the case subject as its argument. Because different classes implement === differently — Range checks membership, Regexp checks for a match, Class checks is_a?, and Proc/Lambda invokes the callable — a single case expression can pattern-match against wildly different criteria without any special syntax. case is also an expression, not just a statement, so it returns a value that can be assigned directly.

🏏

Cricket analogy: Ruby's case is like a third umpire reviewing a dismissal against several different possible criteria at once -- a run-out check, an lbw check, a catch check -- each using its own specific evaluation method, unlike a simple switch that would only compare one fixed value.

The role of ===

The key to understanding case/when is that when value desugars to value === subject, not subject == value. This ordering matters: it's the when clause's class that decides how the comparison happens. Integer === 5 checks whether 5 is an Integer; (1..10) === 5 checks range membership; /^b/ === 'bar' checks whether the string matches the regex. This is why case can elegantly branch on type, range, and pattern all in the same expression.

🏏

Cricket analogy: when value desugars to value === subject, so it's the when clause deciding the comparison, like how a specific fielding-restriction rule (the powerplay range) decides whether over 5 counts, rather than over 5 deciding which rule applies to it.

ruby
def describe(value)
  case value
  when Integer
    "an integer"
  when String
    "a string"
  when /^admin_/
    "an admin-prefixed string"
  when nil
    "nothing at all"
  else
    "something else entirely"
  end
end

puts describe(42)      # "an integer"
puts describe("hello") # "a string"

Subject-less case, and structural pattern matching with case/in

You can omit the subject entirely and use case as a cleaner alternative to a long if/elsif chain — each when clause then acts as its own boolean condition. Separately, since Ruby 2.7, case/in provides structural pattern matching, distinct from ===-based case/when: it can destructure arrays and hashes, bind variables from their contents, and apply guard clauses, which is especially useful when working with nested data such as parsed JSON.

🏏

Cricket analogy: Omitting the case subject is like a captain running through field settings as a checklist of true/false conditions instead of comparing against one ball's trajectory; case/in, meanwhile, is like the analyst destructuring a full match scorecard JSON into named fields (runs, wickets, overs) with guard conditions on each.

ruby
# subject-less case, reads like a cleaner if/elsif chain
score = 82
grade = case
        when score >= 90 then "A"
        when score >= 80 then "B"
        else "F"
        end

# case/in destructures a hash and binds a variable
config = { role: "admin", permissions: ["read", "write"] }
case config
in { role: "admin", permissions: }
  puts "Admin with permissions: #{permissions.join(', ')}"
in { role: "guest" }
  puts "Guest access"
end

Python only gained a structural match statement in 3.10 (2021), decades after Ruby's case/when shipped ===-based matching. JavaScript still has no true pattern-matching switch — its switch uses strict === equality only, so it can't branch on ranges, regexes, or classes the way Ruby's case can.

Order matters in case/when: Ruby evaluates when clauses top to bottom and stops at the first match. Placing a broad matcher like when Integer before a narrower one like when 1..9 means the narrower clause becomes unreachable dead code — always order when clauses from most specific to least specific.

  • case/when compares using when_value === subject, not ==, which is why the when clause's type determines matching behavior.
  • Range, Regexp, Class/Module, and Proc all implement === differently, enabling flexible matching without special syntax.
  • case without a subject works like a cleaner if/elsif chain, evaluating each when as its own boolean expression.
  • case is an expression and returns a value, so its result can be assigned directly to a variable.
  • case/in (Ruby 2.7+) is a distinct structural pattern-matching feature that can destructure arrays/hashes and bind variables.
  • when clauses are checked in order, so broader matchers placed before narrower ones will shadow the more specific cases.

Practice what you learned

Was this page helpful?

Topics covered

#Ruby#RubyStudyNotes#Programming#CaseExpressions#Case#Expressions#Role#Subject#StudyNotes#SkillVeris