An amazing new feature is now available in Ruby, it’s called pattern matching & it lets you extract specific values from complex data structures like arrays, hashes, and objects using concise syntax.
In addition, it helps you check that these objects match a specific structure, so it works as a form of object validation.
Since Ruby 3.0, this feature is no longer experimental (there is an exception, as we will see later) so now you’re free to start using it in all your projects! 🙂
Matching Hash Structure
In this example, we’ll do something very interesting that, before pattern matching, took some extra work to accomplish.
And that is…
Checking if an array has certain keys & if the values of these keys comply with certain rules / patterns.
Example 1:
user = { name: "Mr. Potato", age: 20 } case user in { name: x, age: y } puts "Hello #{x}!" else puts "Invalid user" end
The most important thing to notice here is that we’re using a case
statement with a the in
keyword, this keyword tells Ruby 3.0+ to search for patterns.
It’s important to note that, since we’re dealing with a hash, our in
statement mirrors the expected structure.
So what will happen in this example is:
If user
has a name
& age
keys (it can have any other keys/values too), there will be a match and "Hello #{x}!"
will be printed; otherwise, you’ll see Invalid user
.
In addition to checking for the keys, you can also check the values for specific class types & even if dealing with integers, you can check for a range of values.
Like this:
user = { name: "Mr. Potato", age: 20 } case user in { name: String => x, age: 20.. } puts "Hello #{x}!" else puts "Invalid user" end
Pay attention to line 4, where the in
keyword is, you’ll notice this:
- “String => x”
- “age: 20..”
These will check that name
contains a String
& that age
value is 20
or greater.
Pretty cool! Right??
Matching Arrays & Using Extra Conditions
Please remember that pattern matching is not restricted to hashes, it’s possible to match arrays & other kinds of objects.
Example:
numbers = [2,3,4,5,6,7,8,9] case numbers in [*all] if all.sum > 10 puts "Valid amount." else puts "Invalid amount." end
What I’m doing here is…
Grabbing all the values inside the array, saving them inside a variable named all
, then I check whether the sum
of the values is greater than 10
, and if it’s, then we’ve got a match!
Another example:
numbers = [2,3,4,5,6,7,8,9] case numbers in [first, *rest] if first.even? puts "Valid amount." else puts "Invalid amount." end
Here I’m grabbing the first number from the array & checking if it’s even. As you can see, your imagination is the limit 🙂
Find Patterns
Initially, I mentioned that a portion of this new feature was considered experimental.
Good news.
- Ruby 3.2: “The find pattern is no longer experimental.” [Feature #18585]”
So what is this “find pattern” feature? It’s a way to match patterns without having to use a case statement.
Here is how it works:
[1, "b", 2] in [Integer, Integer, Integer] # false [1, "b", 2] in [Integer, String, Integer] # true [1, "b", 2] in [Integer, x, Integer] # x = "b"
More examples:
[1,"a",2,3,"b",4,"c"] in [*, String => str, *] # true # str = "a" ["banana", "cookies", "milk"] in [*, /^c/ => str, *] # true # str = "cookies"
This is helpful when you just want to check a single object without writing a single line of code & get a boolean value (match or no match) + the values you want from the structure (str
& x
in the last two examples).
Notice that you can even use regular expressions here.
Video Tutorial
Conclusion
In conclusion, diving into the world of pattern matching in Ruby 3.0 and beyond unveils a powerful tool for simplifying your code and enhancing its readability.
With the ability to extract specific values from complex data structures and validate object structures effortlessly, pattern matching becomes a game-changer in your programming toolkit.
As you embrace pattern matching, remember that your creativity is the limit. Crafting elegant and efficient code is not just about functionality; it’s about making your intentions explicit, and pattern matching empowers you to achieve just that.