]> Dogcows Code - chaz/p5-CGI-Ex/commitdiff
CGI::Ex 2.12 v2.12
authorPaul Seamons <perl@seamons.com>
Fri, 11 May 2007 00:00:00 +0000 (00:00 +0000)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Fri, 9 May 2014 23:46:41 +0000 (17:46 -0600)
16 files changed:
Changes
META.yml
lib/CGI/Ex.pm
lib/CGI/Ex/App.pm
lib/CGI/Ex/Auth.pm
lib/CGI/Ex/Conf.pm
lib/CGI/Ex/Die.pm
lib/CGI/Ex/Dump.pm
lib/CGI/Ex/Fill.pm
lib/CGI/Ex/JSONDump.pm
lib/CGI/Ex/Template.pm
lib/CGI/Ex/Template.pod
lib/CGI/Ex/Validate.pm
samples/memory_template.pl
t/7_template_01_includes.t
t/7_template_02_view.t

diff --git a/Changes b/Changes
index e19a6aff6b138ea586fd27958baf00aed49f5817..fbe0df9ad0d65b9e3a322d0b0c466328cf77f0b2 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,3 +1,13 @@
+2.12
+      2007-05-11
+        * Add STAT_TTL
+        * Add NEGATIVE_STAT_TTL
+        * Add WRAPPER configuation
+        * Add ERROR and ERRORS configuration
+        * Cleanup handling of PRE_PROCESS and POST_PROCESS
+        * Add more tests for the file operations
+        * Cleanup some potential argument issues on cached USE and THROW
+
 2.11   2007-05-07
         * Add more samples to App synopsis.
         * Add VIEW directive support to Template.
index 42b2c961341dec2b98ce4b669bec5304e691022f..8c0a92e3a323c3358a865632514d76a8a36d1b00 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -1,7 +1,7 @@
 # http://module-build.sourceforge.net/META-spec.html
 #XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX#
 name:         CGI-Ex
-version:      2.11
+version:      2.12
 version_from: lib/CGI/Ex.pm
 installdirs:  site
 requires:
