Pattern matching in Ruby 2.7

One of the most interesting new features of the latest release of Ruby is pattern matching. Here’s a quick tour of some of its features.

The concept of pattern matching comes from functional languages. The implementer of pattern matching in Ruby – Kazuki Tsujimoto, used this quote about pattern matching, as experienced in Haskell, to explain it.

“Pattern matching consists of specifying patterns to which some data should conform and then checking to see if it does and deconstructing the data according to those patterns.” –

Learn You a Haskell for Great Good! (Miran Lipovaca)

Ruby’s version of pattern matching looks very similar to Elixir’s. One difference however is that Ruby pattern matching can only be used inside case statements. It’s too complex for the Ruby core team to implement method / function overloading as functional languages use.

The following examples use Ruby version 2.7.0. Be warned: pattern matching is an experimental feature that may change in future versions. You’ll see a warning every time your interpreter runs some Ruby with pattern matching.

Let’s look at it in action

Pattern matching allows you to match the data structure of the argument you pass to a case statement and use that to assign variables.

We’ve pattern matched the first element of the array and assigned it to the variable a. The underscore _ is used as the placeholder.

If we don’t care about or don’t need the length of the array but want specific elements, we can use the splat operator (*).

You can also pattern match on splats to obtain the tail of an array.

A powerful tool for nested hashes such as JSON

We have a number of event-driven systems at Simply Business where we consume domain events in JSON from our event bus.

Given the JSON below, we want the quote_id from the payload if the payload type is “online” and there is a quote and the quote is a renewal.

With pattern matching, that’s expressive and simple.

What I like about this is that you don’t need to understand the underlying implementation of pattern matching to see what it is doing.

Further syntax

The pattern is run in sequence until a match is found. If no pattern is matched, the else clause is executed. If no pattern is matched and there is no else clause then the NoMatchingPatternError is raised.

Notice that you can use conditions along with patterns.

Alternative pattern

The | operator can be used to add multiple possible matches to the same in.

sb-tech-site-technology

Pin operator

Inspired by Elixir, the ^ operator can be used to pin the value of a variable of the same name that has been defined previously.

This returns true, as the second a with the pin is looking for the same value – the first a, was defined as:

This errors as it was expecting the second element to have the same value as the first value captured by the pinned a.

Use hash pattern matching on your own objects

To use hash pattern matching on your own objects, they need to implement #deconstruct_keys. This needs to return a hash containing the values you wish to use in your patterns.

In the example below, this allows us to pattern match on the attributes of the shape and also on a custom matching key area, as it’s returned in the #deconstruct_keys hash.

Summary

Pattern matching is an interesting feature and I definitely see how it could be used to make it simpler to parse and extract values from complex data structures such as nested hashes.

Remember – it’s still an experimental feature that will warn you each time you use it.

If you want to learn more, I suggest you read the official Ruby 2.7 documentation.

Ready to start your career at Simply Business?

Want to know more about what it’s like to work in tech at Simply Business? Read about our approach to tech, then check out our current vacancies.

Lewis Jones

This block is configured using JavaScript. A preview is not available in the editor.