DRYing Out Deep Checks
We found ourselves very often writing code with conditions that looked like:
if object && object.child && object.child.valid? do_something(object.child) end
In this case all we really want to do is verify that object.child.valid? returns true, but writing
if object.child.valid?
left us vulnerable to the dreaded
# NoMethodError: undefined method `child' for nil:NilClass
The solution? The try method, which accepts a block and returns the result of that block, or nil if NoMethodError is raised. Thus our conditional becomes
if try { object.child.valid? }
which represents what we’re trying to validate without the cruft of explicitly validating all of the implicit prerequisites.
What does the implementation look like? It turns out that it’s dirt simple:
def try yield rescue NoMethodError nil end
A second pass allows you to define other exceptions that you think are likely but don’t care about:
def try(exceptions = [NoMethodError])
exceptions = [exceptions].flatten
yield
rescue Exception => ex
raise ex if !exceptions.any? {|ec| ex.is_a?(ec)}
nil
end
Thats it. Simple, clean, and dries up a very common idiom in our codebase.