How do I write a switch statement in Ruby?
27 Answers
Ruby uses the case expression instead.
case x when 1..5 "It's between 1 and 5" when 6 "It's 6" when "foo", "bar" "It's either foo or bar" when String "You passed a string" else "You gave me #{x} -- I have no idea what to do with that." end Ruby compares the object in the when clause with the object in the case clause using the === operator. For example, 1..5 === x, and not x === 1..5.
This allows for sophisticated when clauses as seen above. Ranges, classes and all sorts of things can be tested for rather than just equality.
Unlike switch statements in many other languages, Ruby’s case does not have fall-through, so there is no need to end each when with a break. You can also specify multiple matches in a single when clause like when "foo", "bar".
case...when behaves a bit unexpectedly when handling classes. This is due to the fact that it uses the === operator.
That operator works as expected with literals, but not with classes:
1 === 1 # => true Fixnum === Fixnum # => false This means that if you want to do a case ... when over an object's class, this will not work:
obj = 'hello' case obj.class when String print('It is a string') when Fixnum print('It is a number') else print('It is not a string or number') end Will print "It is not a string or number".
Fortunately, this is easily solved. The === operator has been defined so that it returns true if you use it with a class and supply an instance of that class as the second operand:
Fixnum === 1 # => true In short, the code above can be fixed by removing the .class from case obj.class:
obj = 'hello' case obj # was case obj.class when String print('It is a string') when Fixnum print('It is a number') else print('It is not a string or number') end I hit this problem today while looking for an answer, and this was the first appearing page, so I figured it would be useful to others in my same situation.
3It is done using case in Ruby. Also see "Switch statement" on Wikipedia.
Quoted:
case n when 0 puts 'You typed zero' when 1, 9 puts 'n is a perfect square' when 2 puts 'n is a prime number' puts 'n is an even number' when 3, 5, 7 puts 'n is a prime number' when 4, 6, 8 puts 'n is an even number' else puts 'Only single-digit numbers are allowed' end Another example:
score = 70 result = case score when 0..40 then "Fail" when 41..60 then "Pass" when 61..70 then "Pass with Merit" when 71..100 then "Pass with Distinction" else "Invalid Score" end puts result On around page 123 of The Ruby Programming Language (1st Edition, O'Reilly) on my Kindle, it says the then keyword following the when clauses can be replaced with a newline or semicolon (just like in the if then else syntax). (Ruby 1.8 also allows a colon in place of then, but this syntax is no longer allowed in Ruby 1.9.)
case...when
To add more examples to Chuck's answer:
With parameter:
case a when 1 puts "Single value" when 2, 3 puts "One of comma-separated values" when 4..6 puts "One of 4, 5, 6" when 7...9 puts "One of 7, 8, but not 9" else puts "Any other thing" end Without parameter:
case when b < 3 puts "Little than 3" when b == 3 puts "Equal to 3" when (1..10) === b puts "Something in closed range of [1..10]" end Please, be aware of "How to write a switch statement in Ruby" that kikito warns about.
1In Ruby 2.0, you can also use lambdas in case statements, as follows:
is_even = ->(x) { x % 2 == 0 } case number when 0 then puts 'zero' when is_even then puts 'even' else puts 'odd' end You can also create your own comparators easily using a Struct with a custom ===
Moddable = Struct.new(:n) do def ===(numeric) numeric % n == 0 end end mod4 = Moddable.new(4) mod3 = Moddable.new(3) case number when mod4 then puts 'multiple of 4' when mod3 then puts 'multiple of 3' end (Example taken from "Can procs be used with case statements in Ruby 2.0?".)
Or, with a complete class:
class Vehicle def ===(another_vehicle) self.number_of_wheels == another_vehicle.number_of_wheels end end four_wheeler = Vehicle.new 4 two_wheeler = Vehicle.new 2 case vehicle when two_wheeler puts 'two wheeler' when four_wheeler puts 'four wheeler' end (Example taken from "How A Ruby Case Statement Works And What You Can Do With It".)
0Many programming languages, especially those derived from C, have support for the so-called Switch Fallthrough. I was searching for the best way to do the same in Ruby and thought it might be useful to others:
In C-like languages fallthrough typically looks like this:
switch (expression) { case 'a': case 'b': case 'c': // Do something for a, b or c break; case 'd': case 'e': // Do something else for d or e break; } In Ruby, the same can be achieved in the following way:
case expression when 'a', 'b', 'c' # Do something for a, b or c when 'd', 'e' # Do something else for d or e end This is not strictly equivalent, because it's not possible to let 'a' execute a block of code before falling through to 'b' or 'c', but for the most part I find it similar enough to be useful in the same way.
You can use regular expressions, such as finding a type of string:
case foo when /^(true|false)$/ puts "Given string is boolean" when /^[0-9]+$/ puts "Given string is integer" when /^[0-9\.]+$/ puts "Given string is float" else puts "Given string is probably string" end Ruby's case will use the equality operand === for this (thanks @JimDeville). Additional information is available at "Ruby Operators". This also can be done using @mmdemirbas example (without parameter), only this approach is cleaner for these types of cases.
It's called case and it works like you would expect, plus lots more fun stuff courtesy of === which implements the tests.
case 5 when 5 puts 'yes' else puts 'else' end Now for some fun:
case 5 # every selector below would fire (if first) when 3..7 # OK, this is nice when 3,4,5,6 # also nice when Fixnum # or when Integer # or when Numeric # or when Comparable # (?!) or when Object # (duhh) or when Kernel # (?!) or when BasicObject # (enough already) ... end And it turns out you can also replace an arbitrary if/else chain (that is, even if the tests don't involve a common variable) with case by leaving out the initial case parameter and just writing expressions where the first match is what you want.
case when x.nil? ... when (x.match /'^fn'/) ... when (x.include? 'substring') ... when x.gsub('o', 'z') == 'fnzrq' ... when Time.now.tuesday? ... end 0If you are eager to know how to use an OR condition in a Ruby switch case:
So, in a case statement, a , is the equivalent of || in an if statement.
case car when 'Maruti', 'Hyundai' # Code here end See "How A Ruby Case Statement Works And What You Can Do With It".
0Ruby uses the case for writing switch statements.
As per the case documentation:
Case statements consist of an optional condition, which is in the position of an argument to
case, and zero or morewhenclauses. The firstwhenclause to match the condition (or to evaluate to Boolean truth, if the condition is null) “wins”, and its code stanza is executed. The value of the case statement is the value of the successfulwhenclause, ornilif there is no such clause.A case statement can end with an
elseclause. Eachwhena statement can have multiple candidate values, separated by commas.
Example:
case x when 1,2,3 puts "1, 2, or 3" when 10 puts "10" else puts "Some other number" end Shorter version:
case x when 1,2,3 then puts "1, 2, or 3" when 10 then puts "10" else puts "Some other number" end And as "Ruby's case statement - advanced techniques" describes Ruby case;
Can be used with Ranges:
case 5 when (1..10) puts "case statements match inclusion in a range" end ## => "case statements match inclusion in a range" Can be used with Regex:
case "FOOBAR" when /BAR$/ puts "they can match regular expressions!" end ## => "they can match regular expressions!" Can be used with Procs and Lambdas:
case 40 when -> (n) { n.to_s == "40" } puts "lambdas!" end ## => "lambdas" Also, can be used with your own match classes:
class Success def self.===(item) item.status >= 200 && item.status < 300 end end class Empty def self.===(item) item.response_size == 0 end end case http_response when Empty puts "response was empty" when Success puts "response was a success" end Depending on your case, you could prefer to use a hash of methods.
If there is a long list of whens and each of them has a concrete value to compare with (not an interval), it will be more effective to declare a hash of methods and then to call the relevant method from the hash like that.
# Define the hash menu = {a: :menu1, b: :menu2, c: :menu2, d: :menu3} # Define the methods def menu1 puts 'menu 1' end def menu2 puts 'menu 2' end def menu3 puts 'menu3' end # Let's say we case by selected_menu = :a selected_menu = :a # Then just call the relevant method from the hash send(menu[selected_menu]) Since switch case always returns a single object, we can directly print its result:
puts case a when 0 "It's zero" when 1 "It's one" end 0Multi-value when and no-value case:
print "Enter your grade: " grade = gets.chomp case grade when "A", "B" puts 'You pretty smart!' when "C", "D" puts 'You pretty dumb!!' else puts "You can't even use a computer!" end And a regular expression solution here:
print "Enter a string: " some_string = gets.chomp case when some_string.match(/\d/) puts 'String has numbers' when some_string.match(/[a-zA-Z]/) puts 'String has letters' else puts 'String has no numbers or letters' end 5You can write case expressions in two different ways in Ruby:
- Similar to a series of
ifstatements - Specify a target next to the
caseand eachwhenclause is compared to the target.
age = 20 case when age >= 21 puts "display something" when 1 == 0 puts "omg" else puts "default condition" end or:
case params[:unknown] when /Something/ then 'Nothing' when /Something else/ then 'I dont know' end 1You can do like this in more natural way,
case expression when condtion1 function when condition2 function else function end Lots of great answers but I thought I would add one factoid.. If you are attempting to compare objects (Classes) make sure you have a space ship method (not a joke) or understand how they are being compared
"Ruby Equality And Object Comparison" is a good discussion on the topic.
1As stated in many of the above answers, the === operator is used under the hood on case/when statements.
Here is additional information about that operator:
Case equality operator: ===
Many of Ruby's built-in classes, such as String, Range, and Regexp, provide their own implementations of the === operator, also known as "case-equality", "triple equals" or "threequals". Because it's implemented differently in each class, it will behave differently depending on the type of object it was called on. Generally, it returns true if the object on the right "belongs to" or "is a member of" the object on the left. For instance, it can be used to test if an object is an instance of a class (or one of its sub-classes).
String === "zen" # Output: => true Range === (1..2) # Output: => true Array === [1,2,3] # Output: => true Integer === 2 # Output: => true The same result can be achieved with other methods which are probably best suited for the job, such as is_a? and instance_of?.
Range Implementation of ===
When the === operator is called on a range object, it returns true if the value on the right falls within the range on the left.
(1..4) === 3 # Output: => true (1..4) === 2.345 # Output: => true (1..4) === 6 # Output: => false ("a".."d") === "c" # Output: => true ("a".."d") === "e" # Output: => false Remember that the === operator invokes the === method of the left-hand object. So (1..4) === 3 is equivalent to (1..4).=== 3. In other words, the class of the left-hand operand will define which implementation of the === method will be called, so the operand positions are not interchangeable.
Regexp Implementation of ===
Returns true if the string on the right matches the regular expression on the left.
/zen/ === "practice zazen today" # Output: => true # is similar to "practice zazen today"=~ /zen/ The only relevant difference between the two examples above is that, when there is a match, === returns true and =~ returns an integer, which is a truthy value in Ruby. We will get back to this soon.
puts "Recommend me a language to learn?" input = gets.chomp.downcase.to_s case input when 'ruby' puts "Learn Ruby" when 'python' puts "Learn Python" when 'java' puts "Learn Java" when 'php' puts "Learn PHP" else "Go to Sleep!" end 0I've started to use:
a = "secondcase" var_name = case a when "firstcase" then "foo" when "secondcase" then "bar" end puts var_name >> "bar" It helps compact code in some cases.
2$age = 5 case $age when 0 .. 2 puts "baby" when 3 .. 6 puts "little child" when 7 .. 12 puts "child" when 13 .. 18 puts "youth" else puts "adult" end See "Ruby - if...else, case, unless" for more information.
It's critical to emphasize the comma (,) in a when clause. It acts as an || of an if statement, that is, it does an OR comparison and not an AND comparison between the delimited expressions of the when clause. See the following case statement:
x = 3 case x when 3, x < 2 then 'apple' when 3, x > 2 then 'orange' end => "apple" x is not less than 2, yet the return value is "apple". Why? Because x was 3 and since ',`` acts as an||, it did not bother to evaluate the expressionx < 2'.
You might think that to perform an AND, you can do something like this below, but it doesn't work:
case x when (3 && x < 2) then 'apple' when (3 && x > 2) then 'orange' end => nil It doesn't work because (3 && x > 2) evaluates to true, and Ruby takes the True value and compares it to x with ===, which is not true, since x is 3.
To do an && comparison, you will have to treat case like an if/else block:
case when x == 3 && x < 2 then 'apple' when x == 3 && x > 2 then 'orange' end In the Ruby Programming Language book, Matz says this latter form is the simple (and infrequently used) form, which is nothing more than an alternative syntax for if/elsif/else. However, whether it is infrequently used or not, I do not see any other way to attach multiple && expressions for a given when clause.
No support for regular expressions in your environment? E.g. Shopify Script Editor (April, 2018):
[Error]: uninitialized constant RegExp
A workaround following a combination of methods already previously covered in here and here:
code = '!ADD-SUPER-BONUS!' class StrContains def self.===(item) item.include? 'SUPER' or item.include? 'MEGA' or\ item.include? 'MINI' or item.include? 'UBER' end end case code.upcase when '12345PROMO', 'CODE-007', StrContains puts "Code #{code} is a discount code!" when '!ADD-BONUS!' puts 'This is a bonus code!' else puts 'Sorry, we can\'t do anything with the code you added...' end I used ors in the class method statement since || has higher precedence than .include?.
If you still prefer using ||, even though or is preferable in this case, you can do this instead: (item.include? 'A') || .... You can test it in this repl.it.
If you need "less than" or "greater than":
case x when 1..5 "It's between 1 and 5" when 6 "It's 6" when 7..1.0/0 "It's equal or greater than 7" when -1.0/0..0 "It's equal or less than 0" end 1.0/0 is equal to Float::INFINITY, so you can use which you prefer.
After Ruby 2.6 you can use Endless Ranges, After Ruby 2.7 you can also use Beginless Ranges, so you can do for example:
case x when 1..5 "It's between 1 and 5" when 6 "It's 6" when (7..) "It's equal or greater than 7" when (..0) "It's equal or less than 0" end The case statement operator is like switch in the other languages.
This is the syntax of switch...case in C:
switch (expression) { case constant1: // statements break; case constant2: // statements break; . . . default: // default statements } This is the syntax of case...when in Ruby:
case expression when constant1, constant2 #Each when statement can have multiple candidate values, separated by commas. # statements next # is like continue in other languages when constant3 # statements exit # exit is like break in other languages . . . else # statements end For example:
x = 10 case x when 1,2,3 puts "1, 2, or 3" exit when 10 puts "10" # it will stop here and execute that line exit # then it'll exit else puts "Some other number" end For more information see the case documentation.
We can write switch statement for multiple conditions.
For Example,
x = 22 CASE x WHEN 0..14 THEN puts "#{x} is less than 15" WHEN 15 THEN puts "#{x} equals 15" WHEN 15 THEN puts "#{x} equals 15" WHEN 15..20 THEN puts "#{x} is greater than 15" ELSE puts "Not in the range, value #{x} " END 2Ruby supports a case expression instead.
Class matching:
case e = StandardError.new("testing") when Exception then puts "error!" else puts "ok!" end # => error! Multiple value matching:
case 3 when 1,2,3 then puts "1..3" when 4,5,6 then puts "4..6" else puts "?" end # => 1..3 Regex evaluation:
case "monkey" when /mon/ then puts "banana" else puts "?" end # => banana I prefer to use case + than
number = 10 case number when 1...8 then # ... when 8...15 then # ... when 15.. then # ... end