Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Current WIP of pattern matching documentation. Still needs more work.

Pattern Matching

Pattern match statements are an extension of the case expression. They introduce a new keyword to case statements: in.

The in expression

in is used in place of when to use pattern matching behaviors. These two syntaxes cannot be mixed.

An in expression is different from when in that it allows one to match against data structures:

case [1, 2]
in Integer, Integer
  true
else
  false
end

In this example both values of the array are compared using === like a when branch, but differnt in that it compares the values by their position rather than using the comma (,) to separate multiple possible conditions.

This is the same as saying:

array = [1, 2]
Integer === array[0] && Integer === array[1]

Multiple "or" conditions

Instead of a comma, a pipe (|) is used to seperate multiple conditions. This would make the following two pieces of code equivalent:

case 0
in 0 | 1
  true
end

case 0
when 0, 1
  false
end

Pattern Matching against Array-like types

Pattern matching can work on Array-like types. In the case of these types the pattern will match against all items of an Array as with the above example:

case [1, 2]
in Integer, Integer
  true
else
  false
end

Array-like matching can either explicitly use brackets ([]) or avoid them as with the example above:

case [1, 2]
in [Integer, Integer]
  true
else
  false
end

With "or" conditions it should be noted that they apply to one part of the expression:

case [1, 2]
in Integer | String, Integer
  true
else
  false
end

This is equivalent to the following:

case [1, 2]
in (Integer | String), Integer
  true
else
  false
end

The deconstruct method

As with the example above, pattern matching can work against Arrays and other array-like objects that implement a deconstruct method like so:

class Array
  def deconstruct
    self
  end
end

The deconstruct method should return an Array that can be pattern matched against. Given a hypothetical class, Result, which contains a status and a value, we can define our own deconstruct:

class Result
  def initialize(status, value)
    @status = status
    @value = value
  end

  def deconstruct
    [@status, @value]
  end
end

This would allow us to pattern match against a Result type:

case Result.new(:ok, %({ "a" : 1, "b" : 2 }))
in :ok, response_body
  JSON.parse(response_body)
in :fail, error_message
  raise error_message
end
# => {"a"=>1, "b"=>2}

case Result.new(:fail, %(Nothing found!))
in :ok, response_body
  JSON.parse(response_body)
in :fail, error_message
  raise error_message
end
# RuntimeError (Nothing found!)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.