index b6677bfe362c969a4125efdc4db373df00e95769..a5c05aaf03ca7c7dfed3d527e60bf71e8e8857ae 100644 (file)
@@ -24,7 +24,7 @@ use vars qw($VERSION
 use base qw(Exporter);
 
 BEGIN {
-    $VERSION               = '2.11';
+    $VERSION               = '2.12';
     $PREFERRED_CGI_MODULE  ||= 'CGI';
     @EXPORT = ();
     @EXPORT_OK = qw(get_form
index 29483ccc1302ea6074bd824c510ff79861c1907b..70257492df43a96fd12984d011c76c73406c3640 100644 (file)
@@ -10,7 +10,7 @@ use strict;
 use vars qw($VERSION);
 
 BEGIN {
-    $VERSION = '2.11';
+    $VERSION = '2.12';
 
     Time::HiRes->import('time') if eval {require Time::HiRes};
     eval {require Scalar::Util};
index 0c384949746fcc3936c321fc1185069a6997b81c..c159bef5c79de9a159c4bc2a746cdfa53e947c21 100644 (file)
@@ -18,7 +18,7 @@ use MIME::Base64 qw(encode_base64 decode_base64);
 use Digest::MD5 qw(md5_hex);
 use CGI::Ex;
 
-$VERSION = '2.11';
+$VERSION = '2.12';
 
 ###----------------------------------------------------------------###
 
index ac551809d9fd76c339534dcbde0e0b22b6a9c785..174648053177a17a59976c4223175eee19c0f61e 100644 (file)
@@ -29,7 +29,7 @@ use vars qw($VERSION
             );
 @EXPORT_OK = qw(conf_read conf_write in_cache);
 
-$VERSION = '2.11';
+$VERSION = '2.12';
 
 $DEFAULT_EXT = 'conf';
 
index 1145f2e4d2118c535ad6f23ef3f3fc53c98f70e7..9ef4b851015cd90937a6061b22f8583308d661f3 100644 (file)
@@ -23,7 +23,7 @@ use CGI::Ex;
 use CGI::Ex::Dump qw(debug ctrace dex_html);
 
 BEGIN {
-  $VERSION = '2.11';
+  $VERSION = '2.12';
   $SHOW_TRACE = 0      if ! defined $SHOW_TRACE;
   $IGNORE_EVAL = 0     if ! defined $IGNORE_EVAL;
   $EXTENDED_ERRORS = 1 if ! defined $EXTENDED_ERRORS;
index fd6360bea6469d0b78f13eddb270817f3d836bb9..cd4587db058be459e5db01c042ab199c1e632687 100644 (file)
@@ -17,7 +17,7 @@ use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION
 use strict;
 use Exporter;
 
-$VERSION   = '2.11';
+$VERSION   = '2.12';
 @ISA       = qw(Exporter);
 @EXPORT    = qw(dex dex_warn dex_text dex_html ctrace dex_trace);
 @EXPORT_OK = qw(dex dex_warn dex_text dex_html ctrace dex_trace debug);
index 646e21003782c846256d8255af137c845c094201..a43d798434ba8502a703f99902a87d299dc0ed12 100644 (file)
@@ -24,7 +24,7 @@ use vars qw($VERSION
 use base qw(Exporter);
 
 BEGIN {
-    $VERSION   = '2.11';
+    $VERSION   = '2.12';
     @EXPORT    = qw(form_fill);
     @EXPORT_OK = qw(fill form_fill html_escape get_tagval_by_key swap_tagval_by_key);
 };
index 9242ad92246c68c3486c5e8ba0c83136d09a7594..026cabf461fe34256f7d877ade9e247a4ac8e6b2 100644 (file)
@@ -17,7 +17,7 @@ use strict;
 use base qw(Exporter);
 
 BEGIN {
-    $VERSION  = '2.11';
+    $VERSION  = '2.12';
 
     @EXPORT = qw(JSONDump);
     @EXPORT_OK = @EXPORT;
index 37dda33bd88b25f24ce7607b666bc0f03190dbfa..72b56c742d1f7da7fd904a8cfe14d25edf8e3ad2 100644 (file)
@@ -1,8 +1,5 @@
 package CGI::Ex::Template;
 
-#STAT_TTL
-#memory leak in USE
-
 ###----------------------------------------------------------------###
 #  See the perldoc in CGI/Ex/Template.pod
 #  Copyright 2007 - Paul Seamons                                     #
@@ -39,21 +36,20 @@ use vars qw($VERSION
             $WHILE_MAX
             $EXTRA_COMPILE_EXT
             $DEBUG
+            $STAT_TTL
 
             @CONFIG_COMPILETIME
             @CONFIG_RUNTIME
             );
 
 BEGIN {
-    $VERSION = '2.11';
+    $VERSION = '2.12';
 
     $PACKAGE_EXCEPTION   = 'CGI::Ex::Template::Exception';
     $PACKAGE_ITERATOR    = 'CGI::Ex::Template::Iterator';
     $PACKAGE_CONTEXT     = 'CGI::Ex::Template::_Context';
     $PACKAGE_STASH       = 'CGI::Ex::Template::_Stash';
     $PACKAGE_PERL_HANDLE = 'CGI::Ex::Template::EvalPerlHandle';
-    $MAX_EVAL_RECURSE    = 50;
-    $MAX_MACRO_RECURSE   = 50;
 
     $TAGS = {
         asp       => ['<%',     '%>'    ], # ASP
@@ -221,49 +217,46 @@ BEGIN {
     ### setup the operator parsing
     $OPERATORS = [
         # type      precedence symbols              action (undef means play_operator will handle)
-        ['prefix',  99,        ['\\'],              undef                                       ],
-        ['postfix', 98,        ['++'],              undef                                       ],
-        ['postfix', 98,        ['--'],              undef                                       ],
-        ['prefix',  97,        ['++'],              undef                                       ],
-        ['prefix',  97,        ['--'],              undef                                       ],
-        ['right',   96,        ['**', 'pow'],       sub {     $_[0] ** $_[1]                  } ],
-        ['prefix',  93,        ['!'],               sub {   ! $_[0]                           } ],
+        ['prefix',  99,        ['\\'],              undef                       ],
+        ['postfix', 98,        ['++'],              undef                       ],
+        ['postfix', 98,        ['--'],              undef                       ],
+        ['prefix',  97,        ['++'],              undef                       ],
+        ['prefix',  97,        ['--'],              undef                       ],
+        ['right',   96,        ['**', 'pow'],       sub {     $_[0] ** $_[1]  } ],
+        ['prefix',  93,        ['!'],               sub {   ! $_[0]           } ],
         ['prefix',  93,        ['-'],               sub { @_ == 1 ? 0 - $_[0] : $_[0] - $_[1] } ],
-        ['left',    90,        ['*'],               sub {     $_[0] *  $_[1]                  } ],
-        ['left',    90,        ['/'],               sub {     $_[0] /  $_[1]                  } ],
-        ['left',    90,        ['div', 'DIV'],      sub { int($_[0] /  $_[1])                 } ],
-        ['left',    90,        ['%', 'mod', 'MOD'], sub {     $_[0] %  $_[1]                  } ],
-        ['left',    85,        ['+'],               sub {     $_[0] +  $_[1]                  } ],
+        ['left',    90,        ['*'],               sub {     $_[0] *  $_[1]  } ],
+        ['left',    90,        ['/'],               sub {     $_[0] /  $_[1]  } ],
+        ['left',    90,        ['div', 'DIV'],      sub { int($_[0] /  $_[1]) } ],
+        ['left',    90,        ['%', 'mod', 'MOD'], sub {     $_[0] %  $_[1]  } ],
+        ['left',    85,        ['+'],               sub {     $_[0] +  $_[1]  } ],
         ['left',    85,        ['-'],               sub { @_ == 1 ? 0 - $_[0] : $_[0] - $_[1] } ],
-        ['left',    85,        ['~', '_'],          undef                                       ],
-        ['none',    80,        ['<'],               sub {     $_[0] <  $_[1]                  } ],
-        ['none',    80,        ['>'],               sub {     $_[0] >  $_[1]                  } ],
-        ['none',    80,        ['<='],              sub {     $_[0] <= $_[1]                  } ],
-        ['none',    80,        ['>='],              sub {     $_[0] >= $_[1]                  } ],
-        ['none',    80,        ['lt'],              sub {     $_[0] lt $_[1]                  } ],
-        ['none',    80,        ['gt'],              sub {     $_[0] gt $_[1]                  } ],
-        ['none',    80,        ['le'],              sub {     $_[0] le $_[1]                  } ],
-        ['none',    80,        ['ge'],              sub {     $_[0] ge $_[1]                  } ],
-        ['none',    75,        ['==', 'eq'],        sub {     $_[0] eq $_[1]                  } ],
-        ['none',    75,        ['!=', 'ne'],        sub {     $_[0] ne $_[1]                  } ],
-        ['left',    70,        ['&&'],              undef                                       ],
-        ['right',   65,        ['||'],              undef                                       ],
-        ['none',    60,        ['..'],              sub {     $_[0] .. $_[1]                  } ],
-        ['ternary', 55,        ['?', ':'],          undef                                       ],
-        ['assign',  53,        ['+='],              sub {     $_[0] +  $_[1]                  } ],
-        ['assign',  53,        ['-='],              sub {     $_[0] -  $_[1]                  } ],
-        ['assign',  53,        ['*='],              sub {     $_[0] *  $_[1]                  } ],
-        ['assign',  53,        ['/='],              sub {     $_[0] /  $_[1]                  } ],
-        ['assign',  53,        ['%='],              sub {     $_[0] %  $_[1]                  } ],
-        ['assign',  53,        ['**='],             sub {     $_[0] ** $_[1]                  } ],
-        ['assign',  53,        ['~=', '_='],        sub {     $_[0] .  $_[1]                  } ],
-        ['assign',  52,        ['='],               undef                                       ],
-        ['prefix',  50,        ['not', 'NOT'],      sub {   ! $_[0]                           } ],
-        ['left',    45,        ['and', 'AND'],      undef                                       ],
-        ['right',   40,        ['or', 'OR'],        undef                                       ],
-#        ['',         0,        ['{}'],              undef                                       ],
-#        ['',         0,        ['[]'],              undef                                       ],
-#        ['',         0,        ['qr'],              undef                                       ],
+        ['left',    85,        ['~', '_'],          undef                       ],
+        ['none',    80,        ['<'],               sub {     $_[0] <  $_[1]  } ],
+        ['none',    80,        ['>'],               sub {     $_[0] >  $_[1]  } ],
+        ['none',    80,        ['<='],              sub {     $_[0] <= $_[1]  } ],
+        ['none',    80,        ['>='],              sub {     $_[0] >= $_[1]  } ],
+        ['none',    80,        ['lt'],              sub {     $_[0] lt $_[1]  } ],
+        ['none',    80,        ['gt'],              sub {     $_[0] gt $_[1]  } ],
+        ['none',    80,        ['le'],              sub {     $_[0] le $_[1]  } ],
+        ['none',    80,        ['ge'],              sub {     $_[0] ge $_[1]  } ],
+        ['none',    75,        ['==', 'eq'],        sub {     $_[0] eq $_[1]  } ],
+        ['none',    75,        ['!=', 'ne'],        sub {     $_[0] ne $_[1]  } ],
+        ['left',    70,        ['&&'],              undef                       ],
+        ['right',   65,        ['||'],              undef                       ],
+        ['none',    60,        ['..'],              sub {     $_[0] .. $_[1]  } ],
+        ['ternary', 55,        ['?', ':'],          undef                       ],
+        ['assign',  53,        ['+='],              sub {     $_[0] +  $_[1]  } ],
+        ['assign',  53,        ['-='],              sub {     $_[0] -  $_[1]  } ],
+        ['assign',  53,        ['*='],              sub {     $_[0] *  $_[1]  } ],
+        ['assign',  53,        ['/='],              sub {     $_[0] /  $_[1]  } ],
+        ['assign',  53,        ['%='],              sub {     $_[0] %  $_[1]  } ],
+        ['assign',  53,        ['**='],             sub {     $_[0] ** $_[1]  } ],
+        ['assign',  53,        ['~=', '_='],        sub {     $_[0] .  $_[1]  } ],
+        ['assign',  52,        ['='],               undef                       ],
+        ['prefix',  50,        ['not', 'NOT'],      sub {   ! $_[0]           } ],
+        ['left',    45,        ['and', 'AND'],      undef                       ],
+        ['right',   40,        ['or', 'OR'],        undef                       ],
     ];
     $OP          = {map {my $ref = $_; map {$_ => $ref}      @{$ref->[2]}} grep {$_->[0] ne 'prefix' } @$OPERATORS}; # all non-prefix
     $OP_PREFIX   = {map {my $ref = $_; map {$_ => $ref}      @{$ref->[2]}} grep {$_->[0] eq 'prefix' } @$OPERATORS};
@@ -295,7 +288,10 @@ BEGIN {
     $QR_PRIVATE   = qr/^[_.]/;
 
     $WHILE_MAX    = 1000;
-    $EXTRA_COMPILE_EXT = '.sto2';
+    $EXTRA_COMPILE_EXT = '.sto';
+    $MAX_EVAL_RECURSE  = 50;
+    $MAX_MACRO_RECURSE = 50;
+    $STAT_TTL          ||= 1;
 
     @CONFIG_COMPILETIME = qw(ANYCASE INTERPOLATE PRE_CHOMP POST_CHOMP V1DOLLAR V2PIPE);
     @CONFIG_RUNTIME     = qw(DUMP);
@@ -387,6 +383,7 @@ sub load_parsed_tree {
     return if ! defined $file;
 
     my $doc = {name => $file};
+    my $ref = $self->{'_documents'}->{$file};
 
     ### looks like a string reference
     if (ref $file) {
@@ -395,12 +392,11 @@ sub load_parsed_tree {
         $doc->{'_is_str_ref'} = 1;
 
     ### looks like a previously cached-in-memory document
-    } elsif ($self->{'_documents'}->{$file}
-             && (   ($self->{'_documents'}->{$file}->{'_cache_time'} == time) # don't stat more than once a second
-                 || ($self->{'_documents'}->{$file}->{'modtime'}
-                     == (stat $self->{'_documents'}->{$file}->{'_filename'})[9]))) {
+    } elsif ($ref
+             && (   time - $ref->{'cache_time'} < ($self->{'STAT_TTL'} || $STAT_TTL) # don't stat more than once a second
+                 || $ref->{'modtime'} == (stat $ref->{'_filename'})[9]               # otherwise see if the file was modified
+                    )) {
         $doc = $self->{'_documents'}->{$file};
-        $doc->{'_cache_time'} = time;
         return $doc;
 
     ### looks like a block name of some sort
@@ -420,6 +416,13 @@ sub load_parsed_tree {
         $doc->{'_tree'} = $block->{'_tree'} || $self->throw('block', "Invalid block definition (missing tree)");
         return $doc;
 
+    ### handle cached not_founds
+    } elsif ($self->{'_not_found'}->{$file}
+             && ((time - $self->{'_not_found'}->{$file}->{'cache_time'}
+                  < ($self->{'NEGATIVE_STAT_TTL'} || $self->{'STAT_TTL'} || $STAT_TTL))  # negative cache for a second
+                 || do { delete $self->{'_not_found'}->{$file}; 0 } # clear cache on failure
+                 )) {
+        die $self->{'_not_found'}->{$file}->{'exception'};
 
     ### go and look on the file system
     } else {
@@ -446,10 +449,19 @@ sub load_parsed_tree {
                         last;
                     }
                 }
-                die $err if ! $doc->{'_tree'};
+                $err = '' if ! $doc->{'_tree'};
             } elsif ($self->{'DEFAULT'}) {
-                $doc->{'_filename'} = eval { $self->include_filename($self->{'DEFAULT'}) } || die $err;
-            } else {
+                $err = '' if ($doc->{'_filename'} = eval { $self->include_filename($self->{'DEFAULT'}) });
+            }
+            if ($err) {
+                ### cache the negative error
+                if (! defined($self->{'NEGATIVE_STAT_TTL'}) || $self->{'NEGATIVE_STAT_TTL'}) {
+                    $err = $self->exception('undef', $err) if ref($err) !~ /Template::Exception$/;
+                    $self->{'_not_found'}->{$file} = {
+                        cache_time => time,
+                        exception  => $self->exception($err->type, $err->info." (cached)"),
+                    };
+                }
                 die $err;
             }
         }
@@ -497,14 +509,14 @@ sub load_parsed_tree {
     ### cache parsed_tree in memory unless asked not to do so
     if (! $doc->{'_is_str_ref'} && (! defined($self->{'CACHE_SIZE'}) || $self->{'CACHE_SIZE'})) {
         $self->{'_documents'}->{$file} ||= $doc;
-        $doc->{'_cache_time'} = time;
+        $doc->{'cache_time'} = time;
 
         ### allow for config option to keep the cache size down
         if ($self->{'CACHE_SIZE'}) {
             my $all = $self->{'_documents'};
             if (scalar(keys %$all) > $self->{'CACHE_SIZE'}) {
                 my $n = 0;
-                foreach my $file (sort {$all->{$b}->{'_cache_time'} <=> $all->{$a}->{'_cache_time'}} keys %$all) {
+                foreach my $file (sort {$all->{$b}->{'cache_time'} <=> $all->{$a}->{'cache_time'}} keys %$all) {
                     delete($all->{$file}) if ++$n > $self->{'CACHE_SIZE'};
                 }
             }
@@ -1445,6 +1457,9 @@ sub play_expr {
 
     ### determine the top level of this particular variable access
     my $ref;
+    use CGI::Ex::Dump qw(debug dex_trace);
+    debug dex_trace
+        if ref $var ne 'ARRAY';
     my $name = $var->[$i++];
     my $args = $var->[$i++];
     warn "play_expr: begin \"$name\"\n" if trace;
@@ -2610,10 +2625,10 @@ sub play_THROW {
 
     $name = $self->play_expr($name);
 
-    my $named = shift @$args;
-    push @$args, $named if ! $self->is_empty_named_args($named); # add named args back on at end - if there are some
+    my ($named, @args) = @$args;
+    push @args, $named if ! $self->is_empty_named_args($named); # add named args back on at end - if there are some
 
-    my @args = $args ? map { $self->play_expr($_) } @$args : ();
+    @args = map { $self->play_expr($_) } @args;
     $self->throw($name, \@args, $node);
 }
 
@@ -2726,8 +2741,8 @@ sub play_USE {
     my @var = map {($_, 0, '.')} split /(?:\.|::)/, $var;
     pop @var; # remove the trailing '.'
 
-    my $named = shift @$args;
-    push @$args, $named if ! $self->is_empty_named_args($named); # add named args back on at end - if there are some
+    my ($named, @args) = @$args;
+    push @args, $named if ! $self->is_empty_named_args($named); # add named args back on at end - if there are some
 
     ### look for a plugin_base
     my $BASE = $self->{'PLUGIN_BASE'} || 'Template::Plugin'; # I'm not maintaining plugins - leave that to TT
@@ -2744,10 +2759,9 @@ sub play_USE {
         if ($self->{'PLUGIN_FACTORY'}->{$module} || eval {require $require}) {
             my $shape   = $package->load;
             my $context = $self->context;
-            my @args    = $args ? map { $self->play_expr($_) } @$args : ();
-            $obj = $shape->new($context, @args);
+            $obj = $shape->new($context, map { $self->play_expr($_) } @args);
         } elsif (lc($module) eq 'iterator') { # use our iterator if none found (TT's works just fine)
-            $obj = $PACKAGE_ITERATOR->new($args ? $self->play_expr($args->[0]) : []);
+            $obj = $PACKAGE_ITERATOR->new($args[0]);
         } elsif (my @packages = grep {lc($package) eq lc($_)} @{ $self->list_plugins({base => $base}) }) {
             foreach my $package (@packages) {
                 my $require = "$package.pm";
@@ -2755,15 +2769,13 @@ sub play_USE {
                 eval {require $require} || next;
                 my $shape   = $package->load;
                 my $context = $self->context;
-                my @args    = $args ? map { $self->play_expr($_) } @$args : ();
-                $obj = $shape->new($context, @args);
+                $obj = $shape->new($context, map { $self->play_expr($_) } @args);
             }
         } elsif ($self->{'LOAD_PERL'}) {
             my $require = "$module.pm";
             $require =~ s|::|/|g;
             if (eval {require $require}) {
-                my @args = $args ? map { $self->play_expr($_) } @$args : ();
-                $obj = $module->new(@args);
+                $obj = $module->new(map { $self->play_expr($_) } @args);
             }
         }
     }
@@ -2788,7 +2800,6 @@ sub parse_VIEW {
 
     return $ref;
 }
-#sub parse_VIEW { $DIRECTIVES->{'PROCESS'}->[0]->(@_) }
 
 sub play_VIEW {
     my ($self, $ref, $node, $out_ref) = @_;
@@ -3012,44 +3023,80 @@ sub process {
         my $copy = {%$var2, %$var1, %$swap};
 
         local $self->{'BLOCKS'} = $blocks = {%$blocks}; # localize blocks - but save a copy to possibly restore
+        local $self->{'_template'};
 
         delete $self->{'_debug_off'};
         delete $self->{'_debug_format'};
 
         ### handle pre process items that go before every document
+        my $pre = '';
         if ($self->{'PRE_PROCESS'}) {
+            $self->_load_template_meta($content);
             foreach my $name (@{ $self->split_paths($self->{'PRE_PROCESS'}) }) {
-                my $out = '';
-                $self->_process($name, $copy, \$out);
-                $output = $out . $output;
+                $self->_process($name, $copy, \$pre);
             }
         }
 
-        ### handle the process config - which loads a template in place of the real one
-        if (exists $self->{'PROCESS'}) {
-            ### load the meta data for the top document
-            my $doc  = $self->load_parsed_tree($content) || {};
-            my $meta = ($doc->{'_tree'} && ref($doc->{'_tree'}->[0]) && $doc->{'_tree'}->[0]->[0] eq 'META')
-                ? $doc->{'_tree'}->[0]->[3] : {};
+        ### process the central file now - catching errors to allow for the ERROR config
+        eval {
+            ### handle the PROCESS config - which loads another template in place of the real one
+            if (exists $self->{'PROCESS'}) {
+                $self->_load_template_meta($content);
+                foreach my $name (@{ $self->split_paths($self->{'PROCESS'}) }) {
+                    next if ! length $name;
+                    $self->_process($name, $copy, \$output);
+                }
 
-            local $self->{'_template'} = $doc;
-            @{ $doc }{keys %$meta} = values %$meta;
+                ### handle "normal" content
+            } else {
+                local $self->{'_start_top_level'} = 1;
+                $self->_process($content, $copy, \$output);
+            }
+        };
 
-            ### process any other templates
-            foreach my $name (@{ $self->split_paths($self->{'PROCESS'}) }) {
-                next if ! length $name;
-                $self->_process($name, $copy, \$output);
+        ### catch errors with ERROR config
+        if (my $err = $@) {
+            $err = $self->exception('undef', $err) if ref($err) !~ /Template::Exception$/;
+            die $err if $err->type =~ /stop|return/;
+            my $catch = $self->{'ERRORS'} || $self->{'ERROR'} || die $err;
+            $catch = {default => $catch} if ! ref $catch;
+            my $type = $err->type;
+            my $last_found;
+            my $file;
+            foreach my $name (keys %$catch) {
+                my $_name = (! defined $name || lc($name) eq 'default') ? '' : $name;
+                if ($type =~ / ^ \Q$_name\E \b /x
+                    && (! defined($last_found) || length($last_found) < length($_name))) { # more specific wins
+                    $last_found = $_name;
+                    $file       = $catch->{$name};
+                }
             }
 
-        ### handle "normal" content
-        } else {
-            local $self->{'_start_top_level'} = 1;
-            $self->_process($content, $copy, \$output);
+            ### found error handler - try it out
+            if (defined $file) {
+                $output = '';
+                local $copy->{'error'} = local $copy->{'e'} = $err;
+                $self->_process($file, $copy, \$output);
+            }
+        }
+
+        ### handle wrapper directives
+        if (exists $self->{'WRAPPER'}) {
+            $self->_load_template_meta($content);
+            foreach my $name (reverse @{ $self->split_paths($self->{'WRAPPER'}) }) {
+                next if ! length $name;
+                local $copy->{'content'} = $output;
+                my $out = '';
+                $self->_process($name, $copy, \$out);
+                $output = $out;
+            }
         }
 
+        $output = $pre . $output if length $pre;
 
         ### handle post process items that go after every document
         if ($self->{'POST_PROCESS'}) {
+            $self->_load_template_meta($content);
             foreach my $name (@{ $self->split_paths($self->{'POST_PROCESS'}) }) {
                 $self->_process($name, $copy, \$output);
             }
@@ -3132,6 +3179,24 @@ sub DEBUG {
     print STDERR "DEBUG: ", @_;
 }
 
+sub _load_template_meta {
+    my $self = shift;
+    return if $self->{'_template'}; # only do once as need
+
+    ### load the meta data for the top document
+    ### this is needed by some of the custom handlers such as PRE_PROCESS and POST_PROCESS
+    my $content = shift;
+    my $doc     = $self->{'_template'} = $self->load_parsed_tree($content) || {};
+    my $meta    = ($doc->{'_tree'} && ref($doc->{'_tree'}->[0]) && $doc->{'_tree'}->[0]->[0] eq 'META')
+        ? $doc->{'_tree'}->[0]->[3] : {};
+
+    $self->{'_template'} = $doc;
+    @{ $doc }{keys %$meta} = values %$meta;
+
+    return;
+}
+
+
 ###----------------------------------------------------------------###
 
 sub exception {
index f93126132525f6d91f90902d6b35e0580284b2ae..206dcba50de481df56efca3a6b77f2b064406ca2 100644 (file)
@@ -15,9 +15,14 @@ CGI::Ex::Template - Fast and lightweight TT2/3 template engine
         hash => {a => 'b'},
     };
 
+    # print to STDOUT
     $t->process('my/template.tt', $swap)
         || die $t->error;
 
+    # process into a variable
+    my $out = '';
+    $t->process('my/template.tt', $swap, \$out);
+
     ### CET uses the same syntax and configuration as Template::Toolkit
 
 =head1 DESCRIPTION
@@ -180,9 +185,7 @@ to Template::Stash::define_vmethod.
 
 =head1 TODO
 
-    Add WRAPPER configuration item (the WRAPPER directive is supported).
-
-    Add ERROR config item
+    Add HTML::Template support
 
 =head1 HOW IS CGI::Ex::Template DIFFERENT
 
@@ -403,6 +406,14 @@ Used for Data::Dumpering the passed variable or expression.
         PRE_CHOMP => '-'
    %]
 
+=item Configuration options can use lowercase names instead
+of the all uppercase names that TT2 uses.
+
+    my $t = CGI::Ex::Template->new({
+        anycase     => 1,
+        interpolate => 1,
+    });
+
 =item CET does not generate Perl code.
 
 It generates an "opcode" tree.  The opcode tree is an arrayref
@@ -1623,6 +1634,13 @@ Arguments may also be passed to the template:
 Filenames must be relative to INCLUDE_PATH unless the ABSOLUTE
 or RELATIVE configuration items are set.
 
+Multiple filenames can be passed by separating them with a plus, a space,
+or commas (TT2 doesn't support the comma).  Any supplied arguments will
+be used on all templates.
+
+    [% INCLUDE "path/to/template.html",
+               "path/to/template2.html" a = "An arg" b = "Another arg" %]
+
 =item C<INSERT>
 
 Insert the contents of a file without template parsing.
@@ -1630,6 +1648,12 @@ Insert the contents of a file without template parsing.
 Filenames must be relative to INCLUDE_PATH unless the ABSOLUTE
 or RELATIVE configuration items are set.
 
+Multiple filenames can be passed by separating them with a plus, a space,
+or commas (TT2 doesn't support the comma).
+
+    [% INSERT "path/to/template.html",
+              "path/to/template2.html" %]
+
 =item C<LAST>
 
 Used to exit out of a WHILE or FOREACH loop.
@@ -1724,6 +1748,13 @@ Arguments may also be passed to the template:
 Filenames must be relative to INCLUDE_PATH unless the ABSOLUTE
 or RELATIVE configuration items are set.
 
+Multiple filenames can be passed by separating them with a plus, a space,
+or commas (TT2 doesn't support the comma).  Any supplied arguments will
+be used on all templates.
+
+    [% PROCESS "path/to/template.html",
+               "path/to/template2.html" a = "An arg" b = "Another arg" %]
+
 =item C<RAWPERL>
 
 Only available if the EVAL_PERL configuration item is true (default is false).
@@ -2037,8 +2068,8 @@ Block directive.  Processes contents of its block and then passes them
 in the [% content %] variable to the block or filename listed in the
 WRAPPER tag.
 
-    [% WRAPPER foo %]
-    My content to be processed.[% a = 2 %]
+    [% WRAPPER foo b = 23 %]
+    My content to be processed ([% b %]).[% a = 2 %]
     [% END %]
 
     [% BLOCK foo %]
@@ -2050,10 +2081,10 @@ WRAPPER tag.
 This would print.
 
     A header (2).
-    My content to be processed.
+    My content to be processed (23).
     A footer (2).
 
-The WRAPPER directive may also be used as a post directive.
+The WRAPPER directive may also be used as a post operative directive.
 
     [% BLOCK baz %]([% content %])[% END -%]
     [% "foobar" WRAPPER baz %]
@@ -2062,6 +2093,17 @@ Would print
 
     (foobar)');
 
+Multiple filenames can be passed by separating them with a plus, a space,
+or commas (TT2 doesn't support the comma).  Any supplied arguments will
+be used on all templates.  Wrappers are processed in reverse order, so
+that the first wrapper listed will surround each subsequent wrapper listed.
+Variables from inner wrappers are available to the next wrapper that
+surrounds it.
+
+    [% WRAPPER "path/to/outer.html",
+               "path/to/inner.html" a = "An arg" b = "Another arg" %]
+
+
 =back
 
 
@@ -2585,6 +2627,37 @@ Any of the Data::Dumper configuration items may be passed.
 
 Set a string to use as the closing delimiter for TT.  Default is "%]".
 
+=item ERROR
+
+Used as a fall back when the processing of a template fails.  May either
+be a single filename that will be used in all cases, or may be a hashref
+of options where the keynames represent error types that will be handled
+by the filename in their value.  A key named default will be used if no
+other matching keyname can be found.  The selection process is similar
+to that of the TRY/CATCH/THROW directives (see those directives for more
+information).
+
+    my $t = CGI::Ex::Template->new({
+        ERROR => 'general/catch_all_errors.html',
+    });
+
+    my $t = CGI::Ex::Template->new({
+        ERROR => {
+            default   => 'general/catch_all_errors.html',
+            foo       => 'catch_all_general_foo_errors.html',
+            'foo.bar' => 'catch_foo_bar_errors.html',
+        },
+    });
+
+Note that the ERROR handler will only be used for errors during the
+processing of the main document.  It will not catch errors that
+occur in templates found in the PRE_PROCESS, POST_PROCESS, and WRAPPER
+configuration items.
+
+=item ERRORS
+
+Same as the ERROR configuration item.  Both may be used interchangably.
+
 =item EVAL_PERL
 
 Boolean.  Default false.  If set to a true value, PERL and RAWPERL blocks
@@ -2681,6 +2754,16 @@ Is the same as
 
 Any number of hashes can be added to the NAMESPACE hash.
 
+=item NEGATIVE_STAT_TTL (Not in TT)
+
+Defaults to STAT_TTL which defaults to $STAT_TTL which defaults to 1.
+
+Similar to STAT_TTL - but represents the time-to-live
+seconds until a document that was not found is checked again against
+the system for modifications.  Setting this number higher will allow for
+fewer file system accesses.  Setting it to a negative number will allow
+for the file system to be checked every hit.
+
 =item OUTPUT
 
 Alternate way of passing in the output location for processed templates.
@@ -2761,6 +2844,14 @@ that are relative to the currently running process.
 
 Set a string to use as the opening delimiter for TT.  Default is "[%".
 
+=item STAT_TTL
+
+Defaults to $STAT_TTL which defaults to 1.  Represents time-to-live
+seconds until a cached in memory document is compared to the file
+system for modifications.  Setting this number higher will allow for
+fewer file system accesses.  Setting it to a negative number will allow
+for the file system to be checked every hit.
+
 =item TAG_STYLE
 
 Allow for setting the type of tag delimiters to use for parsing the TT.
@@ -2842,21 +2933,30 @@ A hashref of variables to initialize the template stash with.  These
 variables are available for use in any of the executed templates.
 See the section on VARIABLES for the types of information that can be passed in.
 
-=back
+=item WRAPPER
 
+Operates similar to the WRAPPER directive.  The option can be given a
+single filename, or an arrayref of filenames that will be used to wrap
+the processed content.  If an arrayref is passed the filenames are
+processed in reverse order, so that the first filename specified will
+end up being on the outside (surrounding all other wrappers).
 
+   my $t = CGI::Ex::Template->new(
+       WRAPPER => ['my/wrappers/outer.html', 'my/wrappers/inner.html'],
+   );
 
-=head1 UNSUPPORTED TT CONFIGURATION
+Content generated by the PRE_PROCESS and POST_PROCESS will come before
+and after (respectively) the content generated by the WRAPPER
+configuration item.
 
-=over 4
+See the WRAPPER direcive for more examples of how wrappers are construted.
 
-=item WRAPPER
+=back
 
-This will be supported - just not done yet.
 
-=item ERROR
+=head1 UNSUPPORTED TT CONFIGURATION
 
-This will be supported - just not done yet.
+=over 4
 
 =item LOAD_TEMPLATES
 
@@ -2915,7 +3015,9 @@ filters, and perl blocks.
 
 CGI::Ex::Template has its own built in parser.  The closest similarity is
 the parse_tree method.  The output of parse_tree is an optree that is
-later run by execute_tree.
+later run by execute_tree.  CET provides a backend to the Template::Parser::CET
+module which can be used to replace the default parser when using
+the standard Template::Toolkit library.
 
 =item GRAMMAR
 
index 35f717600b3036f9fad32c09393c0c21a7965b89..89f56476d776c49616c529232ca4899bc07bd6f1 100644 (file)
@@ -22,7 +22,7 @@ use vars qw($VERSION
             @UNSUPPORTED_BROWSERS
             );
 
-$VERSION = '2.11';
+$VERSION = '2.12';
 
 $DEFAULT_EXT   = 'val';
 $QR_EXTRA      = qr/^(\w+_error|as_(array|string|hash)_\w+|no_\w+)/;
index 6b03cdf39e08ff60d39214a47e2ec3d68ea3fee8..9c055667568bd9c1dd065ad25d81dfb13ed6010e 100644 (file)
@@ -15,27 +15,58 @@ my $txt  = "[% one %][% two %][% three %][% hash.keys.join %] [% code(one).lengt
 ###----------------------------------------------------------------###
 
 my $module;
+my $name;
 if (! fork) {
     $module = 'CGI::Ex::Template';
-    $0 = "perl $module";
+} elsif (! fork) {
+    $module = 'CGI::Ex::Template::XS';
+} elsif (! fork) {
+    $module = 'Template';
+} elsif (! fork) {
+    $module = 'Template';
+    $name   = 'Template Stash::XS';
+    require Template::Stash::XS;
+} elsif (! fork) {
+    $module = 'HTML::Template';
+} elsif (! fork) {
+    $module = 'HTML::Template::Expr';
 } elsif (! fork) {
     $module = 'Template';
-    $0 = "perl $module";
+    $name   = 'Template::Parser::CET';
+    require Template::Parser::CET;
+    Template::Parser::CET->activate;
 }
 
 if ($module) {
+    $name ||= $module;
+    $0 = "$0 - $name";
+
     my $pm = "$module.pm";
     $pm =~ s|::|/|g;
     require $pm;
 
-    my $t = $module->new(ABSOLUTE => 1);
-    my $out = '';
-    $t->process(\$txt, $swap, \$out);
-    print $out;
-}
+    if ($module =~ /HTML::Template/) {
+        my $t = eval { $module->new };
 
-sleep 15; # go and check the 'ps fauwx|grep perl'
+    } else {
+
+        my $t = $module->new(ABSOLUTE => 1);
+        my $out = '';
+        $t->process(\$txt, $swap, \$out);
+        print "$name $out";
+        for (1..30) { my $out; $t->process(\$txt, $swap, \$out); };
+    }
+
+#    print "$name $_\n" foreach sort keys %INC;
+    print "$name times: (@{[times]})\n";
+    sleep 15;
+    exit;
+}
 
+sleep 2;
+print grep {/\Q$0\E/} `ps fauwx`;
+#sleep 15; # go and check the 'ps fauwx|grep perl'
+exit;
 
 ###----------------------------------------------------------------###
 
index 4054746ae6572b13435627b573a40253133a6a25..a50cab6f9c57e9575f4ab82caa41ec923621c133 100644 (file)
@@ -9,12 +9,12 @@
 use vars qw($module $is_tt);
 BEGIN {
     $module = 'CGI::Ex::Template';
-    #$module = 'Template';
+#    $module = 'Template';
     $is_tt = $module eq 'Template';
 };
 
 use strict;
-use Test::More tests => 25 - ($is_tt ? 6 : 0);
+use Test::More tests => (! $is_tt) ? 93 : 83;
 use Data::Dumper qw(Dumper);
 use constant test_taint => 0 && eval { require Taint::Runtime };
 
@@ -59,14 +59,14 @@ sub process_ok { # process the value and say if it was ok
 my $foo_template = "$test_dir/foo.tt";
 END { unlink $foo_template };
 open(my $fh, ">$foo_template") || die "Couldn't open $foo_template: $!";
-print $fh "([% INCLUDE bar.tt %])";
+print $fh "([% template.foo %][% INCLUDE bar.tt %])";
 close $fh;
 
 ###
 my $bar_template = "$test_dir/bar.tt";
 END { unlink $bar_template };
 open($fh, ">$bar_template") || die "Couldn't open $bar_template: $!";
-print $fh "BAR";
+print $fh "[% blue %]BAR";
 close $fh;
 
 my $baz_template = "$test_dir/baz.tt";
@@ -79,22 +79,63 @@ close $fh;
 my $wrap_template = "$test_dir/wrap.tt";
 END { unlink $wrap_template };
 open($fh, ">$wrap_template") || die "Couldn't open $wrap_template: $!";
-print $fh "Hi[% content %]there";
+print $fh "Hi[% baz; template.foo; baz = 'wrap' %][% content %]there";
 close $fh;
 
+###
+my $meta_template = "$test_dir/meta.tt";
+END { unlink $meta_template };
+open($fh, ">$meta_template") || die "Couldn't open $meta_template: $!";
+print $fh "[% META bar='meta.tt' %]Metafoo([% component.foo %]) Metabar([% component.bar %])";
+close $fh;
+
+###
+my $catch_template = "$test_dir/catch.tt";
+END { unlink $catch_template };
+open($fh, ">$catch_template") || die "Couldn't open $catch_template: $!";
+print $fh "Error ([% error.type %]) - ([% error.info %])";
+close $fh;
+
+###
+my $catch2_template = "$test_dir/catch2.tt";
+END { unlink $catch2_template };
+open($fh, ">$catch2_template") || die "Couldn't open $catch2_template: $!";
+print $fh "Error2 ([% error.type %]) - ([% error.info %])";
+close $fh;
+
+###
+my $die_template = "$test_dir/die.tt";
+END { unlink $die_template };
+open($fh, ">$die_template") || die "Couldn't open $die_template: $!";
+print $fh "[% THROW bing 'blang' %])";
+close $fh;
+
+###
+my $config_template = "$test_dir/config.tt";
+END { unlink $config_template };
+open($fh, ">$config_template") || die "Couldn't open $config_template: $!";
+print $fh "[% CONFIG DUMP => {html => 1} %][% DUMP foo %]";
+close $fh;
+
+
 ###----------------------------------------------------------------###
-### INSERT
+print "### INSERT ###########################################################\n";
 
-process_ok("([% INSERT bar.tt %])" => '(BAR)');
-process_ok("([% SET file = 'bar.tt' %][% INSERT \$file %])" => '(BAR)');
-process_ok("([% SET file = 'bar.tt' %][% INSERT \${file} %])" => '(BAR)') if ! $is_tt;
-process_ok("([% SET file = 'bar.tt' %][% INSERT \"\$file\" %])" => '(BAR)');
-process_ok("([% SET file = 'bar' %][% INSERT \"\$file.tt\" %])" => '(BAR)') if ! $is_tt;
+process_ok("([% INSERT bar.tt %])" => '([% blue %]BAR)');
+process_ok("([% SET file = 'bar.tt' %][% INSERT \$file %])"     => '([% blue %]BAR)');
+process_ok("([% SET file = 'bar.tt' %][% INSERT \${file} %])"   => '([% blue %]BAR)') if ! $is_tt;
+process_ok("([% SET file = 'bar.tt' %][% INSERT \"\$file\" %])" => '([% blue %]BAR)');
+process_ok("([% SET file = 'bar' %][% INSERT \"\$file.tt\" %])" => '([% blue %]BAR)') if ! $is_tt;
 
 ###----------------------------------------------------------------###
-### INCLUDE
+print "### INCLUDE ##########################################################\n";
 
 process_ok("([% INCLUDE bar.tt %])" => '(BAR)');
+process_ok("[% PROCESS foo.tt %]" => '(BAR)');
+process_ok("[% PROCESS meta.tt %]" => 'Metafoo() Metabar(meta.tt)');
+process_ok("[% META foo = 'string'; PROCESS meta.tt %]" => 'Metafoo() Metabar(meta.tt)');
+process_ok("[% PROCESS meta.tt %][% template.bar %]" => 'Metafoo() Metabar(meta.tt)');
+process_ok("[% META foo = 'meta'; PROCESS foo.tt %]" => '(metaBAR)');
 process_ok("([% SET file = 'bar.tt' %][% INCLUDE \$file %])" => '(BAR)');
 process_ok("([% SET file = 'bar.tt' %][% INCLUDE \${file} %])" => '(BAR)') if ! $is_tt;
 process_ok("([% SET file = 'bar.tt' %][% INCLUDE \"\$file\" %])" => '(BAR)');
@@ -105,9 +146,14 @@ process_ok("([% INCLUDE baz.tt %])[% baz %]" => '(42)');
 process_ok("[% SET baz = 21 %]([% INCLUDE baz.tt %])[% baz %]" => '(42)21');
 
 ###----------------------------------------------------------------###
-### PROCESS
+print "### PROCESS ##########################################################\n";
 
 process_ok("([% PROCESS bar.tt %])" => '(BAR)');
+process_ok("[% PROCESS foo.tt %]" => '(BAR)');
+process_ok("[% PROCESS meta.tt %]" => 'Metafoo() Metabar(meta.tt)');
+process_ok("[% META foo = 'string'; PROCESS meta.tt %]" => 'Metafoo() Metabar(meta.tt)');
+process_ok("[% PROCESS meta.tt %][% template.bar %]" => 'Metafoo() Metabar(meta.tt)');
+process_ok("[% META foo = 'meta'; PROCESS foo.tt %]" => '(metaBAR)');
 process_ok("([% SET file = 'bar.tt' %][% PROCESS \$file %])" => '(BAR)');
 process_ok("([% SET file = 'bar.tt' %][% PROCESS \${file} %])" => '(BAR)') if ! $is_tt;
 process_ok("([% SET file = 'bar.tt' %][% PROCESS \"\$file\" %])" => '(BAR)');
@@ -118,7 +164,105 @@ process_ok("([% PROCESS baz.tt %])[% baz %]" => '(42)42');
 process_ok("[% SET baz = 21 %]([% PROCESS baz.tt %])[% baz %]" => '(42)42');
 
 ###----------------------------------------------------------------###
-### WRAPPER
+print "### WRAPPER ##########################################################\n";
 
 process_ok("([% WRAPPER wrap.tt %])" => '');
 process_ok("([% WRAPPER wrap.tt %] one [% END %])" => '(Hi one there)');
+process_ok("([% WRAPPER wrap.tt %] ([% baz %]) [% END %])" => '(Hi () there)');
+process_ok("([% WRAPPER wrap.tt %] one [% END %])" => '(HiBAZ one there)', {baz => 'BAZ'});
+process_ok("([% WRAPPER wrap.tt %] ([% baz; baz='-local' %]) [% END %][% baz %])" => '(Hi-local () there-local)');
+process_ok("([% WRAPPER wrap.tt %][% META foo='BLAM' %] [% END %])" => '(HiBLAM there)');
+
+###----------------------------------------------------------------###
+print "### CONFIG PRE_PROCESS ###############################################\n";
+
+process_ok("Foo" => "BARFoo",      {tt_config => [PRE_PROCESS => 'bar.tt']});
+process_ok("Foo" => "BARFoo",      {tt_config => [PRE_PROCESS => ['bar.tt']]});
+process_ok("Foo" => "(BAR)BARFoo", {tt_config => [PRE_PROCESS => ['foo.tt', 'bar.tt']]});
+process_ok("Foo" => "BlueBARFoo",  {tt_config => [PRE_PROCESS => 'bar.tt'], blue => 'Blue'});
+process_ok("Foo[% blue='Blue' %]" => "BARFoo", {tt_config => [PRE_PROCESS => 'bar.tt']});
+process_ok("Foo[% META foo='meta' %]" => "(metaBAR)Foo", {tt_config => [PRE_PROCESS => 'foo.tt']});
+process_ok("([% WRAPPER wrap.tt %] one [% END %])" => 'BAR(Hi one there)', {tt_config => [PRE_PROCESS => 'bar.tt']});
+
+###----------------------------------------------------------------###
+print "### CONFIG POST_PROCESS ##############################################\n";
+
+process_ok("Foo" => "FooBAR",      {tt_config => [POST_PROCESS => 'bar.tt']});
+process_ok("Foo" => "FooBAR",      {tt_config => [POST_PROCESS => ['bar.tt']]});
+process_ok("Foo" => "Foo(BAR)BAR", {tt_config => [POST_PROCESS => ['foo.tt', 'bar.tt']]});
+process_ok("Foo" => "FooBlueBAR",  {tt_config => [POST_PROCESS => 'bar.tt'], blue => 'Blue'});
+process_ok("Foo[% blue='Blue' %]" => "FooBlueBAR", {tt_config => [POST_PROCESS => 'bar.tt']});
+process_ok("Foo[% META foo='meta' %]" => "Foo(metaBAR)", {tt_config => [POST_PROCESS => 'foo.tt']});
+process_ok("([% WRAPPER wrap.tt %] one [% END %])" => '(Hi one there)BAR', {tt_config => [POST_PROCESS => 'bar.tt']});
+
+###----------------------------------------------------------------###
+print "### CONFIG PROCESS ###################################################\n";
+
+process_ok("Foo" => "BAR",      {tt_config => [PROCESS => 'bar.tt']});
+process_ok("Foo" => "BAR",      {tt_config => [PROCESS => ['bar.tt']]});
+process_ok("Foo" => "(BAR)BAR", {tt_config => [PROCESS => ['foo.tt', 'bar.tt']]});
+process_ok("Foo" => "BlueBAR",  {tt_config => [PROCESS => 'bar.tt'], blue => 'Blue'});
+process_ok("Foo[% META foo='meta' %]" => "(metaBAR)", {tt_config => [PROCESS => 'foo.tt']});
+process_ok("Foo[% META foo='meta' %]" => "BAR(metaBAR)", {tt_config => [PRE_PROCESS => 'bar.tt', PROCESS => 'foo.tt']});
+process_ok("Foo[% META foo='meta' %]" => "(metaBAR)BAR", {tt_config => [POST_PROCESS => 'bar.tt', PROCESS => 'foo.tt']});
+
+###----------------------------------------------------------------###
+print "### CONFIG WRAPPER ###################################################\n";
+
+process_ok(" one " => 'Hi one there', {tt_config => [WRAPPER => 'wrap.tt']});
+process_ok(" one " => 'Hi one there', {tt_config => [WRAPPER => ['wrap.tt']]});
+process_ok(" one " => 'HiwrapHi one therethere', {tt_config => [WRAPPER => ['wrap.tt', 'wrap.tt']]});
+process_ok(" ([% baz %]) " => 'Hi () there', {tt_config => [WRAPPER => 'wrap.tt']});
+process_ok(" one " => 'HiBAZ one there', {baz => 'BAZ', tt_config => [WRAPPER => 'wrap.tt']});;
+process_ok(" ([% baz; baz='-local' %]) " => 'Hi-local () there', {tt_config => [WRAPPER => 'wrap.tt']});
+process_ok("[% META foo='BLAM' %] " => 'HiBLAM there', {tt_config => [WRAPPER => 'wrap.tt']});
+
+process_ok(" one " => 'BARHi one there', {tt_config => [WRAPPER => 'wrap.tt', PRE_PROCESS => 'bar.tt']});
+process_ok(" one " => 'HiBARthere', {tt_config => [WRAPPER => 'wrap.tt', PROCESS => 'bar.tt']});
+process_ok(" one " => 'Hi one thereBAR', {tt_config => [WRAPPER => 'wrap.tt', POST_PROCESS => 'bar.tt']});
+
+###----------------------------------------------------------------###
+print "### CONFIG ERRORS ####################################################\n";
+
+process_ok("[% THROW foo 'bar' %]" => 'Error (foo) - (bar)',  {tt_config => [ERROR  => 'catch.tt']});
+process_ok("[% THROW foo 'bar' %]" => 'Error (foo) - (bar)',  {tt_config => [ERRORS => 'catch.tt']});
+process_ok("[% THROW foo 'bar' %]" => 'Error (foo) - (bar)',  {tt_config => [ERROR  => {default => 'catch.tt'}]});
+process_ok("[% THROW foo 'bar' %]" => 'Error (foo) - (bar)',  {tt_config => [ERRORS => {default => 'catch.tt'}]});
+process_ok("[% THROW foo 'bar' %]" => 'Error2 (foo) - (bar)', {tt_config => [ERRORS => {foo => 'catch2.tt', default => 'catch.tt'}]});
+process_ok("[% THROW foo.baz 'bar' %]" => 'Error2 (foo.baz) - (bar)', {tt_config => [ERRORS => {foo => 'catch2.tt', default => 'catch.tt'}]});
+process_ok("[% THROW foo.baz 'bar' %]" => 'Error2 (foo.baz) - (bar)', {tt_config => [ERRORS => {'foo.baz' => 'catch2.tt', default => 'catch.tt'}]});
+process_ok("[% THROW foo 'bar' %]" => 'Error (foo) - (bar)', {tt_config => [ERRORS => {'foo.baz' => 'catch2.tt', default => 'catch.tt'}]});
+process_ok("[% THROW foo.baz 'bar' %]" => 'Error2 (foo.baz) - (bar)', {tt_config => [ERRORS => {foo => 'catch2.tt', default => 'catch.tt'}]});
+
+process_ok("[% THROW foo 'bar' %]" => 'BARError (foo) - (bar)',  {tt_config => [ERROR  => 'catch.tt', PRE_PROCESS => 'bar.tt']});
+process_ok("[% THROW foo 'bar' %]" => 'Error (bing) - (blang)',  {tt_config => [ERROR  => 'catch.tt', PROCESS => 'die.tt']});
+process_ok("[% THROW foo 'bar' %]" => 'Error (bing) - (blang)',  {tt_config => [ERROR  => 'catch.tt', PROCESS => ['bar.tt', 'die.tt']]});
+process_ok("[% THROW foo 'bar' %]" => 'Error (foo) - (bar)BAR',  {tt_config => [ERROR  => 'catch.tt', POST_PROCESS => 'bar.tt']});
+process_ok("[% THROW foo 'bar' %]" => 'HiError (foo) - (bar)there', {tt_config => [ERROR  => 'catch.tt', WRAPPER => 'wrap.tt']});
+
+process_ok("(outer)[% PROCESS 'die.tt' %]" => 'Error (bing) - (blang)',  {tt_config => [ERROR  => 'catch.tt']});
+process_ok("(outer)[% TRY %][% PROCESS 'die.tt' %][% CATCH %] [% END %]" => '(outer) ',  {tt_config => [ERROR  => 'catch.tt']});
+
+process_ok(" one " => '',  {tt_config => [ERROR  => 'catch.tt', PRE_PROCESS => 'die.tt']});
+process_ok(" one " => '',  {tt_config => [ERROR  => 'catch.tt', POST_PROCESS => 'die.tt']});
+process_ok(" one " => '',  {tt_config => [ERROR  => 'catch.tt', WRAPPER => 'die.tt']});
+
+###----------------------------------------------------------------###
+print "### CONFIG and DUMP ##################################################\n";
+
+process_ok("[% CONFIG DUMP => {html => 0}; DUMP foo; PROCESS config.tt; DUMP foo %]" => qq{DUMP: File "input text" line 1
+    foo = 'FOO';
+<b>DUMP: File "config.tt" line 1</b><pre>foo = &apos;FOO&apos;;
+</pre>DUMP: File "input text" line 1
+    foo = 'FOO';
+}, {foo => 'FOO'}) if ! $is_tt;
+
+###----------------------------------------------------------------###
+print "### NOT FOUND CACHE ##################################################\n";
+
+process_ok("[% BLOCK foo; TRY; PROCESS blurty.tt; CATCH %]([% error.type %])([% error.info %])\n[% END; END; PROCESS foo; PROCESS foo %]" => "(file)(blurty.tt: not found)\n(file)(blurty.tt: not found (cached))\n", {tt_config => [NEGATIVE_STAT_TTL => 2]}) if ! $is_tt;
+process_ok("[% BLOCK foo; TRY; PROCESS blurty.tt; CATCH %]([% error.type %])([% error.info %])\n[% END; END; PROCESS foo; PROCESS foo %]" => "(file)(blurty.tt: not found)\n(file)(blurty.tt: not found)\n", {tt_config => [NEGATIVE_STAT_TTL => -1]}) if ! $is_tt;
+process_ok("[% BLOCK foo; TRY; PROCESS blurty.tt; CATCH %]([% error.type %])([% error.info %])\n[% END; END; PROCESS foo; PROCESS foo %]" => "(file)(blurty.tt: not found)\n(file)(blurty.tt: not found)\n", {tt_config => [STAT_TTL => -1]}) if ! $is_tt;
+
+###----------------------------------------------------------------###
+print "### DONE #############################################################\n";
index dee858854a4e2457af36032e1150670637e46267..704bad69b7c1df34ed4587c370d8d92c356a5c91 100644 (file)
@@ -215,7 +215,7 @@ process_ok("[% USE view -%]
    CATCH view ;
      \"[\$error.type] \$error.info\" ;
    END
-%]" => "[view] file error - Template_View: not found", $vars);
+%]" => qr{^\Q[view] file error - Template_View: not found\E}, $vars);
 
 process_ok("[% USE view -%]
 [% view.print( foo ) %]" => "{ e => 2.718, pi => 3.14 }", $vars);
@@ -418,9 +418,9 @@ Goodbye World!
 [% END %]
 [% END -%]
 [% TRY; INCLUDE foo; CATCH; error; END %]
-[% foo.include_hello %]" => "file error - foo: not found
+[% foo.include_hello %]" => qr{^\Qfile error - foo: not found
 Hello World!
-", $vars);
+\E}, $vars);
 
 process_ok("[% title = \"Previous Title\" -%]
 [% VIEW foo 
This page took 0.05568 seconds and 4 git commands to generate.