Press "Enter" to skip to content

Avoiding a series of tests with Ruby Hashes of Hashes that might have nil before the leaf hash

I’m mostly using Ruby to write Opscode Chef Cookbooks. There are a lot of hashes of hashes that contain attributes or Data Bags. Things that look like:

app['rds_database'][environment]['rds_name']

If I wanted to test if this value is set I couldn’t safely just say:

if app['rds_database'][environment]['rds_name']

because in some cases

if app['rds_database']

or

if app['rds_database'][environment]

may be nil .

If ether of those were nil and I execute

if app['rds_database'][environment]['rds_name']

I would get an exception like:

NoMethodError: undefined method `[]' for nil:NilClass

I have been doing something like:

if app['rds_database'] && app['rds_database'][environment] && app['rds_database'][environment]['rds_name']

But that was starting to make me sick to my stomach. I like my Ruby fine and DRY

So I scoured the Internet (well googled a bit) and found a couple of good Stack Overflow posts like How to access an element deep in an array of arrays without getting ‘undefined method’ error and Looking for a Good Way to Avoid Hash Conditionals in Ruby.

But most of them were ways to Monkey Patch the Hash Object or use new operators that are loaded by Gems.

One of them was pretty simple and was pretty DRY. Though some commentors called it an indiscriminate use of  rescue and EEEEVVVVIIILLLLL.

But it seems to me to be a very discriminate use of rescue, as any case where the rescue happens, I want it to return nil:

if (app['rds_database'][environment]['rds_name'] rescue nil)

The parenthesis aren’t needed, but I think it makes it clearer whats going on. Especially if you say something like:

return unless (app['rds_database'][environment]['rds_name'] rescue nil)

So I’m going to give that a try for a while.