case/when: The Switch Statement That Actually Delivers
Ruby'scase/when uses the === operator for matching, which behaves differently depending on the type. This makes it absurdly more powerful than a simple equality check. Regex patterns, ranges, classes, lambdas: they all work as conditions. Perl's deprecated given/when never even came close.
Part 1: Basic Usage
One statement. Six completely different types of matching. All usingcase line when %r~^ERROR~ then handle_error(line) # regex match when %r~^WARN~ then handle_warn(line) when "" then next # empty string when 1..100 then puts "in range" # range membership when Integer then puts "it's a number" # class check when ->(x) { x.size > 100 } then puts "long" # lambda/proc end
=== under the hood.
Part 2: What === Does for Each Type
| Type | What === Does |
Example |
|---|---|---|
| Regex | =~ match |
%r~error~ === "error log" => true |
| Range | include? |
(1..10) === 5 => true |
| Class | is_a? |
String === "hello" => true |
| Proc/Lambda | call |
->(x){x>5} === 10 => true |
| String | == equality |
"hello" === "hello" => true |
| Symbol | == equality |
:error === :error => true |
Part 3: Lambdas as Smart Matchers
SinceProc#=== calls the proc, you can use lambdas as conditions in case statements:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create reusable conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ multiple_of = ->(factor) { ->(n) { (n % factor).zero? } } case number when multiple_of[3] then puts "Multiple of 3" when multiple_of[7] then puts "Multiple of 7" when multiple_of[11] then puts "Multiple of 11" end
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Day-of-week matching with lambdas # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ is_weekend = ->(date) { [0, 6].include?(date.wday) } is_monday = ->(date) { date.wday == 1 } case Time.now when is_weekend then puts "Weekend!" when is_monday then puts "Monday..." else puts "Weekday" end
Part 4: Case Without Expression
When you usecase without an expression, it acts like an if/elsif chain:
case when line.empty? next when line =~ %r~^#~ next # skip comments when line.length > 1000 warn "line too long at #{$.}" else process(line) end
Part 5: Case as Expression
Ruby'scase returns a value, so you can assign the result:
This is way cleaner than a chain of if/elsif blocks that all assign to the same variable. The intent is obvious: classify and assign.severity = case line when %r~CRITICAL|FATAL~i then :critical when %r~ERROR~i then :error when %r~WARN~i then :warning when %r~INFO~i then :info when %r~DEBUG~i then :debug else :unknown end counts[severity] += 1
Created By: Wildcard Wizard. Copyright 2026