https://www.akshaykhot.com/ruby-switch-statement/ Akshay's Blog Learn Ruby and Rails with me... * Favorites * Archive * About * Testimonials * Contact Subscribe Apr 25, 2023 Ruby's Switch Statement is More Flexible Than You Thought Ruby's switch statement is very versatile and flexible, especially due to the dynamic nature of Ruby. In this post, we'll see how you can use it in various ways. We'll also learn why it works the way it works. Hint: it uses the `===` operator (method) under the hood. Ruby's Switch Statement is More Flexible Than You Thought Here's the standard version of the switch statement in Ruby. season = 'winter' case season when 'summer' puts 'it is warm' when 'winter' puts 'it is cold' else puts 'it is raining' end # output # it is cold In typical Ruby style of developer happiness, it's called case and when, instead of switch and case. I find Ruby's version easier to read and understand. Note: There're no break statements at the end of each when clause. Unlike other languages, Ruby's case doesn't fall through. In the standard form, we're just comparing the expression provided to case with the when expression and executing the code provided. When no matches are found, the else statement is executed. In fact, what really happens is that Ruby compares the expression value provided in the when clause with the value in the case clause using the === operator. This lets you do fancy (but useful) stuff like this: puts 'enter a number' number = gets.to_i case number when 1..10 puts 'between 1 and 10' when 11..20 puts 'between 11 and 20' when 50 puts 'exactly 50' when 60, 70 puts 'either 60 or 70' else puts 'invalid number' end Note: The order matters. We're comparing the expression provided to the when clause with the case expression, not the other way around (when === case, not case === when). This is because Ruby actually calls the === method on the left operand, passing the second operand as an argument. The following example shows the difference. (1..10) === 5 # true 5 === (1..10) # false You can also shorten the code by returning on the same line as when clause, using the then clause. def can_drive(age) case age when 1..14 then 'no' when 15..100 then 'yes' end end puts can_drive(18) # yes Additionally, if you want to do comparisons on a variable, just leave out the case expression. This helps to simplify a long and complex if-else chain. def calculate(num) case when num > 10 puts 'greater than 10' when num == 5 puts 'exact 5' end end calculate 12 # greater than 10 Pretty useful. Now, let's learn how you can match data types of objects. Matching Types The === operator lets you match the types of objects. For example, Integer === 1 # true String === 'name' # true That means you can pass an object in the case clause and match types in the when clause, as follows: def perform(obj) case obj when String puts 'a string' when Integer puts 'an integer' when Vehicle puts 'a vehicle' else puts 'not a string, integer, or vehicle' end end perform 5 # an integer perform 'name' # a string class Vehicle end perform Vehicle.new # a vehicle Note: Do not use obj.class in the case clause, as Integer === Integer returns false. This might seem strange at first, but remember that Ruby is actually calling the === method on Integer. This method checks if the second argument is an instance of this module. Hence it returns false. It's also possible to evaluate custom, complicated expressions via a lambda or even classes. Let's see how. Custom Expressions If it walks like a duck and quacks like a duck, it is a duck. So far, we have learned that Ruby will match the when clause with the case clause using the === operator. In fact, it's calling the === method on the value returned by the when clause. Because of the dynamic nature of Ruby, you can pass any object that has a === method. For example, a lambda has a === method which simply passes the second operand as an argument to the lambda. even = ->(x) { x % 2 == 0 } even === 4 # true even === 5 # false This means that you can pass a lambda expression in the when clause. is_even = ->(x) { x % 2 == 0 } is_odd = ->(x) { x % 2 == 1 } num = 4 case num when is_even then 'even' when is_odd then 'odd' end In fact, any object that has a === method can be used in a when statement. num = 5 class Even def ===(obj) (obj % 2) == 0 end end class Odd def ===(obj) (obj % 2) == 1 end end case num when Even.new then puts 'even' when Odd.new then puts 'odd' end This example is not that useful as it's oversimplified. I can't think of a real-life scenario where I'd use custom classes, but it's pretty useful to know that Ruby let's you do this. Finally, let's see how you can match regular expressions inside case statement. Match Regular Expressions You can use the === operator to match a string against a regular expression. pattern = /hello.+/ pattern === 'hello world' # true pattern === 'world' # false As a result, you can use regular expressions in the when clause in a case statement. case word when /\d/ puts 'digit' when /[aeiou]/ puts 'a vowel' end Couldn't get simpler than this. Pattern Matching Pattern Matching is another powerful use case for the case statement in Ruby (Credits: Thanks to the commenter on Hackernews for pointing this out). I recommend reading the official documentation, but here's a gist of it: Pattern matching allows deep matching of structured values: checking the structure and binding the matched parts to local variables. It uses case .. in instead of case .. when. case in ... in ... in ... else ... end For example, config = {db: {user: 'admin', password: 'abc123'}} case config in db: {user:} # matches subhash and puts matched value in variable user puts "Connect with user '#{user}'" in connection: {username: } puts "Connect with user '#{username}'" else puts "Unrecognized structure of config" end # Prints: "Connect with user 'admin'" It's fascinating and deserves a blog post on its own. Stay tuned! That's a wrap. Did I miss anything? Please let me know in the comments below. --------------------------------------------------------------------- I hope you liked this article and you learned something new. As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I look forward to hearing from you. If you'd like to receive future articles directly in your email, please subscribe to my blog. If you're already a subscriber, thank you. Previous issue Browse all issues Subscribe to Akshay's Blog Sign up now to get access to the library of members-only issues. Jamie Larson Subscribe Akshay's Blog (c) 2023 * Sign up Powered by Ghost