case / when (Ruby)
The case/when construct in Ruby is a syntax for writing multi-branch conditional logic concisely. Internally it uses the === operator for matching, so you can specify not only numbers and strings but also range objects, regular expressions, and class names as conditions.
Syntax
# Basic syntax
case target_value
when value1
# Executed when value1 matches (omitting then is the common style)
when value2, value3
# Executed when either value2 or value3 matches (multi-value match)
when range
# Matches against a Range object
when /regexp/
# Matches against a regular expression
when ClassName
# Checks whether the target is an instance of that class
else
# Executed when no when clause matches
end
# Inline style using then (useful for putting everything on one line)
case target_value
when value1 then action1
when value2 then action2
end
# Can be used as an expression (the last evaluated expression becomes the value)
result = case target_value
when value1 then "A"
when value2 then "B"
else "C"
end
Keywords and Match Patterns
| Expression | Description |
|---|---|
| when value | Matches the target value using the === operator. The block is executed on a match. |
| when value1, value2 | Lists multiple values separated by commas. Executes if any one of them matches. |
| when range | Uses Range#=== to check whether the target value falls within the range. |
| when /regexp/ | Uses Regexp#=== to check whether the target string matches the pattern. |
| when ClassName | Uses Module#=== to check whether the target is an instance of that class. |
| then | Used to put a when clause and its action on a single line. Can be omitted. |
| else | Executed when no when clause matches. Can be omitted. |
Sample Code
Determining the role of Steins;Gate characters. A basic example of matching against string literals and using an else clause.
character_role.rb
characters = ["Okabe Rintaro", "Makise Kurisu", "Shiina Mayuri", "Hashida Itaru", "Kiryuu Moeka"]
characters.each do |name|
role = case name
when "Okabe Rintaro" then "Director of the Future Gadget Lab — self-proclaimed mad scientist"
when "Makise Kurisu" then "Genius scientist — co-developer of the time machine theory"
when "Shiina Mayuri" then "Childhood friend — cosplay designer"
when "Hashida Itaru" then "Daru — super hacker"
else "Lab member (details unknown)"
end
puts "#{name}: #{role}"
end
ruby character_role.rb Okabe Rintaro: Director of the Future Gadget Lab — self-proclaimed mad scientist Makise Kurisu: Genius scientist — co-developer of the time machine theory Shiina Mayuri: Childhood friend — cosplay designer Hashida Itaru: Daru — super hacker Kiryuu Moeka: Lab member (details unknown)
Matching against a numeric Range. Changes the message based on Okabe Rintaro's time leap count.
leap_count.rb
# Range#=== is used, giving the same result as between?
leap_count = 23
message = case leap_count
when 0
"No time leaps yet."
when 1..5
"Early-stage time leaps."
when 6..15
"Getting closer to the truth through repetition."
when 16..Float::INFINITY
"Almost reached the Beta world line."
end
puts "Time leap #{leap_count}: #{message}"
ruby leap_count.rb Time leap 23: Almost reached the Beta world line.
Matching against regular expressions. Determines the pattern of Makise Kurisu's handle names.
handle_check.rb
handles = ["Christina", "Kurisu_0571", "assistant", "hououin_kyouma_777", "mayuri*"]
handles.each do |handle|
category = case handle
when /\A[A-Z][a-z]+\z/
"Real-name style handle"
when /\A\w+_\d+\z/
"User ID style handle"
when /\Aassistant\z/i
"Assistant account"
when /[^a-zA-Z0-9_]/
"Handle containing special characters"
else
"Standard handle"
end
puts "#{handle}: #{category}"
end
ruby handle_check.rb Christina: Real-name style handle Kurisu_0571: User ID style handle assistant: Assistant account hououin_kyouma_777: User ID style handle mayuri*: Handle containing special characters
Matching against class names. Switches processing based on the type of lab member data.
type_dispatch.rb
# Module#=== is used, equivalent to is_a?
lab_data = ["Okabe Rintaro", 18, 3.14, :kurisu, nil, true]
lab_data.each do |item|
description = case item
when String
"String: \"#{item}\""
when Integer
"Integer: #{item} (lab member number)"
when Float
"Float: #{item}"
when Symbol
"Symbol: #{item}"
when NilClass
"nil: no value"
when TrueClass, FalseClass
"Boolean: #{item}"
end
puts description
end
ruby type_dispatch.rb String: "Okabe Rintaro" Integer: 18 (lab member number) Float: 3.14 Symbol: kurisu nil: no value Boolean: true
Multi-value matching. Groups lab members by affiliation using comma-separated when values.
group_match.rb
members = ["Okabe Rintaro", "Makise Kurisu", "Shiina Mayuri", "Hashida Itaru", "Kiryuu Moeka"]
members.each do |name|
group = case name
when "Okabe Rintaro", "Shiina Mayuri", "Hashida Itaru"
"Founding members"
when "Makise Kurisu", "Kiryuu Moeka"
"Later members"
else
"Other"
end
puts "#{name}: #{group}"
end
ruby group_match.rb Okabe Rintaro: Founding members Makise Kurisu: Later members Shiina Mayuri: Founding members Hashida Itaru: Founding members Kiryuu Moeka: Later members
Overview
Ruby's case/when construct uses the === operator internally for matching. For integers and strings a normal equality comparison is performed, while Range performs a range membership check equivalent to include?, Regexp performs pattern matching, and Module performs an instance check. The behavior switches automatically based on the class of the match target, letting you write diverse conditions intuitively without worrying about type checks.
then is used when you want to write a when clause and its action on a single line. When multiple lines of processing follow, omitting then and using a newline is common style. Both produce the same behavior.
When no target value is given after case (the case ... when expression style), the construct behaves like if/elsif. This form is valid, but it can be confusing for readers, so if/elsif is often used for simple conditional branching while case/when is typically reserved for value matching.
Pattern matching (advanced structural decomposition matching available since Ruby 3.0) is a separate feature from case/when. For more on regular expression matching, see Regexp / match. For range objects, see Range / to_a / include? / cover?.
Common Mistakes
Writing comparison operators instead of expressions in a when clause
A when clause expects a value, a range, a regular expression, or a class name. Writing comparison operators such as > or < directly is a syntax error. To use comparison operators, either omit the target value after case (valueless case) or use if/elsif.
when_ng.rb
leap_count = 23
# Writing a comparison operator in when causes a syntax error
result = case leap_count
when > 20 then "Almost at world line convergence"
when > 10 then "Mid-stage time leaps"
else "Early stage"
end
puts result
ruby when_ng.rb when_ng.rb:4: syntax error, unexpected '>'
After fix:
when_ok.rb
leap_count = 23
# Use a Range object, or write it as if/elsif
result = case leap_count
when 21..Float::INFINITY then "Almost at world line convergence"
when 11..20 then "Mid-stage time leaps"
else "Early stage"
end
puts result
ruby when_ok.rb Almost at world line convergence
Confusing the in operator with a range in when
The case/in construct (pattern matching since Ruby 2.7) is a different syntax from case/when. When using ranges in case/when, pass the Range object directly to when as when 1..10. Guard conditions like when x if x > 0 belong to the case/in syntax.
range_ng.rb
lab_number = 4
# Using in inside case/when is a syntax error
result = case lab_number
when 1..5 in :founder then "Founding member"
else "Later member"
end
ruby range_ng.rb range_ng.rb:6: syntax error, unexpected 'in'
After fix:
range_ok.rb
lab_number = 4
# In case/when, pass a Range object directly to when
result = case lab_number
when 1..3 then "Founding member"
when 4..10 then "Early member"
else "Later member"
end
puts "Lab member ##{lab_number}: #{result}"
ruby range_ok.rb Lab member #4: Early member
Trying to write multiple actions in an inline then clause
The one-line style using then is intended for a single expression. While multiple statements can technically be separated by semicolons after then, this hurts readability. When a when clause requires multiple actions, omitting then and using a newline is the common style.
then_ng.rb
okabe_status = "IBN5100 found" # Chaining multiple actions with semicolons after then is hard to read case okabe_status when "IBN5100 found" then puts "Faris!"; puts "It's in Akihabara!"; puts "We need to get it" when "Time machine complete" then puts "It's done!" end
After fix:
then_ok.rb
okabe_status = "IBN5100 found" # When multiple actions follow, omit then and use newlines case okabe_status when "IBN5100 found" puts "Faris!" puts "It's in Akihabara!" puts "We need to get it" when "Time machine complete" puts "It's done!" end
ruby then_ok.rb Faris! It's in Akihabara! We need to get it
If you find any errors or copyright issues, please contact us.