Tuesday, April 12, 2016

Catching Exceptions in Bedrock

When things go wrong, it's a good idea to actually try to handle the mess.  Most higher level programming languages have exception handling built in.  While Bedrock is not a programming language, it is useful for a templating language to have the ability to catch exceptions.  Today's blog describes how Bedrock's <try/catch> blocks can be use with your Application Plugins.

In a previous blog post we discussed how to create custom error pages in Bedrock.  So, one way to handle errors that are not trapped is to create your own custom error page.  However, if you want to trap errors you use the <try/catch> mechanism built into Bedrock.  In it's most basic form a <try/catch> block looks like this:

<try>
...some statements
<catch>
...some other statements
</try>

This form will catch all errors in the try section by interpreting the catch section and including that in your page instead.

The <catch> tag can also take an argument which represents a string that will be compared (as a regular expression) with the exception that is being handled.  If that matches, then the exception is handled by that block.  If not, the next catch statement is tried and so on.  You can learn more about this tag here.

<try>
...some statements
<catch "this">
...catch "this" error
<catch "that">
...catch "that" error
<catch>
...default error block
</try>

The exception itself is available to you as the Bedrock scalar object $@. This allows you to inspect the object directly if you'd like to incorporate it into any handling of the exception you might want to do.  For example, you might want to showing the error to the user in some HTML.

<div class="error"><var $@</div>

Bedrock also exposes an error object $ERROR.  You can get at the same message using $ERROR.mesg()

If you are catching exceptions that may be generated by method calls to one of your application plugin modules, you may want to have your plugins throw exceptions that are themselves Bedrock objects with methods (exception objects or exception classes).  Let's suppose we have an application plugin named $foo that we will cal that might throw an exception.

 1      package Foo::Exception;
 2      
 3      sub new {
 4        my $class = shift || ref($class);
 5        bless { @_ }, $class;
 6      }
 7      
 8      sub as_string {
 9        return sprintf("%s: %s", @{$_[0]}{qw/error error_description/});
10      }
11      
12      package BLM::Startup::Foo;
13      
14      use parent qw(Bedrock::Application::Plugin);
15      
16      sub bar {
17        my $self = shift;
18        my $bar = shift;
19      
20        unless (ref $bar) {
21           die new Foo::Exception( error => "invalid argument", 
22                                  error_description => "must be a reference" );
23         }
24                                 
25        return 1;
26      }
27      
28      sub buzz {
29        my $self = shift;
30        my $buzz = shift;
31        unless (ref $buzz) {
32           die new Foo::Exception( error => "invalid argument", 
33                                  error_description => "must be a reference",
34                                  redirect_on_error => '/buzz-error.roc' );
35         }
36      }
37      
38      1;

So the above snippet of code defines our application plugin and an exception class.  Here's how we might catch errors that are actually exception classes.

<try>
  <null $foo.bar($some_obj)>
<catch "Foo::Exception">
  <div><var $@.as_string()></div>
<catch>
  <div>Not sure what this exception is all about!</div>
</try>

Lot's of interesting things you can do by catching exceptions, including redirect the user to another page if necessary by setting a Location header.

<try>
  <null $foo.bar($some_obj)>
<catch "Foo::Exception">
  <if $@.redirect_on_error>
    <null $header.location($@.redirect_on_error)>
  <else>
    <raise $@.as_string()>
  </if>
</try>


Have fun!

No comments:

Post a Comment

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