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

cvs@template-toolkit.org cvs@template-toolkit.org
Fri, 17 Dec 2004 15:34:51 +0000


cvs         04/12/17 15:34:50

  Modified:    lib/Template Context.pm
  Log:
  * new implementation of template() and component()
  
  Revision  Changes    Path
  1.15      +105 -147  TT3/lib/Template/Context.pm
  
  Index: Context.pm
  ===================================================================
  RCS file: /template-toolkit/TT3/lib/Template/Context.pm,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- Context.pm	2004/12/17 14:20:49	1.14
  +++ Context.pm	2004/12/17 15:34:50	1.15
  @@ -16,7 +16,7 @@
   #   modify it under the same terms as Perl itself.
   #
   # REVISION
  -#   $Id: Context.pm,v 1.14 2004/12/17 14:20:49 abw Exp $
  +#   $Id: Context.pm,v 1.15 2004/12/17 15:34:50 abw Exp $
   #
   #========================================================================
   
  @@ -39,7 +39,7 @@
   use constant FETCH => 'fetch';
   use constant GET   => 'get';
   
  -our $VERSION   = sprintf("%d.%02d", q$Revision: 1.14 $ =~ /(\d+)\.(\d+)/);
  +our $VERSION   = sprintf("%d.%02d", q$Revision: 1.15 $ =~ /(\d+)\.(\d+)/);
   our $DEBUG     = 0 unless defined $DEBUG;
   our $ERROR     = '';
   our $THROW     = 'context';
  @@ -176,10 +176,10 @@
           # create a path object for manipulating the path and cache it
           my $pathclass = $self->pkgvar( PATH => $PATH );
           $pathclass->new($self->{ path } || $self->path())
  -            || return $self->error($pathclass->error());
  +            || $self->throw( path => $pathclass->error() );
       };
       my $paths = $path->paths(@_)
  -        || $self->error($path->error());
  +        || $self->throw( path => $path->error() );
   
       return wantarray ? @$paths : $paths;
   }
  @@ -227,73 +227,27 @@
   
       $self->debug("component($name)\n") if $debug;
   
  +    # $name may already be a component object
  +    if (UNIVERSAL::isa($name, $cclass)) {
  +        $self->debug(" - already a component: ", $name->id()) if $debug;
  +        return $name;
  +    }
  +
  +    # fetch template for this component $name
  +    my $template = $self->template($name);
  +
       # TODO: check local component cache
   
       my $global = $self->{ global } || $self->global();
  -    my $paths  = $global->{ paths };   # id map for static paths
       my $cache  = $global->{ cache };   # in-memory component cache
       my $store  = $global->{ store };   # on-disk component store
  -    my ($component, $template, $id, $path, $names, $static);
  -
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
  -    # Identify
  -    #   First we need to figure out exactly which template is wanted, 
  -    #   resolving ambiguous names (e.g. '.../foo') which can have 
  -    #   multiple possible locations.  We're looking for a template id,
  -    #   to uniquely identify the template.
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
  -
  -    if (ref $name) {
  -        # $name may already be a component
  -        return $name if UNIVERSAL::isa($name, $cclass);
  -
  -        # let template() handle a reference to something else, 
  -        $template = $self->template($name) || return;
  -        $id   = $template->id();
  -        $path = $template->path();
  -    }
  -    else {
  -        # expand $name template name into full path name(s) computed
  -        # relative to the current context path
  -        my $names = $self->paths($name) || return;
  -        $self->debug("paths: ", join(', ', @$names), "\n"), if $debug;
  -
  -        
  -        foreach $path (@$names) {
  -            $self->debug(" - path: $path\n") if $debug;
  +    my ($component, $id, $path, $names, $static);
   
  -            # If there is a global paths cache and the requested path
  -            # is an absolute one then it is static.  We can cache the
  -            # id returned for it so we don't have to look for the
  -            # template again next time we use it
  -            $static = $paths && $path =~ m[^(\w+:)?/];
  +    # get template's unique id suitable for cache/store indexing
  +    $id = $template->id();
   
  -            if ($static && ($id = $paths->{ $path })) {
  -                $self->debug(" - mapped static path '$path' to id '$id'\n") 
  -                    if $debug;
  -                last;
  -            }
  -            elsif ($template = $self->template($path)) {
  -                $id = $template->id();
  -                $self->debug(" - sourced template '$path' with id '$id'\n") 
  -                    if $debug;
  -                # save static path for next time
  -                $paths->{ $path } = $id if $static;
  -                last;
  -            }
  -        }
  -        # we should have a valid template id, or we can't find it
  -        return $self->error("template not found: $name")
  -            unless $id;
  -    }
  -    $self->debug("template path : $path\n") if $debug;
  -
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
  -    # Cache
  -    #   now we've got a template id we can look in the memory cache to
  -    #   see if we already have a compiled component for this template,
  -    #   If we do we check that it's fresh compared to its source template
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  +    # look first in the in-memory cache for a compiled component, and
  +    # if found, check that it's fresh wrt to its template source
   
       if ($cache && ($component = $cache->get($id))) {
           if ($component->fresh()) {
  @@ -306,21 +260,11 @@
           }
       }
   
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  -    # Store
  -    #   If we didn't find the component in the cache then we look for
  -    #   it in the store.  If we find it then we restore its link to a
  -    #   source template so that it can subsequently check its
  -    #   freshness.  If we haven't got a source template (e.g. if we used
  -    #   an id fetched from the global cache for static paths) then we
  -    #   need to go and fetch the complete template first.
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  -            
  -    if ($store && ($component = $store->get($id))) {
  -        # fetch source object if we need to
  -        $template ||= $self->template($path) || return;
  +    # next try the persistant store (if in use) and if found, restore
  +    # its link to the template source object so that it can check its
  +    # freshness.  If it is fresh then we cache it in memory.
   
  -        # notify component of its source object
  +    if ($store && ($component = $store->get($id))) {
           $component->source($template);
   
           if ($component->fresh()) {
  @@ -333,125 +277,139 @@
                   if $debug;
           }
       }
  -
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  -    # Compile
  -    #   If we haven't got a cached/stored component then we have to
  -    #   create one from the template.  If we haven't got a complete 
  -    #   template yet (e.g. we used a static path to get the template id)
  -    #   then we need to get fetch it now.
  -    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  -        
  -    # TODO: $path may be undefined?
  -    $template ||= $self->template($path) || do {
  -        # this should probably never happen, but never say never....
  -        # we could get an id for a template one minute, cache it in
  -        # the static paths, but then some time later, the provider
  -        # could withdraw it.  But if that happens then there shouldn't
  -        # be a global paths cache for static paths in the first place
  -        delete $paths->{ $path } if $static;
  -        return $self->error("template not found (cached id error): $path");
  -    };
   
  -    # cache the template id for a static path
  -    # TODO: warning ($path undefined)
  -    $self->debug("setting path [$path]\n") if $debug;
  -    $paths->{ $path } = $template->id() if $static;
  -
  -    # now we should have a valid source ready to be compiled
  +    # if we haven't got a component from the cache or store then we 
  +    # compile it from the template source
       $component = $template->component(context => $self) 
  -        || return $self->error($template->error());
  +        || return $self->throw( component => $template->error() );
   
       # give the component a chance to cache/store itself
       $component->cache($cache) if $cache;
       $component->store($store) if $store;
   
  +    # TODO: $template->strip() to remove any dead wood before caching
  +
       return $component;
   }
   
   
  -sub template {
  -    my ($self, $path) = @_;
  -    my $debug = $self->{ DEBUG };
  -    my $source;
  +# TODO: may have a context local hash for mapping any names (including 
  +# relative ones) to a template
   
  -    $self->debug("template($path)\n") if $debug;
   
  +sub template {
  +    my ($self, $name) = @_;
       my $tclass = $self->pkgvar( TEMPLATE => $TEMPLATE );
  +    my $debug  = $self->{ DEBUG };
  +    my $template;
   
  -    if (ref $path) {
  -        # $path can be a reference to something
  -        $source = $path;
  +    $self->debug("template($name)\n") if $debug;
  +
  +    if (ref $name) {
  +        # $name can be a reference to something already
  +        $template = $name;
       }
       else {
  -        # otherwise it's the name of a template which we look for
  -        # in the templates for the context and any parents
  -        $source = $self->find( templates => $path ) 
  -            || return $self->decline("template not found: $path");
  +        # get list of one or more paths to try for $name and a reference to
  +        # any global_paths cache mapping explicit paths to template objects
  +        my $paths  = $self->paths($name);
  +        my $global = $self->{ global } || $self->global();
  +        my $gpaths = $global->{ paths };
  +        my $gpath;
  +
  +        $self->debug("- trying paths: ", join(', ', @$paths), "\n") if $debug;
  +        
  +        foreach my $path (@$paths) {
  +            $self->debug(" - path: $path\n") if $debug;
  +
  +            # $gpath flag indicates global_paths are in use ($gpaths)
  +            # and the path is explicit, suitable for global caching
  +            $gpath = $gpaths && $path =~ m[^(\w+:)?/];
  +
  +            if ($gpath && ($template = $gpaths->{ $path })) {
  +                $self->debug(" - found template in global paths cache: $path\n")
  +                    if $debug;
  +                $name = $path;
  +                last;
  +            }
  +            elsif ($template = $self->find( templates => $path )) {
  +                $self->debug(" - found template in context templates: $path\n")
  +                    if $debug;
  +                # cache template in global_path if $gpath set
  +                $gpaths->{ $path } = $template if $gpath;
  +                $name = $path;
  +                last;
  +            }
  +        }
  +        return $self->throw( template => "not found: $name")
  +            unless $template;
       }
   
  -    # $source should be a Template::Template object (or whatever
  -    # the current value of $tclass is), a code reference, or a 
  -    # text string or reference to one, all of which get upgraded
  -    # to Template::Template objects if necessary.
  +    # $template can be a Template::Template object (or whatever the
  +    # current value of $tclass is), a code reference, a text string or
  +    # reference to one, all of which get upgraded to
  +    # Template::Template objects if necessary.
   
  -    if (UNIVERSAL::isa($source, $tclass)) {
  -        $self->debug(" - template source is already a template object\n")
  +    if (UNIVERSAL::isa($template, $tclass)) {
  +        $self->debug(" - template is already a template object: $name\n")
               if $debug;
  -        return $source;
  +        return $template;
       }
  -    elsif (UNIVERSAL::isa($source, 'HASH')) {
  -        # $source is a hash reference
  -        $self->debug(" - constructing template object from hash reference\n")
  +    elsif (UNIVERSAL::isa($template, 'HASH')) {
  +        $self->debug(" - constructing template from hash reference: $name\n")
               if $debug;
           
  -        $source->{ path } = $path
  -            unless defined $source->{ path };
  +        $template->{ path } = $name
  +            unless defined $template->{ path };
  +
  +        $template->{ id } = "hash:$name"
  +            unless defined $template->{ id };
   
  -        $source->{ id } = "hash:$path"
  -            unless defined $source->{ id };
  +        $template->{ time } = CORE::time()
  +            unless defined $template->{ time };
           
  -        return $tclass->new($source)
  -            || $self->error($tclass->error());
  +        return $tclass->new($template)
  +            || $self->throw( template => $tclass->error() );
       }
  -    elsif (UNIVERSAL::isa($source, 'CODE')) {
  -        # $source is an anonymous subroutine reference
  -        $self->debug(" - constructing template object from code reference\n")
  +    elsif (UNIVERSAL::isa($template, 'CODE')) {
  +        $self->debug(" - constructing template object from code reference: $name\n")
               if $debug;
   
           return $tclass->new({
  -            id    => "code:$path",
  -            path  => $path,
  +            id    => "code:$name",
  +            path  => $name,
               time  => CORE::time(),
  -            code  => $source,
  +            code  => $template,
               text  => '',
               fresh => 1,
               cache => 0,
               store => 0,
  -        }) || $self->error($tclass->error());
  +        }) || $self->throw( template => $tclass->error() );
       }
  -    elsif (UNIVERSAL::isa($source, 'SCALAR') || ! ref $source) {
  -        # $source is plain text or a reference to a scalar
  +    elsif (UNIVERSAL::isa($template, 'SCALAR') || ! ref $template) {
  +        # $template is plain text or a reference to a scalar
           $self->debug(" - constructing template object from template text\n")
               if $debug;
   
           return $tclass->new({
  -            id    => "text:$path",
  -            path  => $path,
  +            id    => "text:$name",
  +            path  => $name,
               time  => CORE::time(),
  -            text  => $source,
  +            text  => $template,
               fresh => 1,
               cache => 0,
               store => 0,
  -        }) || $self->error($tclass->error());
  +        }) || $self->throw( template => $tclass->error() );
       }
       else {
  -        return $self->error("invalid template source: $source");
  +        return $self->throw( template => "invalid template: $template" );
       }    
   }
   
   
   
  +
  +
   sub process {
       my ($self, $paths, $params) = @_;
       my $output = '';
  @@ -551,7 +509,7 @@
   
   =head1 VERSION
   
  -$Revision: 1.14 $
  +$Revision: 1.15 $
   
   =head1 COPYRIGHT