DEV Community

francesco agati
francesco agati

Posted on

Ruby Pattern Matching: An Advanced Guide

Pattern matching is a powerful technique in programming that allows you to match data structures and extract their components in a concise and elegant way. Ruby, being a flexible and dynamic language, has recently introduced a new pattern matching syntax in version 3.0 which has made it even more versatile. In this article, we'll dive deep into the world of Ruby pattern matching and explore some advanced use cases.

Basic Syntax
Before we explore advanced topics, let's first review the basic syntax for pattern matching in Ruby. The following code snippet demonstrates how to use the pattern matching syntax in a simple case statement:


case [1, 2, 3]
in [1, x, 3]
  puts "The second element is #{x}"
end
# Output: The second element is 2

Enter fullscreen mode Exit fullscreen mode

In this example, we are matching an array [1, 2, 3] against the pattern [1, x, 3]. The variable x is assigned the value 2, and we print it out using string interpolation.

We can also use pattern matching in method arguments:


def process_data(data, in_progress: false)
  case data
  in Array => items
    items.each { |item| process_data(item, in_progress: true) }
  in Hash => options
    process_data(options[:data], in_progress: in_progress)
  else
    # Process scalar data
  end
end

Enter fullscreen mode Exit fullscreen mode

In this example, we are using pattern matching to distinguish between an array and a hash. If the data is an array, we recursively call the process_data method for each item in the array. If the data is a hash, we extract the :data value and call the process_data method again with the in_progress flag. If the data is neither an array nor a hash, we assume that it is scalar data and process it accordingly.

Advanced Topics

Guards
In addition to pattern matching, Ruby also supports guards, which allow you to add conditions to your patterns. Guards are specified using the if keyword followed by a Boolean expression. Here's an example:


case [1, 2, 3]
in [1, x, 3] if x > 1
  puts "The second element is greater than 1"
else
  puts "No match"
end
# Output: The second element is greater than 1

Enter fullscreen mode Exit fullscreen mode

In this example, we have added a guard to the pattern [1, x, 3] that checks if the value of x is greater than 1. If the guard condition is true, the corresponding code block is executed. Otherwise, the else block is executed.

Nested Patterns
Another powerful feature of Ruby pattern matching is the ability to use nested patterns. This allows you to match complex data structures and extract their components in a hierarchical way. Here's an example:


case { name: "John", address: { city: "New York", state: "NY" } }
in { name: "John", address: { city: "New York", state: state } }
  puts "The state is #{state}"
end
# Output: The state is NY

Enter fullscreen mode Exit fullscreen mode

In this example, we are matching a hash with nested values. The outer pattern matches the name and address keys, and the inner pattern matches the city and state keys within the address hash. We extract the value of state and print it out using string interpolation.

Array Decomposition
Ruby also supports array decomposition, which allows you to extract multiple values from an array using a single pattern. Here's an example:


case [1, 2, 3]
in [a, b, *c] puts "a: #{a}, b: #{b}, c: #{c}" end

Output: a: 1, b: 2, c: [3]

Enter fullscreen mode Exit fullscreen mode

In this example, we are using the pattern [a, b, *c] to match an array with at least two elements. The first element is assigned to the variable a, the second element is assigned to the variable b, and the remaining elements are assigned to the variable c as an array.

Hash Decomposition
Similarly, Ruby also supports hash decomposition, which allows you to extract multiple key-value pairs from a hash using a single pattern. Here's an example:


case { name: "John", age: 30, city: "New York" }
in { name: n, age: a }
  puts "Name: #{n}, Age: #{a}"
end
# Output: Name: John, Age: 30

Enter fullscreen mode Exit fullscreen mode

In this example, we are using the pattern { name: n, age: a } to match a hash with at least two key-value pairs. The values of the name and age keys are assigned to the variables n and a, respectively.

Conclusion

Pattern matching is a powerful technique that can simplify your code and make it more expressive. Ruby's pattern matching syntax, introduced in version 3.0, provides a flexible and concise way to match data structures and extract their components. In this article, we have explored some advanced topics in Ruby pattern matching, including guards, nested patterns, array decomposition, and hash decomposition. I hope this article has given you a good understanding of pattern matching in Ruby and inspired you to use it in your own code.

Top comments (0)