[Templates-cvs] cvs commit: TT3/lib/Template Exception.pm

cvs@template-toolkit.org cvs@template-toolkit.org
Tue, 23 Mar 2004 10:47:07 +0000


cvs         04/03/23 10:47:07

  Added:       lib/Template Exception.pm
  Log:
  * added Template::Exception module
  
  Revision  Changes    Path
  1.1                  TT3/lib/Template/Exception.pm
  
  Index: Exception.pm
  ===================================================================
  #========================================================================
  #
  # Template::Exception
  #
  # DESCRIPTION
  #   Module implementing an exception class for reporting structured
  #   errors.
  # 
  # AUTHOR
  #   Andy Wardley <abw@wardley.org>
  #
  # COPYRIGHT
  #   Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
  #   Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
  #   Copyright (C) 2003-2004 Fotango Ltd.
  #
  #   This module is free software; you can redistribute it and/or
  #   modify it under the same terms as Perl itself.
  #
  # REVISION
  #   $Id: Exception.pm,v 1.1 2004/03/23 10:47:07 abw Exp $
  #
  # TODO
  #   Decide if exceptions still need to handle text buffers and how
  #   they should do it.
  #
  #========================================================================
  
  package Template::Exception;
  
  use strict;
  use warnings;
  use Template::Base;
  use base qw( Template::Base );
  use vars qw( $VERSION $DEBUG $ERROR );
  
  $VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
  $DEBUG   = 0 unless defined $DEBUG;
  $ERROR   = '';
  
  use strict;
  use warnings;
  use vars qw( $VERSION $DEFAULT $FORMAT );
  use overload 
      q|""|    => "text", 
      fallback => 1;
  
  $VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
  $DEFAULT = {
      type => 'undef',
      info => '(no information)',
  };
  $FORMAT  = '<type> error - <info>';
      
  
  
  
  #------------------------------------------------------------------------
  # new($type, $info)
  #------------------------------------------------------------------------
  
  sub new {
      my ($class, $type, $info, $text) = @_;
      my $default;
  
      # look for $DEFAULT hash in derived package 
      no strict 'refs';
      $default = ${"$class\::DEFAULT"} || $DEFAULT;
  
      $type = $default->{ type } 
          unless defined($type) and length($type);
      $info = $default->{ info } 
          unless defined($info) and length($info);
  
      bless {
          type => $type,
          info => $info,
      }, $class;
  }
  
  
  #------------------------------------------------------------------------
  # type()
  #
  # Get/set the exception type.
  #------------------------------------------------------------------------
  
  sub type {
      my $self = shift;
      return @_ ? ($self->{ type } = shift) : $self->{ type };
  }
  
  
  #------------------------------------------------------------------------
  # info()
  #
  # Get/set the exception info.
  #------------------------------------------------------------------------
  
  sub info {
      my $self = shift;
      return @_ ? ($self->{ info } = shift) : $self->{ info };
  }
  
  
  #------------------------------------------------------------------------
  # text()
  #
  # Return a text string containing the type and info fields.
  #------------------------------------------------------------------------
  
  sub text {
      my $self   = shift;
      my $format = shift || do {
          # look for $FORMAT hash in derived package 
          no strict 'refs';
          my $class = ref $self || $self;
          ${"$class\::FORMAT"} || $FORMAT;
      };
  
      $format =~ s/<(\w+)>/defined $self->{ $1 } ? $self->{ $1 } : "(no $1)"/eg;
  
      return $format;
  }
  
  
  #------------------------------------------------------------------------
  # match_type(@types)
  # 
  # Selects the most appropriate handler for the current exception type, 
  # from the list of types passed in as arguments.  The method returns the
  # item which is an exact match for type or the closest, more 
  # generic handler (e.g. foo being more generic than foo.bar, etc.)
  #------------------------------------------------------------------------
  
  sub match_type {
      my ($self, @types) = @_;
      my $type = $self->{ type };
      my %thash;
      @thash{ @types } = (1) x @types;
  
      while ($type) {
          return $type if $thash{ $type };
  
          # strip .element from the end of the exception type to find a 
          # more generic handler
          $type =~ s/\.?[^\.]*$//;
      }
      
      return undef;
  }
      
  
  
  1;
  __END__
  
  =head1 NAME
  
  Template::Exception - structured exception for error handling
  
  =head1 SYNOPSIS
  
      use Template::Exception;
  
      # create exception object
      my $exception = Template::Exception->new($type, $info);
  
      # query exception type and info fields
      $type = $exception->type();
      $info = $exception->info();
      ($type, $info) = $exception->type_info();
  
      # print string summarising exception
      print $exception->as_string();
  
      # use automagic stringification 
      print $exception;
  
      # throw exception
      die $exception;
  
  =head1 DESCRIPTION
  
  This module defines an object class for representing exceptions.  An
  exception is a structured error with C<type> and C<info> fields.  The
  C<type> denotes what kind of error occurred (e.g. 'file', 'parser',
  'database', etc.).  The C<info> field provides further information
  about the error (e.g. 'foo/bar.html not found', 'parser error at line
  42', 'server is on fire', etc.)
  
  =head1 METHODS
  
  =head2 new()
  
  Constructor method for creating a new exception.  The first argument should 
  be a string denoting the exception type, followed by a string or reference
  to a data structure providing further information about the exception.
  
      my $exception = Template::Exception->new(
           database => 'could not connect'
      );
  
  =head2 type()
  
  When called without arguments, this method returns the exception type, 
  as defined by the first argument passed to the C<new()> constructor method.
  
      my $type = $exception->type();
  
  It can also be called with an argument to set a new type for the exception.
  
      $exception->type('database');
  
  
  =head2 info()
  
  When called without arguments, this method returns the information field
  for the exception.
  
      my $info = $exception->info();
  
  It can also be called with an argument to define new information for
  the exception.
  
      $exception->info('could not connect');
  
  =head2 text()
  
  This method returns a text representation of the exception object.
  The string returned is formatted as C<$type error - $info>.
  
      print $exception->text();   # database error - could not connect
  
  This method is also bound to the stringification operator, allowing you to
  simple C<print> the exception object to get the same result as calling
  C<text()> explicitly.
  
      print $exception;   # database error - could not connect
  
  =head2 match_type()
  
  This method selects and returns a type string from the arguments passed 
  that is the nearest correct match for the current exception type.  This
  is used to select the most appropriate handler for the exception.
  
      my $match = $exception->match_type('file', 'parser', 'database')
          || die "no match for exception\n";
  
  In this example, the exception will return one of the values C<file>, 
  C<parser> or C<database>, if and only if its type is one of those
  values.  Otherwise it will return undef;
  
  Exception types can be organised into a hierarchical structure by 
  delimiting each part of the type with a period.  For example, the 
  C<database> exception type might be further divided into the more
  specific C<database.connection>, C<database.query> and 
  C<database.server_on_fire> exception types.
  
  An exception of type C<database.connection> will match a handler type
  of C<database.connection> or more generally, C<database>.  The longer
  (more specific) handler name will always match in preference to a shorter
  (more general) handler as shown in the next example:
  
      $exception->type('database.connection');
  
      my $match = $exception->match_type('database', 'database.connection')
          || die "no match for exception\n";
  
      print $match;    # database.connection
  
  When there is no exact match, the C<match_type()> method will return
  something more general that matches.  In the following example, there
  is no specific handler type for C<database.exploded>, but the more
  general C<database> type still matches.
  
      $exception->type('database.exploded');
  
      my $match = $exception->match_type('database', 'database.connection')
          || die "no match for exception\n";
  
      print $match;    # database
  
  =head1 AUTHOR
  
  Andy Wardley  E<lt>abw@wardley.orgE<gt>
  
  =head1 VERSION
  
  $Revision: 1.1 $
  
  =head1 COPYRIGHT
  
    Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
    Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
    Copyright (C) 2003-2004 Fotango Ltd.
  
  This module is free software; you can redistribute it and/or
  modify it under the same terms as Perl itself.
  
  =cut
  
  # Local Variables:
  # mode: perl
  # perl-indent-level: 4
  # indent-tabs-mode: nil
  # End:
  #
  # vim: expandtab shiftwidth=4: