catch — handle failed 'try' blocks
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? |
The page content contained within [catch
block will
be executed if the correspondingly labeled label_name
] ... [/catch][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.
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]
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}{
structure has been initialized.
label
}
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.
Interchange 5.9.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