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" .
4,288 10 10 gold badges 40 40 silver badges 67 67 bronze badges answered Jun 4, 2009 at 1:22 236k 30 30 gold badges 304 304 silver badges 392 392 bronze badgesYou can also do regex on the passed argument: when /thisisregex/ next line puts "This is the found match nr. 1 #" end
Commented Jan 20, 2013 at 15:34Also worth noting, you can shorten your code by putting the when and return statement on the same line: when "foo" then "bar"
Commented May 11, 2018 at 23:40Important: 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 .
Commented Sep 3, 2018 at 9:45 So many up votes yet not even a mention of the keyword then . Please also see the other answers. Commented Jun 4, 2019 at 23:05case. 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.
answered Apr 17, 2011 at 15:20 52.4k 33 33 gold badges 153 153 silver badges 194 194 bronze badges obj='hello';case obj; when 'hello' then puts "It's hello" end Commented Feb 10, 2017 at 9:59Having the .class part in is interesting to note, thanks. Of course, this is entirely appropriate behavior (though I could see how it might be a common mistake to think that would print It is a string ). you're testing the class of some arbitrary object, not the object itself. So, for example: case 'hello'.class when String then "String!" when Class then "Class!" else "Something else" end results in: "Class!" This works the same for 1.class , <>.class , etc. Dropping .class , we get "String!" or "Something else" for these various values.
Commented Apr 11, 2019 at 7:14 thanks for this! this is more elegant than my solution which was to use "case obj.class.to_s" Commented Jul 23, 2020 at 3:22The implicit === in case statements can be a little tricky, but if you remember about it, it is powerful.
Commented Oct 26, 2022 at 19:47Sigh "but if you remember about it, it is powerful". And if you don't it's a nice source of bugs that no linter/code tools can ever pick up. Sorry, all the implicit behavior is really problematic.
Commented Jan 30, 2023 at 17:12It is done using case in Ruby. Also see "Switch statement" on Wikipedia.
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
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.)
answered Jun 4, 2009 at 1:20 nonopolarity nonopolarity 150k 136 136 gold badges 486 486 silver badges 772 772 bronze badges when (-1.0/0.0)..-1 then "Epic fail" Commented Apr 17, 2011 at 23:49This is the answer I used, because I am defining a variable based on the results of a case switch. Rather than saying type = #
I love ruby so much for letting me just put a switch statement on a variable like that, less clutter and gets right to the point :D
Commented Jul 22, 2020 at 17:47To 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.
160k 44 44 gold badges 218 218 silver badges 306 306 bronze badges answered Jul 5, 2012 at 13:19 mmdemirbas mmdemirbas 9,148 6 6 gold badges 47 47 silver badges 55 55 bronze badges Thanks, this was helpful for having multiple options on one line. I had been trying to use or Commented Dec 9, 2014 at 20:19Many 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.
answered Dec 7, 2013 at 12:11 Robert Kajic Robert Kajic 8,989 5 5 gold badges 47 47 silver badges 43 43 bronze badgesFallthrough is more of a problem than a feature. If Ruby supported the imitation of the fallthrough it would be easily solved by accepting the same condition on multiple when lines, and executing that block where the condition matches. But it does not support it.
Commented Jun 28, 2022 at 9:19In 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
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
1 1 1 silver badge
answered Aug 1, 2013 at 0:04
13k 4 4 gold badges 41 41 silver badges 66 66 bronze badges
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.
160k 44 44 gold badges 218 218 silver badges 306 306 bronze badges answered Oct 16, 2012 at 12:17 Haris Krajina Haris Krajina 15.2k 12 12 gold badges 68 68 silver badges 83 83 bronze badgesIt'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
answered Feb 5, 2016 at 20:40
DigitalRoss DigitalRoss
145k 25 25 gold badges 252 252 silver badges 332 332 bronze badges
If 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
160k 44 44 gold badges 218 218 silver badges 306 306 bronze badges
answered Jul 3, 2014 at 6:46
Manish Shrivastava Manish Shrivastava
31.7k 13 13 gold badges 101 101 silver badges 102 102 bronze badges
Ruby 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 more when clauses. The first when clause 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 successful when clause, or nil if there is no such clause.
A case statement can end with an else clause. Each when a statement can have multiple candidate values, separated by commas.
case x when 1,2,3 puts "1, 2, or 3" when 10 puts "10" else puts "Some other number" end
case x when 1,2,3 then puts "1, 2, or 3" when 10 then puts "10" else puts "Some other number" end
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!"
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
160k 44 44 gold badges 218 218 silver badges 306 306 bronze badges
answered Jul 18, 2016 at 19:59
Lahiru Jayaratne Lahiru Jayaratne
1,754 4 4 gold badges 33 33 silver badges 35 35 bronze badges
Depending on your case, you could prefer to use a hash of methods.
If there is a long list of when s 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 = # 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])
160k 44 44 gold badges 218 218 silver badges 306 306 bronze badges
answered Sep 18, 2014 at 14:48
7,782 4 4 gold badges 54 54 silver badges 66 66 bronze badges
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
31.5k 22 22 gold badges 109 109 silver badges 132 132 bronze badges
answered Nov 5, 2013 at 7:29
Sonu Oommen Sonu Oommen
1,173 1 1 gold badge 10 10 silver badges 21 21 bronze badges
Multi-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
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
31.5k 22 22 gold badges 109 109 silver badges 132 132 bronze badges
answered Jan 20, 2014 at 11:45
794 2 2 gold badges 9 9 silver badges 21 21 bronze badges
why not just case some_string, when /\d/, (stuff), when /[a-zA-Z]/, (stuff), end (where , means newline)
Commented Jan 26, 2014 at 3:21oh, and the first part is already covered in this answer, and many answers already mention regex. Frankly, this answer adds nothing new, and I'm downvoting and voting to delete it.
Commented Jan 26, 2014 at 3:22@DoorknobofSnow This is to show that you can use Regex solution and comma seperated values in switch case. Not sure why the solution is giving you so much ache.
Commented Jan 27, 2014 at 5:19 so if they got a "F", a legit grade, its their fault your code is missing a case? Commented Jun 20, 2014 at 18:48@Doorknob I also agree that this is just a repetition of previous answers, but the fact that he presented instead an empty case using the .match() method is indeed an alternative answer to the first and previous Regex answer in here. I can't see how and why this method would be preferable though.
Commented Apr 18, 2018 at 9:57You can write case expressions in two different ways in Ruby:
age = 20 case when age >= 21 puts "display something" when 1 == 0 puts "omg" else puts "default condition" end
case params[:unknown] when /Something/ then 'Nothing' when /Something else/ then 'I dont know' end
160k 44 44 gold badges 218 218 silver badges 306 306 bronze badges
answered Feb 16, 2017 at 9:32
Vaisakh VM Vaisakh VM
1,071 11 11 silver badges 9 9 bronze badges
Though your code might answer the question, you should add at least a short description on what your code does and how it solves the initial problem.
Commented Feb 16, 2017 at 10:16You can do like this in more natural way,
case expression when condtion1 function when condition2 function else function end
answered May 26, 2016 at 9:15
646 8 8 silver badges 19 19 bronze badges
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
160k 44 44 gold badges 218 218 silver badges 306 306 bronze badges answered Aug 6, 2013 at 20:18 103 1 1 silver badge 5 5 bronze badgesFor reference, the "space-ship" method is <=>, which is used to return -1, 0, 1, or nil depending on whether the comparison returns less-than, equal, greater-than, or not-comparable respectively. Ruby's Comparable module documentation explains it.=>
Commented Sep 11, 2013 at 15:18As 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:
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? .
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.
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.