Handy Ruby shorthand for testing class ancestors
Today I was working on a method that had to take a string, and resolve it to a class. This method needed to perform some validation on the model class, to make sure it was a type we expected.
My first iteration of this didn’t work - I expected that I could use Object#kind_of?
, however this only works for testing whether an instance is a kind of class or module, rather than the class itself. This check looked like:
model.kind_of?(ParentThing)
My next iteration did a direct superclass comparison:
model.superclass == ParentThing
This worked, but was more brittle than I wanted, since it would only work when ParentThing
was the direct ancestor of the class.
I checked in on my company Slack, where Eoin reminded me of the ancestors
method, which returned an array of the ancestors of the class or module the method was called on - essentially, the superclass chain. From this, I composed the test:
model.ancestors.include?(ParentThing)
This worked, was flexible enough to allow ParentThing
to not be the direct ancestor, so I went to commit it, when Rubocop conveniently told me of a recommended replacement:
Performance/AncestorsInclude: Use <= instead of ancestors.include?
This led me to the Rubocop documentation, then to the Fast Ruby reference, indicating that not only does that shorthand exist, it is also faster. Neat!
The <=
method, along with a few other handy-looking examples, are documented in the Ruby documentation.
mod <= other → true, false, or nil
Returns true if mod is a subclass of other or is the same as other. Returns nil if there’s no relationship between the two. (Think of the relationship in terms of the class definition: “class A < B” implies “A < B”.)
My final check implementation became a lot simpler:
model <= ParentThing