CAM-Template
view release on metacpan or search on metacpan
lib/CAM/Template.pm view on Meta::CPAN
#==============================
# PRIVATE FUNCTION
sub _preparse
{
my $self = shift;
my $content = $self->{content};
return $self if ($content->{parsed});
$content->{skip} = {};
$content->{studied} = 0;
$content->{loops} = {};
$content->{loop_cache} = {};
$content->{staticparams} = {};
# Retrieve constant parameters set in the template files
my $static_re = $self->{patterns}->{staticvars};
$content->{string} =~ s/$static_re/$$content{staticparams}{$1}=$2; ""/ge;
# Break up all loops
my $re1 = $self->{patterns}->{loopstart};
my $re2 = $self->{patterns}->{loopend};
my ($start,$end) = split /\$1/, $self->{patterns}->{loop_out}, 2;
my @parts = split /$re1/, $content->{string};
while (@parts > 2) {
my $tail = pop @parts;
my $name = pop @parts;
if ($tail =~ s/^(.*?)$re2/$start$name$end/s)
{
$content->{loops}->{$name} = $1;
}
else
{
warn "Found loop start for '$name' but no loop end";
}
$parts[$#parts] .= $tail;
}
$content->{string} = $parts[0];
$content->{parsed} = 1;
return $self;
}
#==============================
# PRIVATE FUNCTION
sub _fetchfile
{
my $self = shift;
my $filename = shift;
my $cache;
if ($self->{use_cache})
{
my $pkg = ref($self);
$global_filecache{$pkg} ||= {};
$cache = $global_filecache{$pkg};
}
if ($self->{use_cache} && exists $cache->{$filename} &&
$cache->{$filename}->{time} >= (stat($filename))[9])
{
return $cache->{$filename};
}
else
{
my $struct = {
studied => 0,
skip => {},
};
local *FILE;
if (!open(FILE, $filename))
{
&carp("Failed to open file '$filename': $!");
return undef;
}
local $/ = undef;
$struct->{string} = <FILE>;
close(FILE);
if ($self->{include_files})
{
# Recursively add included files -- must be in the same directory
my $dir = $filename;
$dir =~ s,/[^/]+$,,; # remove filename
$dir .= "/" if ($dir =~ /[^\/]$/);
my $re = $self->{patterns}->{include};
$struct->{string} =~ s/$re/ $self->_fetchfile("$dir$1")->{string} /ge;
}
if ($self->{use_cache})
{
$struct->{time} = (stat($filename))[9];
$cache->{$filename} = $struct;
}
return $struct;
}
}
#==============================
=item toString
Executes the search/replace and returns the content.
=cut
sub toString
{
my $self = shift;
return "" unless ($self->{content});
my $content = $self->{content}->{string};
return "" unless (defined $content);
my $re_hash = $self->{patterns};
my $skip = $self->{content}->{skip};
{
# Turn off warnings, since it is likely that some parameters
# will be undefined
no warnings;
# incoming params can override template params
my %params = (
"__filename__" => $self->{filename},
%{$self->{content}->{staticparams}},
%{$self->{params}},
);
unless ($skip->{cond})
{
# Do the following multiple times to handle nested conditionals
if ($re_hash->{if} && $re_hash->{unless}) # legacy subclassing
{
&carp("DEPRECATED: please use 'ifunless' instead of 'if' and 'unless'\n" .
"in your patterns. There was a subtle bug in the old way, and\n" .
"the new way is too slow with 'if' and 'unless'\n");
my $pos = 1;
my $neg = 1;
do {
if ($neg)
{
$neg = ($content =~ s/$$re_hash{unless}/(!$params{$1}) ? $2 : ''/ge);
}
if ($pos)
{
$pos = ($content =~ s/$$re_hash{if}/$params{$1} ? $2 : ''/ge);
}
} while ($neg || $pos);
}
( run in 2.208 seconds using v1.01-cache-2.11-cpan-437f7b0c052 )