MrProper: Cleaner blocks in Ruby

Pablo Villalba October 28 2009

I love blocks in Ruby. I use them all the time: each, collect, map, etc. And they’re a great way of making code more readable and fun.

But I don’t like it that when I call them for a nil object, they raise an exception. So I have to add an if around them, and my codes becomes ugly. I get this often when trying to evaluate params for a form that may not have a given field, like checkboxes.

A fix for this would be using an or, so if the object is not defined the blocks will use the empty array and not get run. Like this:

But then I remembered why I love Ruby: You can rewrite everything! So I came up with #is_defined, which you can call to clean up your code in this way:

Since this is pretty cool, I turned this into a MrProper, a plugin that you can download at Github. Just drop it inside config/initializers/mrproper.rb

Note: You could also overload NilClass with methods called each, map, etc. The problem with this is that other libraries may use exception control to manage the flow in part of their code, so these solution could break things by failing silently. Therefore, it’s better to explicitly call a method to avoid errors and be aware that they won’t rise.

Update:
Thanks to @raganwald, @peteforde and @heycarsten for the interesting links. There are better alternatives to this, like andand. I enjoyed the posst about Array-ifying values and Self confident code, too.

Read also

  • Mike Berrow
    But why not just do ...

    class NilClass
    def each
    []
    end
    end
  • Mike, that would be much cleaner, but it could break other Ruby code (frameworks, plugins) relying on exceptions that need to be raised when an unexpected nil gets passed.

    if_defined assures that you are expecting the possibility of receiving a nil, so it's safer and explains what's behind the scenes.
  • Thanks for the linkage. Note that since Ruby already provides a 'defined?' operator with slightly different semantics, the use of the term "defined" to mean defined-and-not-nil might be a bit confusing. Something like 'if_not_nil' or 'if_valued' might be more precise.
  • I agree there, if_valued would be better naming. However, Array(variable) is a good way of avoiding nil checks, so I guess we should rather use that!
blog comments powered by Disqus

Latest Posts