Sunday, February 24, 2008

Ruby: Inline Rescue

On my current project we use action specific Presenters 20% of the time. We opened ActionController and ActionView and redefined the render methods to automatically create presenters based on convention. For example the CommentsController has a show action, so render will try to create Comments::ShowPresenter when the show action is rendered. This works well for us, but like I said we only need a specific presenter 20% of the time. The other 80% of the time we still want a presenter that contains basic methods necessary on each page, but it is not specific to an action.

We solved this issue by attempting to create the specific presenter and rescuing with the base presenter.

klass = "#{action}_presenter".camelize.constantize rescue Presenter
@presenter = klass.new

Inline rescues promote concise code, but they shouldn't be overused to create overly complex lines of code. For example, I probably could have combined the two lines above into one line, but that would be a bit much to digest in my opinion.

In the example we attempt to create the class using constantize, but if an error (like uninitialized constant) occurs we rescue with the base Presenter class. Either way, the result is assigned to the klass local variable.

7 comments:

  1. I'm a fan of inline rescue's as well, but I think its important to use them judiciously. In your example you're executing a very specific set of methods and there's not many types of errors that could be thrown...which creates a great place to use an inline rescue. The flip side that I've seen is that people will do things like:

    obj = some.complex.calls.and.logic rescue nil

    where the chain of events could do anything from throw an ActiveRecord error to a LoadError, or more. The more responsible thing IMHO in places like that is to be specific about what error you're catching, which will force you to split things out over multiple lines in a block format.

    ReplyDelete
  2. Here's a line that I include in every project..

    xml.append! begin render( :partial => "layouts/#{controller.controller_name}" ) rescue yield end

    I use builder for templates and append! is a method I added that works just like << except adds indentation. So render the controller template, or just show the action if there isn't one.

    I don't use inline rescue much, but it's nice to have sometimes. :)

    ReplyDelete
  3. Hi Jay,

    Did you consider using const_defined? instead of rescue? "Exceptions are for Exceptional circumstances" and all that.

    ReplyDelete
  4. his reminds me of on error resume next in vb :D

    ReplyDelete
  5. Hey Toby,
    Yeah, that's probably a better solution. Rescuing was the first thing that came to mind and it just worked so I never gave it another thought.

    Cheers, Jay

    ReplyDelete
  6. you wanted to express it as a single line - Easy and great. Anyway, I always have a twitch on my left eye when I see this "klass" idiom. Here:

    @presenter = ("#{action}_presenter".camelize.constantize rescue Presenter).new

    Parenthesis are a great tool, and often underused in Ruby :)

    ReplyDelete
  7. Wow I like the parentheses mentioned in the comments. Suppose I should use more of those.
    I'm a fan of inline rescue, too, though...they're a little scary. andand might help out in the case of it returning nil.
    Take care.
    -R

    ReplyDelete

Note: Only a member of this blog may post a comment.