Categories
conditional-statements ruby switch-statement

How to write a switch statement in Ruby

2238

How do I write a switch statement in Ruby?

0

    2889

    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".

    4

    • 17

      You can also do regex on the passed argument: when /thisisregex/ next line puts “This is the found match nr. 1 #{$1}” end

      Jan 20, 2013 at 15:34

    • 9

      Also worth noting, you can shorten your code by putting the when and return statement on the same line: when "foo" then "bar"

      – Alexander

      May 11, 2018 at 23:40


    • 14

      Important: 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.

      – janniks

      Sep 3, 2018 at 9:45

    • 4

      So many up votes yet not even a mention of the keyword then. Please also see the other answers.

      Jun 4, 2019 at 23:05

    480

    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.

    3

    • obj=’hello’;case obj; when ‘hello’ then puts “It’s hello” end

      Feb 10, 2017 at 9:59

    • Having 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.

      – lindes

      Apr 11, 2019 at 7:14


    • 1

      thanks for this! this is more elegant than my solution which was to use “case obj.class.to_s”

      Jul 23, 2020 at 3:22

    239

    It 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.)

    3

    • 44

      when (-1.0/0.0)..-1 then "Epic fail"

      Apr 17, 2011 at 23:49

    • 1

      This is the answer I used, because I am defining a variable based on the results of a case switch. Rather than saying type = #{score} each line, I can simply copy what you did. Much more elegant I also like the one-liners much better (if possible)

      – onebree

      May 12, 2015 at 14:06

    • 1

      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 😀

      Jul 22, 2020 at 17:47