use strict;
use Carp ;
+use Data::Dumper ;
use Scalar::Util qw( reftype ) ;
use File::Slurp ;
-use Data::Dumper ;
our $VERSION = '0.03';
my $code_body = $self->_compile_chunk( '', "${$tmpl_ref}", "\t" ) ;
- $self->{source} = <<CODE ;
-
+ my $source = <<CODE ;
no warnings ;
sub {
my( \$data ) = \@_ ;
- my \$out =
- $code_body ;
+ my \$out ;
+$code_body
return \\\$out ;
}
CODE
- $self->{source_cache}{$template_name} = $self->{source} ;
- print $self->{source} ;
+#print $source ;
- my $code_ref = eval $self->{source} ;
+ my $code_ref = eval $source ;
-die $@ if $@ ;
+print $@ if $@ ;
$self->{compiled_cache}{$template_name} = $code_ref ;
+ $self->{source_cache}{$template_name} = $source ;
}
-
sub _compile_chunk {
my( $self, $chunk_name, $template, $indent ) = @_ ;
return '' unless length $template ;
- $indent .= "\t" ;
-
- my @parts ;
-
-# loop all nested chunks and the text separating them
-
- while( $template =~ m{$self->{chunk_re}}g ) {
+# generate a lookup in data for this chunk name (unless it is the top
+# level). this descends down the data tree during rendering
-# grab the pre-chunk text and compile it for scalars and save all of its parts
+ my $data_init = $chunk_name ? "\$data->{$chunk_name}" : '$data' ;
- push @parts, $self->_compile_scalars(
- substr( $template, 0, $-[0] ) ) ;
+ my $code = <<CODE ;
+${indent}my \@data = $data_init ;
+${indent}while( defined( my \$data = shift \@data ) ) {
-# compile the nested chunk and save its parts
+${indent} if ( ref \$data eq 'ARRAY' ) {
+${indent} push \@data, \@{\$data} ;
+${indent} next ;
+${indent} }
- push @parts, $self->_compile_chunk( $1, $2, $indent ) ;
+CODE
-# chop off the pre-chunk and chunk
+ $indent .= "\t" ;
- substr( $template, 0, $+[0], '' ) ;
- }
+# loop all nested chunks and the text separating them
-# compile trailing text for scalars and save all of its parts
+ while( $template =~ m{$self->{chunk_re}} ) {
- push @parts, $self->_compile_scalars( $template ) ;
+# get the pre-match text and compile its scalars and text. append to the code
-# generate the code for this chunk
+ $code .= $self->_compile_scalars(
+ substr( $template, 0, $-[0] ), $indent ) ;
-# start it with a do{} block open
+# print "OFF: $-[0] $+[0]\n" ;
+# print "PRE: [", substr( $template, 0, $-[0] ), "]\n\n" ;
+# print "CHUNK: [$1] BODY [$2]\n\n" ;
+# print "TRUNC: [", substr( $template, 0, $+[0] ), "]\n\n" ;
+# print "LEFT: [$template]\n\n" ;
- my $code = "do {\n$indent" ;
+# compile the nested chunk and append to the code
-# generate a lookup in data for this chunk name (unless it is the top
-# level). this descends down the data tree during rendering
+ $code .= $self->_compile_chunk( $1, $2, $indent ) ;
- $code .= <<CODE . $indent if $chunk_name ;
-my \$data = \$data->{$chunk_name} ;
-CODE
+# chop off the pre-match and the chunk
-# now generate the code to output all the parts of this chunk. they
-# are all concatentated by the . operator
+ substr( $template, 0, $+[0], '' ) ;
+ }
- $code .= join( "\n$indent.\n$indent", @parts ) ;
+# compile trailing text for scalars and append to the code
-# now we close the do block
+ $code .= $self->_compile_scalars( $template, $indent ) ;
chop $indent ;
- $code .= "\n$indent}" ;
+
+# now we end the loop for this chunk
+ $code .= <<CODE ;
+$indent}
+CODE
return $code ;
}
sub _compile_scalars {
- my( $self, $template ) = @_ ;
+ my( $self, $template, $indent ) = @_ ;
# if the template is empty return no parts
- return unless length $template ;
+ return '' unless length $template ;
my @parts ;
while( $template =~ m{$self->{scalar_re}}g ) {
-# keep the text before the scalar markup and the code to access the scalar
+# get the pre-match text before the scalar markup and generate code to
+# access the scalar
push( @parts,
dump_text( substr( $template, 0, $-[0] ) ),
"\$data->{$1}"
) ;
+
+# truncate the matched text so the next match starts at begining of string
+
substr( $template, 0, $+[0], '' ) ;
}
push @parts, dump_text( $template ) ;
- return @parts ;
+ my $parts_code = join( "\n$indent.\n$indent", @parts ) ;
+
+ return <<CODE ;
+
+${indent}\$out .= ref \$data ne 'HASH' ? \$data :
+${indent}$parts_code ;
+
+CODE
}
-use Data::Dumper ;
sub dump_text {
return $dumped ;
}
+sub get_source {
+
+ my( $self, $template_name ) = @_ ;
+
+ return $self->{source_cache}{$template_name} ;
+}
+
sub render {
my( $self, $template_name, $data ) = @_ ;
-# render with cached code if we precompiled this template
+ my $tmpl_ref = ref $template_name eq 'SCALAR' ? $template_name : '' ;
- if ( my $compiled = $self->{compiled_cache}{$template_name} ) {
+ unless( $tmpl_ref ) {
- return $compiled->($data) ;
- }
+# render with cached code and return if we precompiled this template
-# TODO: look for template by name
+ if ( my $compiled = $self->{compiled_cache}{$template_name} ) {
- my $template = eval{ $self->_get_template($1) } ;
+ return $compiled->($data) ;
+ }
-print "GOT [$template]\n" ;
+# not compiled so get this template by name
-# force the template into a ref
+ $tmpl_ref ||= eval{ $self->_get_template($template_name) } ;
- my $tmpl_ref = ref $template eq 'SCALAR' ? $template : \$template ;
+# we couldn't find this template name so assume it is the template text
+
+ $tmpl_ref ||= \$template_name ;
+ }
my $rendered = $self->_render_includes( $tmpl_ref ) ;
$rendered =~ s{$self->{chunk_re}}
{
# print "CHUNK $1\nBODY\n----\n<$2>\n\n------\n" ;
- print "CHUNK $1\nBODY\n----\n<$2>\n\n------\n" ;
- print "pre CHUNK [$`]\n" ;
+# print "CHUNK $1\nBODY\n----\n<$2>\n\n------\n" ;
+# print "pre CHUNK [$`]\n" ;
${ $self->_render_chunk( \"$2", $href->{$1} ) }
}gex ;
my( $self, @names ) = @_ ;
+# delete all the cached stuff or just the names passed in
+
@names = keys %{$self->{tmpl_cache}} unless @names ;
+# clear out all the caches
+# TODO: reorg these into a hash per name
+
delete @{$self->{tmpl_cache}}{ @names } ;
+ delete @{$self->{compiled_cache}}{ @names } ;
+ delete @{$self->{source_cache}}{ @names } ;
+
+# also remove where we found it to force a fresh search
delete @{$self->{template_paths}}{ @names } ;