Someone asked me whether I had used Ruby’s throw/catch mechanism in production. I thought I had, but couldn’t remember a specific instance. Today, I ran across some of my production code that uses throw/catch.
The product has a form that the end user fills out in order to pay a bill. For the user’s convenience, the form is prefilled from any of several sources. For example, if the user has made a payment before, we’ll use the address they filled in last time. If they have not made a payment but the system knows the address that their statement was mailed to, it will use that. There is also a test mode that can provide prefills, and defaults to use when no prefill value is found.
The class that knows the prefill rules has a constructor that takes the different objects that prefill information can come from:
There are about 20 fields, and so 20 methods to encapsulate the business rules for how prefill works with each field. At first, these methods looked like this:
Just one or two methods like that is no big deal. But with 20 of them, we wanted a way to make the business rules stand out better. We ended up with this instead:
The DSL that makes this work is implemented in just a few private methods. This is the first of them. All it does is to catch a symbol and then yield to the passed block:
The other methods throw a value, if it exists. If the value does not exist, they just return so that the next method can be tried:
The result of the top-level catch
is the result of the first throw
that gets executed. Using throw/catch gives the DSL a nice way to
stop looking when the prefill value is found.