Template-Toolkit
view release on metacpan or search on metacpan
lib/Template/Provider.pm view on Meta::CPAN
$alias = $name unless defined $alias or ref $name;
$self->debug("_load($name, ", $alias // '<no alias>',
')') if $self->{ DEBUG };
# SCALAR ref is the template text
if (ref $name eq 'SCALAR') {
# $name can be a SCALAR reference to the input text...
return {
name => $alias // 'input text',
path => $alias // 'input text',
text => $$name,
time => $now,
load => 0,
};
}
# Otherwise, assume GLOB as a file handle
if (ref $name) {
local $/;
my $text = <$name>;
$text = $self->_decode_unicode($text) if $self->{ UNICODE };
return {
name => $alias // 'input file handle',
path => $alias // 'input file handle',
text => $text,
time => $now,
load => 0,
};
}
# Otherwise, it's the name of the template
if ( defined $self->_template_modified( $name ) ) { # does template exist?
my ($text, $error, $mtime ) = $self->_template_content( $name );
unless ( $error ) {
$text = $self->_decode_unicode($text) if $self->{ UNICODE };
return {
name => $alias,
path => $name,
text => $text,
time => $mtime,
load => $now,
};
}
return ( $error, Template::Constants::STATUS_ERROR )
unless $tolerant;
}
# Unable to process template, pass onto the next Provider.
return (undef, Template::Constants::STATUS_DECLINED);
}
#------------------------------------------------------------------------
# _refresh(\@slot)
#
# Private method called to mark a cache slot as most recently used.
# A reference to the slot array should be passed by parameter. The
# slot is relocated to the head of the linked list. If the file from
# which the data was loaded has been updated since it was compiled, then
# it is re-loaded from disk and re-compiled.
#------------------------------------------------------------------------
sub _refresh {
my ($self, $slot) = @_;
my $stat_ttl = $self->{ STAT_TTL };
my ($head, $file, $data, $error);
$self->debug(
"_refresh([ ",
join(', ', map { $_ // '<undef>' } @$slot),
'])'
) if $self->{ DEBUG };
# if it's more than $STAT_TTL seconds since we last performed a
# stat() on the file then we need to do it again and see if the file
# time has changed
my $now = time;
my $expires_in_sec = $slot->[ STAT ] + $stat_ttl - $now;
if ( $expires_in_sec <= 0 ) { # Time to check!
$slot->[ STAT ] = $now;
# Grab mtime of template.
# Seems like this should be abstracted to compare to
# just ask for a newer compiled template (if it's newer)
# and let that check for a newer template source.
my $template_mtime = $self->_template_modified( $slot->[ NAME ] );
if ( ! defined $template_mtime || ( $template_mtime != $slot->[ LOAD ] )) {
$self->debug("refreshing cache file ", $slot->[ NAME ])
if $self->{ DEBUG };
($data, $error) = $self->_load($slot->[ NAME ], $slot->[ DATA ]->{ name });
($data, $error) = $self->_compile($data, $self->_compiled_filename($slot->[ NAME ]))
unless $error;
if ($error) {
# if the template failed to load/compile then we wipe out the
# STAT entry. This forces the provider to try and reload it
# each time instead of using the previously cached version
# until $STAT_TTL is next up
$slot->[ STAT ] = 0;
}
else {
$slot->[ DATA ] = $data->{ data };
$slot->[ LOAD ] = $data->{ time };
}
}
} elsif ( $self->{ DEBUG } ) {
$self->debug( sprintf('STAT_TTL not met for file [%s]. Expires in %d seconds',
$slot->[ NAME ], $expires_in_sec ) );
}
# Move this slot to the head of the list
unless( $self->{ HEAD } == $slot ) {
# remove existing slot from usage chain...
if ($slot->[ PREV ]) {
$slot->[ PREV ]->[ NEXT ] = $slot->[ NEXT ];
}
else {
$self->{ HEAD } = $slot->[ NEXT ];
}
if ($slot->[ NEXT ]) {
$slot->[ NEXT ]->[ PREV ] = $slot->[ PREV ];
}
else {
$self->{ TAIL } = $slot->[ PREV ];
}
# ..and add to start of list
$head = $self->{ HEAD };
$head->[ PREV ] = $slot if $head;
$slot->[ PREV ] = undef;
$slot->[ NEXT ] = $head;
$self->{ HEAD } = $slot;
}
return ($data, $error);
}
#------------------------------------------------------------------------
# _store($name, $data)
#
# Private method called to add a data item to the cache. If the cache
# size limit has been reached then the oldest entry at the tail of the
# list is removed and its slot relocated to the head of the list and
# reused for the new data item. If the cache is under the size limit,
# or if no size limit is defined, then the item is added to the head
# of the list.
# Returns compiled template
#------------------------------------------------------------------------
sub _store {
my ($self, $name, $data, $compfile) = @_;
my $size = $self->{ SIZE };
my ($slot, $head);
# Return if memory cache disabled. (overriding code should also check)
# $$$ What's the expected behaviour of store()? Can't tell from the
# docs if you can call store() when SIZE = 0.
return $data->{data} if defined $size and !$size;
# check the modification time -- extra stat here
my $load = $data->{ mtime } || $self->_modified($name);
# extract the compiled template from the data hash
$data = $data->{ data };
$self->debug("_store($name, $data)") if $self->{ DEBUG };
if (defined $size && $self->{ SLOTS } >= $size) {
# cache has reached size limit, so reuse oldest entry
$self->debug("reusing oldest cache entry (size limit reached: $size)\nslots: $self->{ SLOTS }") if $self->{ DEBUG };
# remove entry from tail of list
$slot = $self->{ TAIL };
$slot->[ PREV ]->[ NEXT ] = undef;
$self->{ TAIL } = $slot->[ PREV ];
# remove name lookup for old node
delete $self->{ LOOKUP }->{ $slot->[ NAME ] };
# add modified node to head of list
$head = $self->{ HEAD };
$head->[ PREV ] = $slot if $head;
@$slot = ( undef, $name, $data, $load, $head, time );
$self->{ HEAD } = $slot;
# add name lookup for new node
$self->{ LOOKUP }->{ $name } = $slot;
}
else {
# cache is under size limit, or none is defined
$self->debug("adding new cache entry") if $self->{ DEBUG };
# add new node to head of list
$head = $self->{ HEAD };
$slot = [ undef, $name, $data, $load, $head, time ];
$head->[ PREV ] = $slot if $head;
$self->{ HEAD } = $slot;
$self->{ TAIL } ||= $slot;
# add lookup from name to slot and increment nslots
$self->{ LOOKUP }->{ $name } = $slot;
$self->{ SLOTS }++;
}
( run in 0.688 second using v1.01-cache-2.11-cpan-5511b514fd6 )