Back to home

Pattern Matching In Ruby main image

Pattern Matching In Ruby

Pattern matching in Ruby enables the capability to check data conformity with a particular pattern and to handle appropriately based on the match (or a default action/error).

Introduced in Ruby 2.7, most of the pattern matching features are no longer considered experimental as of Ruby 3.1 (although there are some differences with pattern matching in Ruby 3 that will be explored).

Hello, pattern matching!

The pattern matching block opens with the keyword case and the expression to be checked is passed in as the first argument. This is the same as the case statements you will be familiar with.

We can check against cases with the in/then keyword combination e.g. in 'VALUE' then do_something. The difference between the case statement we are familiar with and pattern matching is that in is used instead of when. A default can be set with the else keyword, where we can execute the default behavior, otherwise NoMatchingPatternError will be raised.

Below is a simple example:

team = 'A' case team in 'A' then puts 'Team A' in 'B' then puts 'Team B' else puts 'Team C' end # => "Team A"

If we omit the else and match against an unhandled case, we note that the NoMatchingPatternError is raised.

begin team = 'D' case team in 'A' then puts 'Team A' in 'B' then puts 'Team B' end puts 'Still executes' rescue NoMatchingPatternError puts 'No matching pattern' end # => "No matching pattern"

Matching patterns

There are a number of ways that we can match against a pattern. Below are some examples:

  • Object pattern match (comparing two objects).
  • Variable pattern which binds a variable(s) to the values that match the pattern.
  • As pattern which manages more complex variable assignments.
  • Alternative pattern match which allows you to match against multiple patterns in one case i.e. in 0 | 1 | 2.
  • Guard conditions which can be used to execute a pattern match if a condition is met i.e. in 'A' if condition_is_true.
  • Array pattern match which allows us to match against an array of values based on value or object match (including matches with a splat * or "any value" _).
  • Hash pattern matching (which only works for symbol keys and not string keys) which can also work with matching on a double splat **. Be mindful that the hash pattern will match cases with only a subset of keys matching.
  • Find pattern which will help match against part of an array.

Some useful examples of some of the above.

The Object pattern:

# Object pattern class Input end value = Input.new case value in Input then puts 'Object is Input' end # => Object is Input

The Alternative pattern:

value = 0 case value in 0 | 1 | 2 then puts 'Value is 0, 1 or 2' end # => Value is 0, 1 or 2

Guard conditions:

is_allowed = false value = 0 case value in 0 if is_allowed then puts 'Value is 0' end # => NoMatchingPattern error raised

Hash pattern:

a = {a: 1, b: 2, c: 3} b = {a: 2, b: 3, c: 4} c = a case c in a then puts 'Hash matches "a"' in b then puts 'Hash matches "b"' end # => Hash matches "a" case c in {a:, **rest} then puts 'Hash matches splat' in a then puts 'Hash matches "a"' in b then puts 'Hash matches "b"' end # => Hash matches splat

Summary

Today's post is a short overview on pattern matching, how it differs from case statements and how it can be used to solve a variety of matching problems.

Resources and further reading

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on workingoutloud.dev, Den Dribbles and LandPad .

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.