Name

catch — handle failed 'try' blocks

ATTRIBUTES

Attribute Pos. Req. Default Description
label 1 1 default Name to assign to the [try] block. The name is later used by [catch] (or some custom code) to refer to the proper [try] block.
exact
joiner
error_set
error_scratch
interpolate     0 interpolate input?
reparse     1 interpolate output?
hide     0 Hide the tag return value?

DESCRIPTION

The page content contained within [catch label_name] ... [/catch] block will be executed if the correspondingly labeled [try] block fails. This kind of error handling is common in some general-purpose programming languages, such as Java, SML or even Perl.

Except providing just a general error handling mechanism, Interchange implementation can take different code paths, depending on the specific error that occurred. That is achieved by matching the error message using regexps.

BEHAVIOR

This tag does not appear to be affected by, or affect, the rest of Interchange.

EXAMPLES

Example: Raising and handling "division by zero" Perl error

In Perl, division by zero might result with the following error reported in the error log: 127.0.0.1 4cU3Pgsh:127.0.0.1 - [24/May/2001:14:45:07 -0400] tag /cgi-bin/tag72/tag Safe: Illegal division by zero at (eval 526) line 2 . Or it may be something like 127.0.0.1 G5vRfC9B:127.0.0.1 - [08/March/2005:18:25:17 +0100] tutorial /cgi-bin/ic/tutorial/catch Safe: 'eval "string"' trapped by operation mask at (tag 'perl') line 2.

The proper way to provide error handling is something like this:

[set divisor]0[/set]

[try label=div]
  [calc] eval(1 / [scratch divisor]) [/calc]
[/try]

[catch div]
  [/Illegal division by zero/]
    0
  [/Illegal division by zero/]
  
  [/trapped by operation mask/]
    Perl Safe error
  [/trapped by operation mask/]
  
  Other division error
[/catch]

NOTES

Note that the [catch] block executes at place of occurrence in place the page (if it is triggered), and not in place of the failed [try] block. This gives great flexibility but must be taken into account.

[catch] block must always follow [try], that is — be executed after the $Session->{try}{label} structure has been initialized.

You might wonder, what will the actual error messages be, and how will you know which regexps to use in matching them? The error messages "raised" will usually be those that are also placed in the error logs. See the section called “EXAMPLES” for clarification.

AVAILABILITY

catch is available in Interchange versions:

4.6.0-5.7.0 (git-head)

SOURCE

Interchange 5.7.0:

Source: code/SystemTag/catch.coretag
Lines: 80


# Copyright 2002-2007 Interchange Development Group and others
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.  See the LICENSE file for details.
# 
# $Id: catch.coretag,v 1.7 2007-03-30 23:40:49 pajamian Exp $

UserTag catch               Order        label
UserTag catch               addAttr
UserTag catch               hasEndTag
UserTag catch               Version      $Revision: 1.7 $
UserTag catch               Routine      <<EOR
sub {
my ($label, $opt, $body) = @_;
$label = 'default' unless $label;
my $patt;
my $error;
return pull_else($body) 
  unless $error = $Vend::Session->{try}{$label};

$body = pull_if($body);

if ( $opt->{exact} ) {
  #----------------------------------------------------------------
  # Convert multiple errors to 'or' list and compile it.
  # Note also the " at (eval ...)" kludge to strip the line numbers
  $patt = $error;
  $patt =~ s/(?: +at +\(eval .+\).+)?\n\s*/|/g;
  $patt =~ s/^\s*//;
  $patt =~ s/\|$//;
  $patt = qr($patt);
  #----------------------------------------------------------------
}

my @found;
while ($body =~ s{
          \[/
            (.+?)
          /\]
          (.*?)
          \[/
          (?:\1)?/?
          \]}{}sx ) {
  my $re;
  my $emsg = $2;
  eval {
    $re = qr{$1}
  };
  next if $@;
  if($emsg =~ $patt) {
    push @found, $emsg;
  }
  next unless $error =~ $re;
  push @found, $emsg;
  last;
}

if(@found) {
  $body = join $opt->{joiner} || "\n", @found;
}
else {
  $body =~ s/\$ERROR\$/$error/g;
}

$body =~ s/\s+$//;
$body =~ s/^\s+//;

if($opt->{error_set}) {
  set_error($body, $opt->{error_set});
}
if($opt->{error_scratch}) {
  $::Scratch->{$opt->{error_scratch}} = 1;
}

return '' if $opt->{hide};
return $body;
}
EOR

AUTHORS

Interchange Development Group

SEE ALSO

try(7ic)

DocBook! Interchange!