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

cvs@template-toolkit.org cvs@template-toolkit.org
Thu, 25 Mar 2004 14:28:16 +0000


cvs         04/03/25 14:28:15

  Modified:    lib/Template Source.pm
  Log:
  * enhanced component() method to build components out of existing
    subroutine references and also do the right thing if passed an
    existing component reference
  
  Revision  Changes    Path
  1.2       +89 -40    TT3/lib/Template/Source.pm
  
  Index: Source.pm
  ===================================================================
  RCS file: /template-toolkit/TT3/lib/Template/Source.pm,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Source.pm	2004/03/23 14:57:58	1.1
  +++ Source.pm	2004/03/25 14:28:15	1.2
  @@ -17,7 +17,7 @@
   #   modify it under the same terms as Perl itself.
   #
   # REVISION
  -#   $Id: Source.pm,v 1.1 2004/03/23 14:57:58 abw Exp $
  +#   $Id: Source.pm,v 1.2 2004/03/25 14:28:15 abw Exp $
   #
   #========================================================================
   
  @@ -25,15 +25,19 @@
   
   use strict;
   use warnings;
  +use Template::Component;
   use Template::Base;
   use base qw( Template::Base );
  -use vars qw( $VERSION $DEBUG $ERROR $LIFE );
  +use vars qw( $VERSION $DEBUG $ERROR $LIFE $COMPONENT );
   
  -$VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
  -$DEBUG   = 0 unless defined $DEBUG;
  -$ERROR   = '';
  -$LIFE    = 60;     # default lifetime is 60 seconds before re-stat
  +$VERSION   = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
  +$DEBUG     = 0 unless defined $DEBUG;
  +$ERROR     = '';
  +$COMPONENT = 'Template::Component';
  +#$THROW    = 'source';
  +$LIFE     = 60;     # default lifetime is 60 seconds before re-stat
   
  +# TODO: make component an option
   
   #------------------------------------------------------------------------
   # init()
  @@ -195,7 +199,8 @@
   
       return $self->{ text } ||= do {
           my $provider = $args->{ provider } || $self->{ provider } 
  -            || return $self->error('no provider defined');
  +            || return $self->error('no provider to load template text: ',
  +                                   $self->{ id });
   
           $provider->load($self->{ load })
               || return $self->error($provider->error());
  @@ -251,18 +256,58 @@
       my $code = $self->{ code } || $self->code(@_) || return;
       my $component;
   
  -    # trap any errors thrown via die()
  -    local $SIG{__WARN__} = sub { die(@_) };
  -
  -    # evaluate Perl code to generate component object
  -    $component = eval $$code;
  -
  -    # check for errors
  -    return $self->error("failed to create component: $@")
  -        if $@ || ! $component;
  +    if (UNIVERSAL::isa($code, 'SCALAR')) {
  +        # this is the usual case where $code is a reference to a scalar
  +        # containing the Perl code compiled from the template source.
  +        # we first set up a hook to throw warnings as errors and then 
  +        # eval the Perl code to (hopefull) generate a live component.
  +
  +        $self->debug("evaluating component source code\n") if $self->{ DEBUG };
  +
  +        # trap any errors thrown via die()
  +        local $SIG{__WARN__} = \&death;
  +
  +        # evaluate Perl code to generate component object
  +        $component = eval $$code
  +            || return $self->error("failed to evaluate component source code: $@");
  +    }
  +    elsif (UNIVERSAL::isa($code, 'CODE')) {
  +        # looks like we've already got a code reference, probably
  +        # provided as an anonymous subroutine, but we must delete
  +        # it from the source and create a dummy value instead to 
  +        # indicate that the source code (i.e. Perl code) isn't 
  +        # available any more (or ever in this case).
  +
  +        $self->debug("creating component code wrapper\n") if $self->{ DEBUG };
  +
  +        my $dummy_code = '';
  +        $self->{ code } = \$dummy_code;
  +        
  +        $component = $COMPONENT->new({
  +            name => $self->{ name },
  +            path => $self->{ path },
  +            time => $self->{ time },
  +            body => $code,
  +            options => $self->{ options },
  +        }) || return $self->error($COMPONENT->error());
  +    }
  +    elsif (UNIVERSAL::isa($code, $COMPONENT)) {
  +        # looks like we've already got a component, but we also
  +        # need to blank out the code reference to avoid circular
  +        # references when we bind the source to the component below
  +
  +        $self->debug("using existing component\n") if $self->{ DEBUG };
  +
  +        $component = $code;
  +        $code = '';
  +        $self->{ code } = \$code;
  +    }
  +    else {
  +        return $self->error("invalid source code type: $code\n");
  +    }
   
       # set source in component
  -    # $component->source($self);
  +    $component->source($self);
   
       $self->debug("created component: $component\n") if $self->{ DEBUG };
   
  @@ -301,42 +346,26 @@
               if $self->{ DEBUG };
           return 1;
       }
  -
  -    # TODO: should we just return OK, or not?
   
  +    # if we haven't got a provider then we assume we're fresh
       my $provider = $self->{ provider } 
  -        || return $self->error('no provider defined');
  +        || return 1;
   
  -    my $time = $provider->time($self->{ load });
  +    my $time = $provider->time($self->{ load })
  +        || return 1;
   
  -    return $self->error($provider->error())
  -        unless defined $time;
  -
       return $time > $self->{ time } ? 0 : 1;
   }
   
   
   #------------------------------------------------------------------------
  -# strip()
  -#
  -# Delete anything non-essential and potentially large (e.g. text and 
  -# code) to reduce the memory footprint of the object as much as possible
  -# to make it more suitable for caching in memory.
  -#------------------------------------------------------------------------
  -
  -sub strip {
  -    my $self = shift;
  -    delete @$self{ qw( text code ) };
  -    return $self;
  -}
  -
  -
  -#------------------------------------------------------------------------
   # stub()
   #
   # Return a reference to a hash array containing the minimal set of data
   # items (id and time) required to identifying the source to a cache, 
   # store or other template storage mechanism.
  +# TODO: don't think we need this any more - templates only stored id
  +# in srcmap now
   #------------------------------------------------------------------------
   
   sub stub {
  @@ -348,6 +377,21 @@
   }
   
   
  +#------------------------------------------------------------------------
  +# death(@_)
  +#
  +# Simple handler which is used to catch compilation warnings and upgrade
  +# then to errors, thrown via die.
  +#------------------------------------------------------------------------
  +
  +sub death { 
  +    die @_;
  +}
  +
  +
  +
  +
  +
   1;
   
   __END__
  @@ -379,6 +423,11 @@
   the source of a template, typically a file, as provided by a
   Template::Provider.
   
  +TODO: the code is shifting a little and the docs are lagging behind.
  +Most of what is written below should be accurate, but I haven't done
  +a final sweep.  Some recent changes in component() method haven't been
  +documented (like 'code' being a subroutine ref, or existing component).
  +
   =head1 METHODS
   
   =head2 new()
  @@ -533,7 +582,7 @@
   
   =head1 VERSION
   
  -$Revision: 1.1 $
  +$Revision: 1.2 $
   
   =head1 COPYRIGHT