| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package TX; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 4 |  |  | 4 |  | 102467 | use 5.008008; | 
|  | 4 |  |  |  |  | 16 |  | 
|  | 4 |  |  |  |  | 147 |  | 
| 4 | 4 |  |  | 4 |  | 24 | use strict; | 
|  | 4 |  |  |  |  | 7 |  | 
|  | 4 |  |  |  |  | 143 |  | 
| 5 | 4 |  |  | 4 |  | 45 | use warnings; | 
|  | 4 |  |  |  |  | 14 |  | 
|  | 4 |  |  |  |  | 107 |  | 
| 6 | 4 |  |  | 4 |  | 3910 | use Text::Template::Library; | 
|  | 4 |  |  |  |  | 36741 |  | 
|  | 4 |  |  |  |  | 206 |  | 
| 7 | 4 |  |  | 4 |  | 40 | use File::Spec; | 
|  | 4 |  |  |  |  | 10 |  | 
|  | 4 |  |  |  |  | 99 |  | 
| 8 | 4 |  |  | 4 |  | 22 | use Exporter 'import'; | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 115 |  | 
| 9 | 4 |  |  | 4 |  | 23 | use Config qw/%Config/; | 
|  | 4 |  |  |  |  | 6 |  | 
|  | 4 |  |  |  |  | 982 |  | 
| 10 | 4 |  |  | 4 |  | 22 | use Carp; | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 675 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | our @EXPORT_OK=qw(include); | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | our $VERSION='0.09'; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | our @attributes; | 
| 17 |  |  |  |  |  |  | BEGIN { | 
| 18 |  |  |  |  |  |  | # define attributes and implement accessor methods | 
| 19 | 4 |  |  | 4 |  | 56 | @attributes=qw/path cache cachesize delimiters Ostack Vstack Lstack Fstack G | 
| 20 |  |  |  |  |  |  | export_include auto_reload_templates package prepend output | 
| 21 |  |  |  |  |  |  | binmode evalcache evalcachesize preserve_G/; | 
| 22 | 4 |  |  |  |  | 25 | for( my $i=0; $i<@attributes; $i++ ) { | 
| 23 | 72 |  |  |  |  | 84 | my $method_num=$i; | 
| 24 |  |  |  |  |  |  | ## no critic | 
| 25 | 4 |  |  | 4 |  | 22 | no strict 'refs'; | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 332 |  | 
| 26 | 72 |  |  | 794 |  | 17069 | *{__PACKAGE__.'::'.$attributes[$method_num]}= | 
|  | 794 |  |  |  |  | 4437 |  | 
| 27 | 72 |  |  |  |  | 230 | sub : lvalue {$_[0]->[$method_num]}; | 
| 28 |  |  |  |  |  |  | ## use critic | 
| 29 |  |  |  |  |  |  | } | 
| 30 |  |  |  |  |  |  | } | 
| 31 | 5 |  |  | 5 | 0 | 256 | sub attributes {@attributes} | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | our $TX; | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | sub new { | 
| 36 | 5 |  |  | 5 | 1 | 3496 | my ($class, @param)=@_; | 
| 37 | 5 |  | 33 |  |  | 46 | $class=ref($class) || $class; | 
| 38 |  |  |  |  |  |  |  | 
| 39 | 5 |  |  |  |  | 16 | my $I=bless []=>$class; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 5 |  |  |  |  | 27 | $I->export_include=1; | 
| 42 | 5 |  |  |  |  | 26 | $I->prepend=''; | 
| 43 |  |  |  |  |  |  |  | 
| 44 | 5 |  |  |  |  | 41 | my (%public, %private, %ignored); | 
| 45 | 5 |  |  |  |  | 24 | foreach my $attr ($I->attributes) { | 
| 46 | 96 | 100 |  |  |  | 174 | if( $attr=~/^_/ ) { | 
| 47 | 2 |  |  |  |  | 6 | $private{$attr}=1; | 
| 48 |  |  |  |  |  |  | } else { | 
| 49 | 94 |  |  |  |  | 292 | $public{$attr}=1; | 
| 50 |  |  |  |  |  |  | } | 
| 51 |  |  |  |  |  |  | } | 
| 52 | 5 |  |  |  |  | 38 | my @initparam; | 
| 53 | 5 |  |  |  |  | 64 | while( my ($k, $v)=splice @param, 0, 2 ) { | 
| 54 | 16 | 100 |  |  |  | 61 | unless( exists $public{$k} ) { | 
| 55 | 5 | 100 |  |  |  | 12 | if( exists $private{$k} ) { | 
| 56 | 2 |  |  |  |  | 4 | $ignored{$k}=1; | 
| 57 |  |  |  |  |  |  | } else { | 
| 58 | 3 |  |  |  |  | 6 | push @initparam, $k, $v; | 
| 59 |  |  |  |  |  |  | } | 
| 60 | 5 |  |  |  |  | 16 | next; | 
| 61 |  |  |  |  |  |  | } | 
| 62 | 11 |  |  |  |  | 39 | $I->$k=$v; | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 5 |  |  |  |  | 28 | @initparam=$I->init(@initparam); | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 5 | 100 |  |  |  | 22 | if( @initparam ) { | 
| 68 | 2 |  |  |  |  | 5 | my %o=@initparam; | 
| 69 | 2 |  |  |  |  | 8 | @ignored{keys %o}=(); | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 5 | 100 |  |  |  | 21 | if( keys %ignored ) { | 
| 73 | 2 |  |  |  |  | 453 | carp "the following parameters have been ignored: ".join(', ', | 
| 74 |  |  |  |  |  |  | keys %ignored); | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 5 |  |  |  |  | 51 | return $I; | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | sub init { | 
| 81 | 5 |  |  | 5 | 0 | 27 | my ($I, @param)=@_; | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 5 | 100 |  |  |  | 20 | if( defined $I->path ) { | 
| 84 | 2 | 50 |  |  |  | 6 | if( ref $I->path ne 'ARRAY' ) { | 
| 85 | 0 |  |  |  |  | 0 | $I->path=[split /\Q$Config{path_sep}\E/, $I->path]; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  | } else { | 
| 88 | 3 | 100 |  |  |  | 22 | if( exists $ENV{TEMPLATE_PATH} ) { | 
| 89 | 1 |  |  |  |  | 37 | $I->path=[split /\Q$Config{path_sep}\E/, $ENV{TEMPLATE_PATH}]; | 
| 90 |  |  |  |  |  |  | } else { | 
| 91 | 2 |  |  |  |  | 6 | $I->path=[]; | 
| 92 |  |  |  |  |  |  | # default path is derived from the location of $0 and this module. | 
| 93 |  |  |  |  |  |  | # the filename component and last directory component of $0 are replaced | 
| 94 |  |  |  |  |  |  | # by 'templates' | 
| 95 | 2 |  |  |  |  | 45 | my ($vol, $dir, $filename)=File::Spec->splitpath($0); | 
| 96 | 2 |  |  |  |  | 4 | my @dirs; | 
| 97 | 2 | 50 |  |  |  | 7 | if( ref($I) ne __PACKAGE__ ) { | 
| 98 | 2 |  |  |  |  | 9 | ($filename=ref($I))=~s!::!/!g; $filename.='.pm'; | 
|  | 2 |  |  |  |  | 4 |  | 
| 99 | 2 | 50 |  |  |  | 8 | if( exists $INC{$filename} ) { | 
| 100 | 0 |  |  |  |  | 0 | ($vol, $dir, $filename)=File::Spec->splitpath($INC{$filename}); | 
| 101 | 0 |  |  |  |  | 0 | @dirs=File::Spec->splitdir($dir); | 
| 102 | 0 |  |  |  |  | 0 | $filename=~s/\.pm$//; | 
| 103 | 0 |  |  |  |  | 0 | push @dirs, $filename; | 
| 104 | 0 |  |  |  |  | 0 | push @dirs, 'templates'; | 
| 105 | 0 |  |  |  |  | 0 | push @{$I->path}, | 
|  | 0 |  |  |  |  | 0 |  | 
| 106 |  |  |  |  |  |  | File::Spec->catpath($vol, File::Spec->catdir(@dirs), ''); | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 2 |  |  |  |  | 6 | ($filename=__PACKAGE__)=~s!::!/!g; $filename.='.pm'; | 
|  | 2 |  |  |  |  | 3 |  | 
| 111 | 2 | 50 |  |  |  | 8 | if( exists $INC{$filename} ) { | 
| 112 | 2 |  |  |  |  | 23 | ($vol, $dir, $filename)=File::Spec->splitpath($INC{$filename}); | 
| 113 | 2 |  |  |  |  | 20 | @dirs=File::Spec->splitdir($dir); | 
| 114 | 2 |  |  |  |  | 10 | $filename=~s/\.pm$//; | 
| 115 | 2 |  |  |  |  | 4 | push @dirs, $filename; | 
| 116 | 2 |  |  |  |  | 5 | push @dirs, 'templates'; | 
| 117 | 2 |  |  |  |  | 2 | push @{$I->path}, | 
|  | 2 |  |  |  |  | 10 |  | 
| 118 |  |  |  |  |  |  | File::Spec->catpath($vol, File::Spec->catdir(@dirs), ''); | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 5 | 50 |  |  |  | 26 | unless( defined $I->binmode ) { | 
| 124 | 5 |  |  |  |  | 25 | $I->binmode=$ENV{TEMPLATE_BINMODE}; | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 5 | 100 |  |  |  | 23 | $I->delimiters=$ENV{TEMPLATE_DELIMITERS} unless( defined $I->delimiters ); | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 5 | 100 | 100 |  |  | 14 | if( defined $I->delimiters and ref $I->delimiters ne 'ARRAY' ) { | 
| 130 | 1 |  |  |  |  | 3 | my @l=split /\t+/, $I->delimiters, 2; | 
| 131 | 1 | 50 |  |  |  | 6 | @l==2 or @l=split /\s+/, $I->delimiters, 2; | 
| 132 | 1 | 50 |  |  |  | 7 | $I->delimiters=\@l if @l==2; | 
| 133 |  |  |  |  |  |  | } | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 5 |  |  |  |  | 24 | $I->cache={}; | 
| 136 | 5 | 50 | 33 |  |  | 45 | if( defined $I->cachesize and $I->cachesize>0 ) { | 
| 137 | 0 | 0 |  |  |  | 0 | if( eval {require Tie::Cache::LRU} ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 138 | 0 |  |  |  |  | 0 | tie %{$I->cache}, 'Tie::Cache::LRU', $I->cachesize; | 
|  | 0 |  |  |  |  | 0 |  | 
| 139 |  |  |  |  |  |  | } else { | 
| 140 | 0 |  |  |  |  | 0 | warn "Cannot load Tie::Cache::LRU: $@"; | 
| 141 |  |  |  |  |  |  | } | 
| 142 |  |  |  |  |  |  | } | 
| 143 |  |  |  |  |  |  |  | 
| 144 | 5 | 100 |  |  |  | 17 | unless( defined $I->evalcache ) { | 
| 145 | 3 |  |  |  |  | 15 | $I->evalcache=$ENV{TEMPLATE_EVALCACHE}; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 5 | 100 |  |  |  | 16 | if( $I->evalcache ) { | 
| 149 | 2 | 50 |  |  |  | 5 | $I->evalcache={} unless( ref($I->evalcache) eq 'HASH' ); | 
| 150 | 2 | 50 | 33 |  |  | 14 | if( defined $I->evalcachesize and $I->evalcachesize>0 ) { | 
| 151 | 0 | 0 |  |  |  | 0 | if( eval {require Tie::Cache::LRU} ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 152 | 0 |  |  |  |  | 0 | tie %{$I->evalcache}, 'Tie::Cache::LRU', $I->evalcachesize; | 
|  | 0 |  |  |  |  | 0 |  | 
| 153 |  |  |  |  |  |  | } else { | 
| 154 | 0 |  |  |  |  | 0 | warn "Cannot load Tie::Cache::LRU: $@"; | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  | } | 
| 158 |  |  |  |  |  |  |  | 
| 159 | 5 |  |  |  |  | 27 | $I->Fstack=[]; | 
| 160 | 5 |  |  |  |  | 55 | $I->Ostack=[]; | 
| 161 | 5 |  |  |  |  | 19 | $I->Vstack=[]; | 
| 162 | 5 |  |  |  |  | 25 | $I->Lstack=[]; | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 5 |  |  |  |  | 17 | return @param; | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | sub clear_cache { | 
| 168 | 0 |  |  | 0 | 1 | 0 | my ($I, $re, $xor)=@_; | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 0 |  |  |  |  | 0 | local $_; | 
| 171 | 0 | 0 | 0 |  |  | 0 | if( @_>2 ) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | # got both $re and $xor | 
| 173 | 0 | 0 |  |  |  | 0 | $re=qr/$re/ unless ref($re) eq 'Regexp'; | 
| 174 | 0 |  | 0 |  |  | 0 | delete @{$I->cache}{grep( ($xor xor !$_=~$re), keys %{$I->cache} )}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 175 |  |  |  |  |  |  | } elsif( @_>1 and ref($re) eq 'Regexp' ) { | 
| 176 | 0 |  |  |  |  | 0 | delete @{$I->cache}{grep( !$_=~$re, keys %{$I->cache} )}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 177 |  |  |  |  |  |  | } elsif( @_>1 ) { | 
| 178 | 0 |  |  |  |  | 0 | $xor=$re=~s/^!//; | 
| 179 | 0 |  |  |  |  | 0 | $re=qr/$re/; | 
| 180 | 0 |  | 0 |  |  | 0 | delete @{$I->cache}{grep( ($xor xor !$_=~$re), keys %{$I->cache} )}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 181 |  |  |  |  |  |  | } else { | 
| 182 | 0 |  |  |  |  | 0 | %{$I->cache}=(); | 
|  | 0 |  |  |  |  | 0 |  | 
| 183 |  |  |  |  |  |  | } | 
| 184 | 0 |  |  |  |  | 0 | return; | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | sub get_template { | 
| 188 | 27 |  |  | 27 | 0 | 47 | my ($I, $filename, $module)=@_; | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | #use Data::Dumper; warn Dumper(\@_); | 
| 191 |  |  |  |  |  |  |  | 
| 192 | 27 | 100 |  |  |  | 48 | if( ref $filename ) { | 
| 193 | 21 |  |  |  |  | 32 | my $template_string=$filename->{template}; | 
| 194 | 21 |  |  |  |  | 38 | $filename=$filename->{filename}; | 
| 195 |  |  |  |  |  |  | my $t=Text::Template::Library->new | 
| 196 |  |  |  |  |  |  | ( | 
| 197 |  |  |  |  |  |  | TYPE=>'STRING', SOURCE=>$template_string, | 
| 198 |  |  |  |  |  |  | FILENAME=>$filename, | 
| 199 |  |  |  |  |  |  | ($I->delimiters ? (DELIMITERS=>$I->delimiters) : ()), | 
| 200 |  |  |  |  |  |  | BROKEN=>sub { | 
| 201 | 0 |  |  | 0 |  | 0 | my %o=@_; | 
| 202 | 0 | 0 |  |  |  | 0 | die $o{error} if ref $o{error}; | 
| 203 | 0 |  |  |  |  | 0 | $o{error}=~s/\s*\z//; | 
| 204 | 0 |  |  |  |  | 0 | die "Template Error in $filename($o{lineno}): $o{error}\n"; | 
| 205 |  |  |  |  |  |  | }, | 
| 206 | 21 | 50 |  |  |  | 42 | PREPEND=>$I->prepend."\n;use strict; our (%V, %G, %L)\n", | 
|  |  | 50 |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | (defined $I->evalcache ? (EVALCACHE=>$I->evalcache) : ()), | 
| 208 |  |  |  |  |  |  | ); | 
| 209 | 21 | 50 |  |  |  | 8841 | die "Template Error: Cannot compile $filename\n" unless( $t->compile ); | 
| 210 | 21 |  |  |  |  | 10808 | $I->cache->{$filename}=[$t]; | 
| 211 |  |  |  |  |  |  | } else { | 
| 212 | 6 | 50 | 66 |  |  | 22 | if( exists $I->cache->{$filename} and $I->auto_reload_templates ) { | 
| 213 | 0 |  |  |  |  | 0 | my ($path, $base); | 
| 214 | 0 |  |  |  |  | 0 | foreach my $p (@{$I->path}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 215 | 0 |  |  |  |  | 0 | my $base=File::Spec->catfile($p, $filename); | 
| 216 | 0 | 0 | 0 |  |  | 0 | if( -f ($path=$base) && -r _ or | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 217 |  |  |  |  |  |  | -f ($path=$base.".tmpl") && -r _ or | 
| 218 |  |  |  |  |  |  | -f ($path=$base.".html") && -r _ ) { | 
| 219 | 0 |  |  |  |  | 0 | my ($dev, $ino, $mtime)=(stat _)[0,1,9]; | 
| 220 | 0 |  |  |  |  | 0 | my $cachel=$I->cache->{$filename}; | 
| 221 | 0 | 0 | 0 |  |  | 0 | if( $cachel->[1]!=$dev or | 
|  |  |  | 0 |  |  |  |  | 
| 222 |  |  |  |  |  |  | $cachel->[2]!=$ino or | 
| 223 |  |  |  |  |  |  | $cachel->[3]!=$mtime ) { | 
| 224 | 0 |  |  |  |  | 0 | delete $I->cache->{$filename}; | 
| 225 |  |  |  |  |  |  | } | 
| 226 | 0 |  |  |  |  | 0 | last; | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  | } | 
| 230 | 6 | 100 |  |  |  | 14 | unless( exists $I->cache->{$filename} ) { | 
| 231 | 4 |  |  |  |  | 6 | my $fh; | 
| 232 | 4 |  |  |  |  | 5 | my ($path, $base); | 
| 233 | 4 |  |  |  |  | 6 | foreach my $p (@{$I->path}) { | 
|  | 4 |  |  |  |  | 11 |  | 
| 234 | 6 |  |  |  |  | 121 | my $base=File::Spec->catfile($p, $filename); | 
| 235 | 6 |  |  |  |  | 24 | my $mode=$I->binmode; | 
| 236 | 6 | 50 |  |  |  | 14 | if( defined $I->binmode ) { | 
| 237 | 0 |  |  |  |  | 0 | $mode=~s/^:?/<:/; | 
| 238 |  |  |  |  |  |  | } else { | 
| 239 | 6 |  |  |  |  | 9 | $mode='<'; | 
| 240 |  |  |  |  |  |  | } | 
| 241 | 6 | 100 | 66 |  |  | 390 | if( open $fh, $mode, $path=$base or | 
|  |  |  | 66 |  |  |  |  | 
| 242 |  |  |  |  |  |  | open $fh, $mode, $path=$base.".tmpl" or | 
| 243 |  |  |  |  |  |  | open $fh, $mode, $path=$base.".html" ) { | 
| 244 |  |  |  |  |  |  | my $t=Text::Template::Library->new | 
| 245 |  |  |  |  |  |  | ( | 
| 246 |  |  |  |  |  |  | TYPE=>'FILEHANDLE', SOURCE=>$fh, | 
| 247 |  |  |  |  |  |  | FILENAME=>$filename, | 
| 248 |  |  |  |  |  |  | ($I->delimiters ? (DELIMITERS=>$I->delimiters) : ()), | 
| 249 |  |  |  |  |  |  | BROKEN=>sub { | 
| 250 | 4 |  |  | 4 |  | 2047 | my %o=@_; | 
| 251 | 4 | 50 |  |  |  | 15 | die $o{error} if ref $o{error}; | 
| 252 | 4 |  |  |  |  | 76 | $o{error}=~s/\s*\z//; | 
| 253 | 4 |  |  |  |  | 54 | die "Template Error in $path($o{lineno}): $o{error}\n"; | 
| 254 |  |  |  |  |  |  | }, | 
| 255 | 4 | 50 |  |  |  | 15 | PREPEND=>$I->prepend."\n;use strict; our (%V, %G, %L)\n", | 
|  |  | 100 |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | (defined $I->evalcache ? (EVALCACHE=>$I->evalcache) : ()), | 
| 257 |  |  |  |  |  |  | ); | 
| 258 | 4 | 50 |  |  |  | 2015 | die "Template Error: Cannot compile $path\n" unless( $t->compile ); | 
| 259 | 4 |  |  |  |  | 1099 | $I->cache->{$filename}=[$t, (stat $fh)[0,1,9]]; | 
| 260 | 4 |  |  |  |  | 73 | last; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  | } | 
| 264 | 0 |  |  |  |  | 0 | die "Template Error: $filename not found in path ". | 
| 265 | 6 | 50 |  |  |  | 17 | join($Config{path_sep}, @{$I->path})."\n" | 
| 266 |  |  |  |  |  |  | unless( exists $I->cache->{$filename} ); | 
| 267 |  |  |  |  |  |  | } | 
| 268 |  |  |  |  |  |  |  | 
| 269 | 27 | 100 | 66 |  |  | 507 | if( defined $module and length $module ) { | 
| 270 | 22 |  |  |  |  | 45 | return $I->cache->{$filename}->[0]->module($module); | 
| 271 |  |  |  |  |  |  | } else { | 
| 272 | 5 |  |  |  |  | 14 | return $I->cache->{$filename}->[0]; | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  | } | 
| 275 |  |  |  |  |  |  |  | 
| 276 |  |  |  |  |  |  | sub include { | 
| 277 | 27 |  |  | 27 | 1 | 18774 | my $tmpl=shift; | 
| 278 | 27 |  |  |  |  | 45 | my $I; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 27 |  |  |  |  | 37 | my $tx=$TX; | 
| 281 |  |  |  |  |  |  |  | 
| 282 | 27 | 100 |  |  |  | 37 | if( eval {$tmpl->isa(__PACKAGE__)} ) { | 
|  | 27 | 100 |  |  |  | 278 |  | 
| 283 | 6 |  |  |  |  | 11 | $I=$tmpl; | 
| 284 | 6 |  |  |  |  | 11 | $tmpl=shift; | 
| 285 |  |  |  |  |  |  | } elsif( $tx ) { | 
| 286 | 20 |  |  |  |  | 25 | $I=$tx; | 
| 287 |  |  |  |  |  |  | } else { | 
| 288 | 1 |  |  |  |  | 7 | $TX=$I=__PACKAGE__->new; | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  |  | 
| 291 | 27 |  |  |  |  | 40 | local $TX; | 
| 292 | 27 |  |  |  |  | 31 | $TX=$I; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 27 |  |  |  |  | 31 | my ($filename, $tmp_filename, $module); | 
| 295 | 27 | 100 |  |  |  | 53 | if( ref($tmpl) ) { | 
| 296 | 3 |  |  |  |  | 4 | $filename=$tmpl; | 
| 297 | 3 |  |  |  |  | 9 | $module=$tmpl->{fragment}; | 
| 298 |  |  |  |  |  |  | } else { | 
| 299 | 24 |  |  |  |  | 72 | ($tmp_filename, $module)=split /#/, $tmpl, 2; | 
| 300 | 24 | 100 |  |  |  | 57 | if( length $tmp_filename ) { | 
| 301 | 4 |  |  |  |  | 8 | $filename=$tmp_filename; | 
| 302 |  |  |  |  |  |  | } else { | 
| 303 | 20 |  |  |  |  | 49 | $filename=$I->Fstack->[0]; | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  | } | 
| 306 | 27 |  |  |  |  | 39 | unshift @{$I->Fstack}, $filename; | 
|  | 27 |  |  |  |  | 53 |  | 
| 307 |  |  |  |  |  |  |  | 
| 308 | 27 |  |  |  |  | 30 | my %opts; | 
| 309 | 27 | 100 |  |  |  | 90 | if( ref($_[0]) eq 'HASH' ) { | 
| 310 | 15 |  |  |  |  | 19 | %opts=%{shift()}; | 
|  | 15 |  |  |  |  | 65 |  | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  |  | 
| 313 | 27 |  |  |  |  | 41 | my $add_v=''; | 
| 314 | 27 | 100 |  |  |  | 98 | $add_v=lc delete $opts{VMODE} if exists $opts{VMODE}; | 
| 315 | 27 |  |  |  |  | 45 | my $keep_v=$add_v eq 'keep'; | 
| 316 | 27 |  |  |  |  | 36 | $add_v=$add_v eq 'add'; | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | #use Data::Dumper; $Data::Dumper::Useqq=1; warn Dumper \%opts, $I->Ostack; | 
| 319 | 27 | 100 |  |  |  | 81 | unless( %opts ) { | 
| 320 | 23 | 100 |  |  |  | 23 | %opts=%{$I->Ostack->[0]} if( @{$I->Ostack} ); | 
|  | 20 |  |  |  |  | 38 |  | 
|  | 23 |  |  |  |  | 45 |  | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 27 | 100 |  |  |  | 83 | unless( exists $opts{OUTPUT} ) { | 
| 324 | 3 | 50 |  |  |  | 4 | $opts{OUTPUT}=(@{$I->Ostack} | 
|  | 3 | 50 |  |  |  | 8 |  | 
| 325 |  |  |  |  |  |  | ? $I->Ostack->[0]->{OUTPUT} | 
| 326 |  |  |  |  |  |  | : defined $I->output ? $I->output : \*STDOUT); | 
| 327 |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 27 | 100 |  |  |  | 63 | unless( exists $opts{PACKAGE} ) { | 
| 330 | 7 | 50 |  |  |  | 24 | $opts{PACKAGE}=(@{$I->Ostack} | 
|  | 7 | 100 |  |  |  | 28 |  | 
| 331 |  |  |  |  |  |  | ? $I->Ostack->[0]->{PACKAGE} | 
| 332 |  |  |  |  |  |  | : defined $I->package ? $I->package : __PACKAGE__.'::__'); | 
| 333 |  |  |  |  |  |  | } | 
| 334 |  |  |  |  |  |  | #use Data::Dumper; $Data::Dumper::Useqq=1; warn Dumper \%opts; | 
| 335 | 27 |  |  |  |  | 38 | unshift @{$I->Ostack}, +{%opts}; | 
|  | 27 |  |  |  |  | 47 |  | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | # allow to specify an arbitrary string as OUTPUT to indicate | 
| 338 |  |  |  |  |  |  | # the result is wanted as string. | 
| 339 | 27 |  |  |  |  | 40 | my $want_stringoutput; | 
| 340 | 27 | 50 |  |  |  | 62 | unless( ref($opts{OUTPUT}) ) { | 
| 341 | 27 |  |  |  |  | 60 | delete $opts{OUTPUT}; | 
| 342 | 27 |  |  |  |  | 35 | $want_stringoutput=1; | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  |  | 
| 345 | 27 | 50 |  |  |  | 55 | if( $I->export_include ) { | 
| 346 | 4 |  |  | 4 |  | 37 | no strict 'refs'; | 
|  | 4 |  |  |  |  | 10 |  | 
|  | 4 |  |  |  |  | 1094 |  | 
| 347 | 27 | 100 |  |  |  | 33 | unless( defined &{$opts{PACKAGE}.'::include'} ) { | 
|  | 27 |  |  |  |  | 113 |  | 
| 348 | 3 |  |  |  |  | 7 | *{$opts{PACKAGE}.'::include'}=\&include; | 
|  | 3 |  |  |  |  | 25 |  | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  | } | 
| 351 |  |  |  |  |  |  |  | 
| 352 | 27 |  |  |  |  | 29 | my $vars; | 
| 353 | 27 | 100 |  |  |  | 165 | if( $keep_v ) { | 
|  |  | 50 |  |  |  |  |  | 
| 354 | 13 | 50 |  |  |  | 16 | $vars=@{$I->Vstack} ? $I->Vstack->[0] : +{}; | 
|  | 13 |  |  |  |  | 28 |  | 
| 355 |  |  |  |  |  |  | } elsif( $add_v ) { | 
| 356 | 0 |  |  |  |  | 0 | $vars=+{%{$I->Vstack->[0]}}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 357 | 0 |  |  |  |  | 0 | my %x=@_; | 
| 358 | 0 |  |  |  |  | 0 | @{$vars}{keys %x}=values %x; | 
|  | 0 |  |  |  |  | 0 |  | 
| 359 |  |  |  |  |  |  | } else {			# new V | 
| 360 | 14 |  |  |  |  | 40 | $vars=+{@_}; | 
| 361 |  |  |  |  |  |  | } | 
| 362 | 27 |  |  |  |  | 32 | unshift @{$I->Vstack}, $vars; | 
|  | 27 |  |  |  |  | 50 |  | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 27 | 100 | 66 |  |  | 31 | if( !@{$I->Lstack} and | 
|  | 27 |  | 66 |  |  | 48 |  | 
| 365 |  |  |  |  |  |  | !$I->preserve_G || ref($I->G) ne 'HASH' ) { | 
| 366 | 4 |  |  |  |  | 21 | $I->G={}; | 
| 367 |  |  |  |  |  |  | } | 
| 368 | 27 |  |  |  |  | 31 | unshift @{$I->Lstack}, {}; | 
|  | 27 |  |  |  |  | 46 |  | 
| 369 |  |  |  |  |  |  |  | 
| 370 | 27 |  |  |  |  | 36 | my $rc; | 
| 371 | 27 |  |  |  |  | 35 | eval { | 
| 372 | 4 |  |  | 4 |  | 24 | no strict 'refs'; | 
|  | 4 |  |  |  |  | 4 |  | 
|  | 4 |  |  |  |  | 1067 |  | 
| 373 |  |  |  |  |  |  |  | 
| 374 | 27 |  |  |  |  | 28 | local *{$opts{PACKAGE}.'::V'}=$vars; | 
|  | 27 |  |  |  |  | 129 |  | 
| 375 | 27 |  |  |  |  | 53 | local *{$opts{PACKAGE}.'::G'}=$I->G; | 
|  | 27 |  |  |  |  | 75 |  | 
| 376 | 27 |  |  |  |  | 53 | local *{$opts{PACKAGE}.'::L'}=$I->Lstack->[0]; | 
|  | 27 |  |  |  |  | 85 |  | 
| 377 | 27 | 50 |  |  |  | 49 | if( $want_stringoutput ) { | 
|  |  | 0 |  |  |  |  |  | 
| 378 | 27 |  |  |  |  | 65 | $rc=$I->get_template($filename, $module)->fill_in(%opts); | 
| 379 |  |  |  |  |  |  | } elsif( $I->get_template($filename, $module)->fill_in(%opts) ) { | 
| 380 | 0 |  |  |  |  | 0 | $rc=''; | 
| 381 |  |  |  |  |  |  | } else { | 
| 382 | 0 |  |  |  |  | 0 | die "ERROR: Text::Template::Base::fill_in failed: $Text::Template::Base::ERROR\n"; | 
| 383 |  |  |  |  |  |  | } | 
| 384 |  |  |  |  |  |  | }; | 
| 385 | 27 |  |  |  |  | 15303 | shift @{$I->Vstack}; | 
|  | 27 |  |  |  |  | 65 |  | 
| 386 | 27 |  |  |  |  | 38 | shift @{$I->Ostack}; | 
|  | 27 |  |  |  |  | 53 |  | 
| 387 | 27 |  |  |  |  | 66 | shift @{$I->Fstack}; | 
|  | 27 |  |  |  |  | 54 |  | 
| 388 | 27 |  |  |  |  | 36 | shift @{$I->Lstack}; | 
|  | 27 |  |  |  |  | 49 |  | 
| 389 |  |  |  |  |  |  |  | 
| 390 | 27 | 100 |  |  |  | 6387 | die $@ if( $@ ); | 
| 391 |  |  |  |  |  |  |  | 
| 392 | 23 | 100 | 100 |  |  | 26 | if( @{$I->Fstack} and !defined(wantarray) and length $rc ) { | 
|  | 23 |  | 66 |  |  | 44 |  | 
| 393 |  |  |  |  |  |  | # inside a recursive call (called from a template) in void context | 
| 394 |  |  |  |  |  |  | # with non-empty output. Assume the template author has forgotten | 
| 395 |  |  |  |  |  |  | # to say "OUT include ..." but instead said "include ...". So we do | 
| 396 |  |  |  |  |  |  | # it for him. | 
| 397 |  |  |  |  |  |  |  | 
| 398 | 4 |  |  | 4 |  | 22 | no strict 'refs'; | 
|  | 4 |  |  |  |  | 14 |  | 
|  | 4 |  |  |  |  | 624 |  | 
| 399 | 18 |  |  |  |  | 20 | return &{$opts{PACKAGE}.'::OUT'}( $rc ); | 
|  | 18 |  |  |  |  | 76 |  | 
| 400 |  |  |  |  |  |  | } | 
| 401 |  |  |  |  |  |  |  | 
| 402 | 5 |  |  |  |  | 38 | return $rc; | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | 1; | 
| 406 |  |  |  |  |  |  | __END__ |