Using the Case (Switch) Ruby Statement

Woman programmer working in hip office

In most computer languages, the case (also known as switch) statement compares the value of a variable with that of several constants or literals and executes the first path with a matching case. In Ruby, it's a bit more flexible (and powerful).

Instead of a simple equality test being performed, the case equality operator is used, opening the door to many new uses.

There are some difference from other languages though. In C, a switch statement is a kind of replacement for a series of if and goto statements. The cases are technically labels, and the switch statement will go to the matching label. This exhibits a behavior called "fallthough," as the execution doesn't stop when it reaches another label.

This is usually avoided using a break statement, but fallthrough is sometimes intentional. The case statement in Ruby, on the other hand, can be seen as a shorthand for a series of if statements. There is no fallthrough, only the first matching case will be executed.

The Basic Form of a Case Statement

The basic form of a case statement is as follows.

name = gets.chomp
case name
when "Alice"
puts "Welcome Alice"
when /[qrz].+/i
puts "Your name begins with Q, R or Z, you're not welcome here!"
puts "Welcome stranger!"

As you can see, this is structured something like an if/else if/else conditional statement. The name (which we'll call the value), in this case inputted from the keyboard, is compared to each of the cases from the when clauses (i.e. cases), and the first when block with a matching case will be executed. If none of them match, the else block will be executed.

What's interesting here is how the value is compared to each of the cases. As mentioned above, in C++, and other C-like languages, a simple value comparison is used. In Ruby, the case equality operator is used.

Remember that the type of the left-hand side of a case equality operator is important, and the cases are always the left-hand side. So, for each when clause, Ruby will evaluate case === value until it finds a match.

If we were to input Bob, Ruby would first evaluate "Alice" === "Bob", which would be false since String#=== is defined as the comparison of the strings. Next, /[qrz].+/i === "Bob" would be executed, which is false since Bob doesn't begin with Q, R or Z.

Since none of the cases matched, Ruby will then execute the else clause.

How the Type Comes Into Play

A common use of the case statement is to determine the type of the value and do something different depending on its type. Though this breaks Ruby's customary duck typing, it's sometimes necessary to get things done.

This works by using the Class#=== (technically, the Module#===) operator, which tests if the right-hand side is_a? left-hand side.

The syntax is simple and elegant:

def do(thing)
case thing
when Sound
# Play the sound
when Music
# Play the music in the background
SoundManager.music_paused = false
when Graphic
# Display the graphic
# Unknown resource
raise "Unknown resource type"

Another Possible Form

If the value is omitted, the case statement works a bit differently: it works almost exactly like an if/else if/else statement. The advantages of using the case statement over an ​if statement, in this case, are merely cosmetic.

when name == "Bob"
puts "Hello Bob!"
when age == 100
puts "Happy 100th birthday!"
when occupation =~ /ruby/
puts "Hello, Rubyist!"
puts "I don't think I know you."

A More Compact Syntax

There are times when there are a large number of small when clauses. Such a case statement easily grows too large to fit on the screen. When this is the case (no pun intended), you can use the then keyword to put the body of the when clause on the same line.

While this makes for some very dense code, as long as each when clause is very similar, it actually becomes more readable.

When you should use single-line and multi-line when clauses are up to you, it's a matter of style. However, mixing the two is not recommended - a case statement should follow a pattern to be as readable as possible.

case arguments
when 1 then arg1(a)
when 2 then arg2(a,b)
when 3 then arg2(b,a,7)
when 4 then arg5(a,b,c,d,'test')
when 5 then arg5(a,b,c,d,e)

Case Assignment

Like if statements, case statements evaluate to the last statement in the when clause. In other words, they can be used in assignments to provide a kind of table. However, don't forget that case statements are much more powerful than simple array or hash lookups. Such a table doesn't necessarily need to use literals in the when clauses.

spanish = case number
when 1 then "Uno"
when 2 then "Dos"
when 3 then "Tres"

If there is no matching when clause and no else clause, then the case statement will evaluate to nil.