added compiled loop support
Uri Guttman [Sun, 14 Dec 2008 07:08:06 +0000 (02:08 -0500)]
added compile scalar vs hash data support
needs testing and benchmarking

lib/Template/Simple.pm

index 1b603d0..d4804ba 100644 (file)
@@ -115,8 +115,7 @@ no warnings ;
 sub {
        my( \$data ) = \@_ ;
 
-       my \$out =
-       $code_body ;
+       my \$out = $code_body ;
 
        return \\\$out ;
 }
@@ -139,24 +138,22 @@ sub _compile_chunk {
 
        return '' unless length $template ;
 
-       $indent .= "\t" ;
-
        my @parts ;
 
 # loop all nested chunks and the text separating them
 
        while( $template =~ m{$self->{chunk_re}}g ) {
 
-# grab the pre-chunk text and compile it for scalars and save all of its parts
+# grab the pre-match text and compile its scalars and save all of its parts
 
                push @parts, $self->_compile_scalars(
                                substr( $template, 0, $-[0] ) ) ;
 
 # compile the nested chunk and save its parts
 
-               push @parts, $self->_compile_chunk( $1, $2, $indent ) ;
+               push @parts, $self->_compile_chunk( $1, $2, "$indent\t\t" ) ;
 
-# chop off the pre-chunk and chunk
+# chop off the pre-match and the chunk
 
                substr( $template, 0, $+[0], '' ) ;
        }
@@ -169,24 +166,46 @@ sub _compile_chunk {
 
 # start it with a do{} block open
 
-       my $code = "do {\n$indent" ;
+       my $code = <<CODE ;
+do {
+CODE
+
+       $indent .= "\t" ;
 
 # generate a lookup in data for this chunk name (unless it is the top
 # level). this descends down the data tree during rendering
 
-       $code .= <<CODE . $indent if $chunk_name ;
-my \$data = \$data->{$chunk_name} ;
+       $code .= <<CODE if $chunk_name ;
+${indent}my \$data = \$data->{$chunk_name} ;
+CODE
+
+# add the loop code to handle a scalar or an array
+
+       $code .= <<CODE ;
+${indent}my \$out ;
+${indent}foreach my \$data ( ref \$data eq 'ARRAY' ? \@{\$data} : \$data ) {
+
+       ${indent}\$out .= ref \$data ne 'HASH' ? \$data :
 CODE
 
+       $indent .= "\t" ;
+
 # now generate the code to output all the parts of this chunk. they
 # are all concatentated by the . operator
 
-       $code .= join( "\n$indent.\n$indent", @parts ) ;
+       $code .= $indent . join( "\n$indent.\n$indent", @parts ) ;
 
-# now we close the do block
+       chop $indent ;
+
+# now we end the .= statement, the loop and the do block for this chunk
+       $code .= <<CODE ;
+ ;
+$indent}
+$indent\$out ;
+CODE
 
        chop $indent ;
-       $code .= "\n$indent}" ;
+       $code .= "$indent}" ;
 
        return $code ;
 }
@@ -241,22 +260,25 @@ 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
+
+               if ( my $compiled = $self->{compiled_cache}{$template_name} ) {
 
-# TODO: look for template by name 
+                       return $compiled->($data) ;
+               }
 
-       my $template = eval{ $self->_get_template($1) } ;
+# not compiled so get this template by name
 
-print "GOT [$template]\n" ;
+               $tmpl_ref ||= eval{ $self->_get_template($template_name) } ;
 
-# force the template into a ref
+# we couldn't find this template name so assume it is the template text
 
-       my $tmpl_ref = ref $template eq 'SCALAR' ? $template : \$template ;
+               $tmpl_ref ||= \$template_name ;
+       }
 
        my $rendered = $self->_render_includes( $tmpl_ref ) ;