In which I explain the gem Izzy
In the time I’ve been off of writing on here, I’ve had a bit of a stint of gem creation. We’re going to cover a number of them in the coming week.
Some may say that monkeypatching is inherently evil, but I would tend to disagree. An RPG serves a very tactical purpose when used correctly, but often times it can have rather unfortunate results in the hands of the untrained. Such is monkeypatching, something that should be viewed in a pragmatic sense rather than one of dogmatic vitriol. With that, let’s take a look:
Izzy
Izzy got popular right after a Ruby Weekly post mentioned it as a method of mitigating long conditionals. I made it for the express purpose of simplifying multiple conditionals on the same object into something more succinct.
Going off of what’s in the README as far as order, we’ll take a look into some of the inspiration and workings of each method.
Matchers
Matchers are methods that are checked against any of the attributes of an Object that includes Izzy. Let’s say we have an instance of me made in a Person class implementing Izzy:
1
|
|
Now it gets really tiresome to do something like this while trying to validate against this object:
1
|
|
It seems repetitive and downright unnecessary to specify the object multiple times. Rails has a tendency to use hashes to create, query, and update object, so why not add some of that type of magic to validations?
1
|
|
To me that’s far more succinct. So how do we make something like this in Ruby? Let’s take a look at the source:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
The first thing you may notice is that the body of the block is abstracted into a private matcher_check. This is to abstract the logic for reuse on the two other matcher types.
The fun thing about this is because it’s in a method, we can send another argument to it. The value is then pulled into the block, or closure if you prefer. In this case, we’re sending what to check the values against dynamically. Notice that we only use all on the matches_all?
method.
Let’s step through this piece by piece with only using the check brandon.matches_all? name: /^br/
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
So why does ===
work there you might wonder. It’s overridden very frequently for classes, notably for Regex (matches), Range (includes), and Proc (call). Most of the time this is bad practice not to use the longhand versions, but in this case it affords us a great deal of flexibility not to worry about how it’s evaluated as long as it does a proper match.
This is actually one of the most powerful features in the case statement, which uses ===
for its when
clauses. Notice that Proc.call is the same as Proc.===, meaning you can throw lambda and friends into the mix for even more powerful checks.
Boolean Matchers
Boolean matchers were the original method, again using the abstracted block:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
This one is far simpler in that all it does is call a list of methods on an object, checking their truthfulness. If we had some methods defined on person to check legal status, or various other simple checks, this would come in handy:
1
|
|
Enumerable Module
Because sometimes it’s nice to have a bit of that Rails feel in regular Ruby. These methods use the matches_all?
method in conjunction with select
, reject
, and find
to provide some Rails like shorthand:
1 2 3 4 5 6 7 8 9 10 11 |
|
We’re not always in Rails, and one of my favorite features are the ActiveRecord where
and find
methods. Composing the two functions allows us to do that quite nicely.
Final Notes
Combining multiple small functions into something larger is one of the cornerstones of functional programming known as composition, and something well worth looking into. Not every gem has to be a monolithic beast that can tame the worlds problems. Sometimes you only need to do the simple things well and build up from there.
Next up we’ll look into Streamable, Pipeable, @banister’s Funkify Library, and hacking Piping functionality onto Ruby.