Understanding and using Ruby's powerful #grep method
Ruby is known for its many handy methods. I’d like to take a look at one that is a little bit less known, but quite powerful nonetheless: the #grep
method.
About the method
#grep is one of many instance methods defined on the Enumerable
module. This essentially means that you can use it on all Ruby classes that include this module, e.g. Array
or Hash
. The Enumerable
module is the place where many other popular “collection” methods are defined - #map
, #select
, and the like. Whatever Ruby object you can use the #map
on, you should be able to use the #grep
on as well.
“Getting a #grep”
Let’s see an example usage of the #grep
method:
Seems pretty handy, right? And that’s just one way of using it. But before showing more examples, let’s deconstruct this to understand exactly how it works.
What happens under the hood here could be mimicked with a code like this:
Or, more generally:
Notice a few things here:
- The return value will always be an array. The length of this array will be between 0 (empty), and the size of the original collection (which is exactly how
#select
behaves too). - We are using the triple equals (
#===
) method (“operator”). The#===
is probably worthy of a separate article. But for now, we can just recall that it’s implemented in classes as sort of a “lighter” (meaning: less strict) equality method (also called “case” equality due to its usage in case statements). We can illustrate the difference between regular and “case” equality with an example:
-
We don’t have to limit ourselves to regexes. Any object could be passed as a “pattern” to compare against.
-
The triple equals method is invoked on the given pattern, not the elements of the collection. (The
pattern === element
bit is of course just a syntactical sugar forpattern.=== element
- stripping out the ‘sugar’ exposes the method invocation). Invoking the method on the pattern makes sense, as it’s this object that should “know” when something is passing its “light” equality requirements. Notice the difference here:
When and how to use it
Enough theory. Let’s get down to it and look at some concrete situations where the #grep
method might come in very handy to you.
#grep with a Regexp
You can easily match strings with a Regexp pattern.
Just use:
instead of:
Apart from handling collections of strings in the code, I find the #grep
method to be very handy for… recalling things (e.g. by performing a quick lookup in the terminal). These examples should illustrate the idea:
(The Regexp#===
works with symbols just as it does with strings)
#grep with a Range
Range#===
checks the inclusion of Numeric values in the given range. This means that we can pass a range to grep to quickly filter values falling within the range.
#grep with a class name Constant
#grep with any object
Since the #===
method in Ruby is implemented on an Object
, you can pass any descendant of this class to the #grep
method.
In the Object
class, the #===
method behaves the same way as #==
. It’s up to descending class to implement (or not) a different meaning between the two.
The opposite: #grep_v
Just like #select
has an opposite #reject
method, there is also a #grep_v
method that behaves like you would imagine - it rejects the matched objects, similar to how this code would:
Example usage:
Passing a block
Both #grep
, and #grep_v
are utilizing a block if one is supplied. The block is used to transform the matched values before returning them in an array (just like chaining a #map
after #select
would). E.g.
The same operation without a #grep would probably look something like that:
Summary
As you can see, the #grep
method is pretty powerful! If you haven’t already, add it to your developer’s arsenal and see where it can help you in your work.
Are you using the #grep
method in your project? Please share in the comments below!
And if your Ruby project suffers from slow build times, consider using Knapsack Pro to improve the productivity and delivery times of your team!