Published on June 02, 2008

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.

About the author

kevin Kevin is currently heading up Causes on MySpace development, after joining the team straight from the Obama presidential campaign. Also in his background are several years of experience with high performance computing clusters, and a degree in Physics from UC San Diego. Outside of work you can catch him dancing, reading, and hanging out with friends and his fiancée.