[Templates-cvs] cvs commit: TT3/lib/Template Base.pm
cvs@template-toolkit.org
cvs@template-toolkit.org
Wed, 24 Mar 2004 14:16:25 +0000
cvs 04/03/24 14:16:25
Modified: lib/Template Base.pm
Log:
* revamp of the whole error reporting, declining, exception throwing mechanism
with changes to the error() and decline() methods, and the addition of a proper
throw() method
Revision Changes Path
1.2 +144 -28 TT3/lib/Template/Base.pm
Index: Base.pm
===================================================================
RCS file: /template-toolkit/TT3/lib/Template/Base.pm,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Base.pm 2004/03/23 10:32:13 1.1
+++ Base.pm 2004/03/24 14:16:25 1.2
@@ -18,7 +18,7 @@
# modify it under the same terms as Perl itself.
#
# REVISION
-# $Id: Base.pm,v 1.1 2004/03/23 10:32:13 abw Exp $
+# $Id: Base.pm,v 1.2 2004/03/24 14:16:25 abw Exp $
#
#========================================================================
@@ -26,16 +26,20 @@
use strict;
use warnings;
-use vars qw( $VERSION $DEBUG $ERROR $WARNINGS $PAD $TEXTLEN $UTILS );
+use vars qw( $VERSION $DEBUG $ERROR $WARNINGS
+ $PAD $TEXTLEN $UTILS $EXCEPTION );
+# these both subclass from Template::Base so require rather than use
require Template::Utils;
+require Template::Exception;
-$VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
-$DEBUG = 0 unless defined $DEBUG;
-$ERROR = '';
-$PAD = 2;
-$TEXTLEN = 32;
-$UTILS = 'Template::Utils';
+$VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
+$DEBUG = 0 unless defined $DEBUG;
+$ERROR = '';
+$PAD = 2;
+$TEXTLEN = 32;
+$UTILS = 'Template::Utils';
+$EXCEPTION = 'Template::Exception';
#------------------------------------------------------------------------
@@ -62,6 +66,10 @@
ERROR => '',
}, $class;
+ # merge in any 'throw' parameter
+ $self->{ THROW } = $config->{ throw }
+ if exists $config->{ throw };
+
return $self->init($config)
|| $class->error($self->error());
}
@@ -180,6 +188,7 @@
# in the object error item and/or the $ERROR package variable. A
# single reference argument (e.g. an exception object) can be passed
# as an argument. This is used as is without being first stringified.
+# If the THROW item is set then the error is thrown via throw().
#------------------------------------------------------------------------
sub error {
@@ -190,12 +199,28 @@
if (@_) {
# don't stringify objects passed as argument
- my $error = ref $_[0]
- ? shift
- : join('', map { defined($_) ? $_ : '' } @_);
- $self->{ ERROR } = $error if ref $self;
+ my $error = ref $_[0] ? shift : join('', map { defined($_) ? $_ : '' } @_);
+ my $throw;
+
+ # set package variable
${"$class\::ERROR"} = $error;
- return undef;
+
+ if (ref $self) {
+ # set object error
+ $self->{ ERROR } = $error;
+
+ # look for errors action in object, then package
+ $throw = exists $self->{ THROW }
+ ? $self->{ THROW }
+ : ${"$class\::THROW"};
+ }
+ else {
+ # look in package for errors
+ $throw = ${"$class\::THROW"};
+ }
+
+ # throw error or return undef/0 value of $throw
+ return $throw ? $self->throw($throw, $error) : $throw;
}
elsif (ref $self) {
return $self->{ ERROR };
@@ -273,21 +298,32 @@
#------------------------------------------------------------------------
-# decline($reason)
+# decline($reason, $more_reasons, ...)
#
-# General purpose method used to decline a request of some kind. Calls
-# error() to report the reason passed as one or more arguments, and then
-# returns 0.
+# General purpose method used to decline a request of some kind. Joins
+# all the arguments into a single string and stores it in the internal
+# DECLINED item to be accessed via the declined() method. Returns undef.
#------------------------------------------------------------------------
sub decline {
my $self = shift;
- $self->error(@_);
- return 0;
+ $self->{ DECLINED } = join('', @_) if ref $self;
+ return undef;
}
#------------------------------------------------------------------------
+# declined()
+#
+# Returns the value of DECLINED, set by decline().
+#------------------------------------------------------------------------
+
+sub declined {
+ return $_[0]->{ DECLINED };
+}
+
+
+#------------------------------------------------------------------------
# throw()
#
# This method is only here temporarily. It might get moved, it might
@@ -296,7 +332,14 @@
sub throw {
my $self = shift;
- die @_;
+
+ if (@_ == 1 && UNIVERSAL::isa($_[0], $EXCEPTION)) {
+ # only argument is an exception so re-throw it
+ die $_[0];
+ }
+ else {
+ die $EXCEPTION->new(@_);
+ }
}
@@ -313,7 +356,7 @@
my $name = shift;
my $config = @_ && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ };
- $self->debug("module($name)\n") if $DEBUG;
+ $self->debug("module($name)\n") if $self->{ DEBUG };
# TODO: may want to implement caching, e.g. have an object
# cache => { scanner => 1, parser => 1, handler => 0 } item
@@ -370,6 +413,20 @@
#------------------------------------------------------------------------
+# version()
+#
+# Return the value of the $VERSION package variable for the object.
+#------------------------------------------------------------------------
+
+sub version {
+ my $self = shift;
+ my $class = ref $self || $self;
+ no strict 'refs';
+ return ${"${class}::VERSION"};
+}
+
+
+#------------------------------------------------------------------------
# debug($msg1, $msg2, ...)
#
# Debugging method which currently outputs all arguments to STDERR.
@@ -735,6 +792,62 @@
my $object = My::Template::Module->new()
|| die $My::Template::Module::ERROR;
+If an object defines a C<throw> item or if the C<$THROW> package
+variable is defined for the subclass, then the C<error()> method will
+call the C<throw()> method to throw the error as an exception instead
+of simply returning undef. The value of the C<throw> item or
+C<$THROW> variable is used to define the exception type, with the error
+message providing the additional information.
+
+Here's an example showing how the C<throw> option can be set as
+a constructor option.
+
+ my frob = My::Template::Frobulator->new( throw => 'frob' );
+
+Now when we call a method that raises an error via the C<error()> method,
+it will be thrown as a Template::Exception object using Perl's die()
+function.
+
+ $frob->something_that_generates_an_error();
+
+It doesn't hurt to add the code to check if the method returns undef.
+That way, your code will do the right thing regardless of how the
+object error handling is defined.
+
+ $frob->something_that_generates_an_error()
+ || die $object->error();
+
+Here's an example showing the C<$THROW> package variable being set
+for a module.
+
+ package My::Template::Frobulator;
+ use base qw( Template::Base );
+ use vars qw( $THROW );
+ $THROW = 'frob';
+
+ sub something_that_generates_an_error {
+ my $self = shift;
+ return $self->error('The sky has fallen in');
+ }
+
+Now when we create a My::Template::Frobulator object, it's as if the
+C<throw> option is set by default.
+
+ # errors thrown as exceptions by default
+ my $frob = My::Template::Frobulator->new();
+
+If we want to disable the default behaviour defined by C<$THROW> then
+we simply provide an explicit value for C<throw> as a constructor
+option. This can be set to C<undef> to provide the default
+(i.e. non-throwing) behaviour, or can define a different exception
+type.
+
+ # errors return undef
+ my $frob = My::Template::Frobulator->new( throw => undef );
+
+ # error thrown as 'frobless'
+ my $frob = My::Template::Frobulator->new( throw => 'frobless' );
+
=head2 warning()
This method is very similar to C<error()> described above. However,
@@ -808,15 +921,18 @@
die "warning while disengaging warp drive: ",
$object->warnings();
}
+
+=head2 decline($reason, $more_reasons, ...)
-=head2 decline($reason)
+This method concatentates all arguments into a single string, stores
+it internally, and then returns C<undef>. The string should indicate
+a reason for declining a request (e.g. "frobulator template not found")
+and can be subsequently retrieved via the C<declined()> method.
-This method is similar to the C<error()> method described above. In
-fact, it is implemented as a wrapper around C<error()>, forwarding all
-arguments to allow the object to set its internal error string. However,
-instead of returning C<undef>, the C<decline()> method returns 0.
+=head2 declined()
-This may be subject to change.
+Returns the reason for declining a request, as set by the most recent call
+to C<decline()>.
=head2 debug($msg1, $msg2, ...)
@@ -864,7 +980,7 @@
=head1 VERSION
-$Revision: 1.1 $
+$Revision: 1.2 $
=head1 COPYRIGHT