In most languages, the case (or '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). A simple equality test is not 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 goto 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 for 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!" else puts "Welcome stranger!" end
As you can see, this is structured something like an if/else if/else statements. The name (which we'll call the value), in this case input from the keyboard, is compared to each of the cases from the when clauses (which we'll call 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-like languages a simple value comparison is used. In Ruby, the case equality operator is used. Recall 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.
A common use for 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 SoundManager.play_sample(thing) when Music # Play the music in the background SoundManager.play_music(thing) SoundManager.music_paused = false when Graphic # Display the graphic Display.show(thing) else # Unknown resource raise "Unknown resource type" end
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 to using the case statement over an if statement in this case are merely cosmetic.
case when name == "Bob" puts "Hello Bob!" when age == 100 puts "Happy 100th birthday!" when occupation =~ /ruby/ puts "Hello, Rubyist!" else puts "I don't think I know you." end
A More Compact Syntax
There are times when there are a large number of small when clauses. Such a case statement soon grown to something 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 is 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) end
Like if statements, case statements evaluate to the last statement in the when clause executed. 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" end
If there is no matching when clause and no else clause, then the case statement will evaluate to nil.