[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