HTML-Template-2.97/0000775000175000017500000000000013107402001012100 5ustar samsamHTML-Template-2.97/t/0000775000175000017500000000000013107402001012343 5ustar samsamHTML-Template-2.97/t/12-utf8.t0000644000175000017500000000343313107402001013637 0ustar samsamuse strict; use warnings; use File::Temp qw(tempdir); use Test::More ($] < 5.007001 ? (skip_all => 'utf8 needs at least perl 5.7.1') : (tests => 5)); use_ok('HTML::Template'); # make sure we can't use along with open_mode eval { HTML::Template->new(path => 'templates', filename => 'utf8-test.tmpl', utf8 => 1, open_mode => 1)}; like($@, qr/utf8 and open_mode cannot be used/i, 'cant use uft8 and open_mode at the same time'); my $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', utf8 => 1, ); my $output = $tmpl->output; chomp $output; is($output, chr(228), 'correct UTF8 encoded character'); my $cache_dir = tempdir(CLEANUP => 1); # same as before, this time we test file_cache $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', utf8 => 1, cache => 0, file_cache => 1, file_cache_dir => $cache_dir, ); # trigger cache storage: $output = $tmpl->output; # this time it will implicitly read from the cache $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', utf8 => 1, cache => 0, file_cache => 1, file_cache_dir => $cache_dir, ); $output = $tmpl->output; chomp $output; is($output, chr(228), 'correct UTF8 encoded character from cache'); # this time it will implicitly read from the cache w/out open_mode # which means it won't be correct UTF8. $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', cache => 0, file_cache => 1, file_cache_dir => $cache_dir, ); $output = $tmpl->output; chomp $output; is(sprintf('%vd', $output), "195.164", 'correct non-UTF8 bytes: different open_mode, no cache'); HTML-Template-2.97/t/01-coderefs.t0000644000175000017500000002002613107402001014536 0ustar samsamuse strict; use Test::More (tests => 40); use HTML::Template; my ($output, $template, $result); # test a simple code-ref $template = HTML::Template->new(path => 'templates', filename => 'var.tmpl'); $template->param(foo => sub { 'bar' }); $output = clean($template->output); is($output, 'bar', 'correct value returned'); # test escapes with code-refs $template = HTML::Template->new(path => 'templates', filename => 'escapes.tmpl'); $template->param(foo => sub { '' }); $output = clean($template->output); is($output, ' <bar "foo"> %3Cbar%20%22foo%22%3E', 'correct value escaped'); # a coderef that will increment a variable my $count = 0; $template->param(foo => sub { ++$count }); $output = clean($template->output); is($output, '1 2 3 4 5', 'sub called multiple times'); is($count, 5, 'correctly number of increments'); # a coderef that will increment a variable, but turn cache_lazy_vars on $count = 0; $template = HTML::Template->new(path => 'templates', filename => 'escapes.tmpl', cache_lazy_vars => 1); $template->param(foo => sub { ++$count }); $output = clean($template->output); is($output, '1 1 1 1 1', 'cache_lazy_vars works'); is($count, 1, 'correctly number of increments'); $output = clean($template->output); is($output, '1 1 1 1 1', 'cache_lazy_vars works: output() called multiple times'); is($count, 1, 'correctly number of increments'); # a coderef for a non-existant variable $count = 0; $template = HTML::Template->new(path => 'templates', filename => 'var.tmpl', die_on_bad_params => 0); $template->param(bar => sub { $count++ }); $output = clean($template->output); is($output, '', 'no output'); is($count, 0, 'bar sub never called'); # a coderef used in conditionals and vars $count = 0; $template = HTML::Template->new(path => 'templates', filename => 'if.tmpl'); $template->param(bool => sub { $count++ }); $output = clean($template->output); is($output, 'This is a line outside the if.', 'conditional false and then true'); is($count, 2, 'currect number of increments'); $template->param(bool => sub { --$count }); $output = clean($template->output); is($output, 'This is a line outside the if. INSIDE the if unless', 'conditional true and then false'); is($count, 0, 'currect number of decrements'); # a coderef used in conditionals and vars, but turn cache_lazy_vars on $count = 0; $template = HTML::Template->new(path => 'templates', filename => 'if.tmpl', cache_lazy_vars => 1); $template->param(bool => sub { $count++ }); $output = clean($template->output); is($output, 'This is a line outside the if. unless', 'conditional false w/cache_lazy_vars'); is($count, 1, 'currect number of increments'); # a coderef returns false w/conditionals and vars, but turn cache_lazy_vars on $count = 1; $template = HTML::Template->new(path => 'templates', filename => 'if.tmpl', cache_lazy_vars => 1); $template->param(bool => sub { $count-- }); $output = clean($template->output); is($output, 'This is a line outside the if. INSIDE the if', 'conditional true w/cache_lazy_vars'); is($count, 0, 'currect number of decrements'); # try using a code ref on a TMPL_LOOP $template = HTML::Template->new(path => 'templates', filename => 'loop.tmpl'); $template->param(loop_one => sub { [{var => 1}, {var => 2}] }); $output = clean($template->output); is($output, '1 2', 'simple coderef for a loop'); # try using a code ref on a TMPL_LOOP w/cache_lazy_loops $template = HTML::Template->new(path => 'templates', filename => 'loop.tmpl', cache_lazy_loops => 1); $template->param(loop_one => sub { [{var => 1}, {var => 2}] }); $output = clean($template->output); is($output, '1 2', 'simple coderef for a loop (cache_lazy_loops doesnt change anything)'); # a code ref that returns different things each time it's called $count = 0; $template->param(loop_one => sub { [{var => $count++}, {var => $count++}] }); $output = clean($template->output); is($output, '0 1', 'loop coderef that returns something different each time'); is($count, 2, 'currect number of increments'); # a code ref that returns different things each time it's called w/cache_lazy_loops $count = 0; $template = HTML::Template->new(path => 'templates', filename => 'loop.tmpl', cache_lazy_loops => 1); $template->param(loop_one => sub { [{var => $count++}, {var => $count++}] }); $output = clean($template->output); is($output, '0 1', 'loop coderef that returns something different each time, w/cache_lazy_loops'); is($count, 2, 'currect number of increments'); # try using a code ref on a TMPL_LOOP that's also used as a conditional $count = 0; $template = HTML::Template->new(path => 'templates', filename => 'loop-if.tmpl'); $template->param(loop_one => sub { [{var => $count++}, {var => $count++}] }); $output = clean($template->output); is($output, '2 3', 'loop coderef that returns something different each time'); is($count, 4, 'currect number of increments'); # try using a code ref on a TMPL_LOOP that's also used as a conditional w/cache_lazy_loops $count = 1; $template = HTML::Template->new(path => 'templates', filename => 'loop-if.tmpl', cache_lazy_loops => 1); $template->param(loop_one => sub { [{var => $count++}, {var => $count++}] }); $output = clean($template->output); is($output, '1 2', 'loop coderef that returns something different each time w/cache_lazy_loops'); is($count, 3, 'currect number of increments'); # a code ref (for a loop also used as a conditional) that returns a list the 1st time and an empty list the 2nd $count = 1; $template = HTML::Template->new(path => 'templates', filename => 'loop-if.tmpl'); $template->param(loop_one => sub { $count-- ? [{var => 1}, {var => 2}] : [] }); $output = clean($template->output); is($output, '', 'no output because loop is blank the 2nd time'); is($count, -1, 'currect number of decrements'); # a code ref (for a loop also used as a conditional) that returns a list the 1st time and an empty list the 2nd w/cache_lazy_loops $count = 1; $template = HTML::Template->new(path => 'templates', filename => 'loop-if.tmpl', cache_lazy_loops => 1); $template->param(loop_one => sub { $count-- ? [{var => 1}, {var => 2}] : [] }); $output = clean($template->output); is($output, '1 2', 'loop isnt blank the 2nd time because of cache_lazy_loops'); is($count, 0, 'currect number of decrements'); # a code ref (for a loop also used as a conditional) that returns an empty list the 1st time and a list the 2nd $count = 1; $template = HTML::Template->new(path => 'templates', filename => 'loop-if.tmpl'); $template->param(loop_one => sub { $count-- ? [] : [{var => 1}, {var => 2}] }); $output = clean($template->output); is($output, 'Loop not filled in!', 'coderef returns empty loop the first time and doesnt get called the 2nd'); is($count, 0, 'currect number of decrements'); # a code ref (for a loop also used as a conditional) that returns an empty list the 1st time and a list the 2nd w/cache_lazy_loops $count = 1; $template = HTML::Template->new(path => 'templates', filename => 'loop-if.tmpl', cache_lazy_loops => 1); $template->param(loop_one => sub { $count-- ? [] : [{var => 1}, {var => 2}] }); $output = clean($template->output); is($output, 'Loop not filled in!', 'coderef returns empty loop the first time and cache_lazy_loops caches it'); is($count, 0, 'currect number of decrements'); # a coderef for a non-existant loop $count = 0; $template = HTML::Template->new(path => 'templates', filename => 'loop.tmpl', die_on_bad_params => 0); $template->param(loop_ten => sub { $count++; [{var => 1}, {var => 2}] }); $output = clean($template->output); is($output, '', 'no output because loop doesnt exist'); is($count, 0, 'loop sub never called'); # a coderef for a loop that should never be executed $template = HTML::Template->new(scalarref => \'0', die_on_bad_params => 0); $template->param(bar => sub { $count++; [{var => 1}, {var => 2}] }); $output = clean($template->output); is($output, '', 'no output because surrounding conditional is false'); is($count, 0, 'loop sub never called'); sub clean { my $string = shift; $string =~ s/\s+/ /g; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } HTML-Template-2.97/t/04-no_taintmode.t0000644000175000017500000000051213107402001015425 0ustar samsamuse Test::More ($] < 5.008000 ? (skip_all => 'force_untaint needs at least perl 5.8.0') : (tests => 2)); use_ok('HTML::Template'); my $text = 'foo'; eval { HTML::Template->new(debug => 0, scalarref => \$text, force_untaint => 1) }; like($@, qr/perl does not run in taint mode/, "force_untaint does not work without taint mode"); HTML-Template-2.97/t/13-loop-context.t0000644000175000017500000000564413107402001015413 0ustar samsamuse strict; use warnings; #use Test::More tests => 4; use Test::More 'no_plan'; use_ok('HTML::Template'); my @loop = ({bar => 'a'}, {bar => 'b'}, {bar => 'c'}, {bar => 'd'}, {bar => 'e'}); # no loop_context_vars my $tmpl_string = '10'; my $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0); $template->param(foo => \@loop); my $output = $template->output; is($output, '00000', 'no loop_context_vars'); # __first__ $tmpl_string = '10'; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, '10000', '__first__'); # __last__ $tmpl_string = '10'; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, '00001', '__last__'); # __inner__ $tmpl_string = '10'; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, '01110', '__inner__'); # __outer__ $tmpl_string = '10'; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, '10001', '__outer__'); # __odd__ $tmpl_string = '10'; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, '10101', '__odd__'); # __even__ $tmpl_string = '10'; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, '01010', '__even__'); # __counter__ $tmpl_string = ': '; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, 'a:1 b:2 c:3 d:4 e:5 ', '__counter__'); # __index__ $tmpl_string = ': '; $template = HTML::Template->new(scalarref => \$tmpl_string, die_on_bad_params => 0, loop_context_vars => 1); $template->param(foo => \@loop); $output = $template->output; is($output, 'a:0 b:1 c:2 d:3 e:4 ', '__index__'); HTML-Template-2.97/t/13-loop-boolean.t0000644000175000017500000000236413107402001015342 0ustar samsamuse strict; use warnings; use Test::More tests => 4; use_ok('HTML::Template'); # normal loop with values my $tmpl_string = 'You have a loopNope Foo: '; my $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( my_loop => [{foo => 1}, {foo => 2}]); my $output = $template->output; is($output, 'You have a loop Foo: 1 Foo: 2', 'non-empty loop'); # a loop with an empty data structure $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( my_loop => []); $output = $template->output; is($output, 'Nope', 'empty loop'); # a loop with data inside the structure, but nothing in the template $tmpl_string = 'You have a loopNope'; $template = HTML::Template->new_scalar_ref( \$tmpl_string, die_on_bad_params => 0 ); $template->param( my_loop => [{foo => 1}, {foo => 2}]); $output = $template->output; is($output, 'You have a loop', 'non-empty structure, but empty '); =head1 NAME t/13-loop-boolean.t =head1 OBJECTIVE Provide a test to show that loops (full or empty) should be able to be used as booleans in a TMPL_IF along with using an empty loop. =cut HTML-Template-2.97/t/02-random.t0000644000175000017500000000102213107402001014220 0ustar samsamuse Test::More tests => 200; use HTML::Template; use strict; my $text = q{YESNO}; my $template = HTML::Template->new(scalarref => \$text,); $template->param(foo => sub { int(rand(2)) }); # make sure HTML::Template never goes both ways down an if, which it # used to do because it would re-evaluate the conditional at the else. # Need to test it many times to be sure since it can guess right. my $good = 1; for (1 .. 200) { my $r = $template->output; ok($r eq 'YES' or $r eq 'NO'); } HTML-Template-2.97/t/03-associate.t0000644000175000017500000000164013107402001014722 0ustar samsamuse strict; use warnings; use Test::More # qw(no_plan) tests => 7; BEGIN { use_ok('HTML::Template'); use_ok('CGI', qw(:html3)); } my ($template, $q, %options); # test a simple template $template = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', debug => 0 ); can_ok('HTML::Template', qw(associateCGI)); isa_ok($template, 'HTML::Template'); $q = CGI->new(); isa_ok($q, 'CGI'); $template->associateCGI($q); %options = map { $_, 1 } keys(%{$template->{options}}); ok($options{associate}, "associate option exists in HTML::Template object"); eval { $template->associateCGI([1 .. 10]); }; like( $@, qr/Warning! non-CGI object was passed to HTML::Template::associateCGI/, "non-CGI object detected as incorrectly passed to associateCGI()" ); =head1 NAME t/03-associate.t =head1 OBJECTIVE Test previously untested method C. =cut HTML-Template-2.97/t/05-force_untaint.t0000644000175000017500000000177613107402001015623 0ustar samsam#!perl -T use Test::More ($] < 5.008000 ? (skip_all => 'force_untaint needs at least perl 5.8.0') : (tests => 4)); use Scalar::Util qw(tainted); use lib 'lib'; # needed for prove in taint mode use_ok('HTML::Template'); my $text = qq{ }; my $template = HTML::Template->new( debug => 0, scalarref => \$text, force_untaint => 1, ); # We can't manually taint a variable, can we? # OK, let's use ENV{PATH} - it is usually set and tainted [sn] ok(tainted($ENV{PATH}), "PATH environment variable must be set and tainted for these tests"); $template->param(a => $ENV{PATH}); eval { $template->output() }; like($@, qr/tainted value with 'force_untaint' option/, "set tainted value despite option force_untaint"); # coderef that returns a tainted value $template->param(a => sub { return $ENV{PATH} }); eval { $template->output() }; like( $@, qr/'force_untaint' option but coderef returns tainted value/, "coderef returns tainted value despite option force_untaint" ); HTML-Template-2.97/t/02-parse.t0000644000175000017500000000467213107402001014070 0ustar samsamuse strict; use warnings; use Test::More (tests => 9); use_ok('HTML::Template'); # testing line 1978 my $tmpl_text = < Name:
Job:

EOT eval { HTML::Template->new_scalar_ref(\$tmpl_text) }; like($@, qr/ESCAPE option invalid/, "Escape not in TMPL_VAR"); # testing line 1981 $tmpl_text = < Name:
Job:

EOT eval { HTML::Template->new_scalar_ref(\$tmpl_text) }; like($@, qr/DEFAULT option invalid/, "Escape not in TMPL_VAR"); # testing line 1984 else # not quite checking 1984, deserves some sober attention $tmpl_text = < Name:
Job:

EOT ok(HTML::Template->new_scalar_ref(\$tmpl_text, strict => 0), "Ignores invalid TMPL tags with strict off"); # now with strict on eval { HTML::Template->new_scalar_ref(\$tmpl_text, strict => 1) }; like($@, qr/Syntax error/, "Spits at invalid TMPL tag with strict on"); # make sure we can use and syntax my $tmpl = HTML::Template->new(scalarref => \':'); $tmpl->param(foo => 'a'); my $output = $tmpl->output; is($output, 'a:a', 'both var forms worked'); # attempting to check lines 1540-44 # test using HTML_TEMPLATE_ROOT with path { my $file = 'four.tmpl'; # non-existent file local $ENV{HTML_TEMPLATE_ROOT} = "templates"; eval { HTML::Template->new(path => ['searchpath'], filename => $file) }; like($@, qr/Cannot open included file $file/, "Template file not found"); } { my $file = 'four.tmpl'; # non-existent file local $ENV{HTML_TEMPLATE_ROOT} = "templates"; eval { HTML::Template->new(filename => $file); }; like($@, qr/Cannot open included file $file/, "Template file not found"); } { my ($template, $output); local $ENV{HTML_TEMPLATE_ROOT} = "templates"; $template = HTML::Template->new(filename => 'searchpath/three.tmpl'); $output = $template->output; ok($output =~ /THREE/, "HTML_TEMPLATE_ROOT working without 'path' option being set"); } =head1 NAME t/02-parse.t =head1 OBJECTIVE Test previously untested code inside C. Much remains to be done. =cut HTML-Template-2.97/t/04-escape.t0000644000175000017500000002210113107402001014203 0ustar samsamuse strict; use Test::More (tests => 117); use_ok('HTML::Template'); while () { chomp; next if /^$/; next if /^#/; my ($text, $given, $wanted) = split /\|/; my $template = HTML::Template->new( scalarref => \$text, default_escape => "HTML" ); undef $given if $given eq 'undef'; $template->param(foo => $given); my $output = $template->output; is($output, $wanted, $text); } # use pipe as the seperator between fields. # the TMPL_VAR name should always be 'foo' # fields: TMPL_VAR|given string|escaped string __DATA__ # use default escaping |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n |this is bold\n|<b>this is bold\n # use js escaping |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n |this is bold\n|this is bold\\n #use url escaping |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn |this is bold\n|%3Cb%3Ethis%20is%20bold%5Cn # no escaping |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n # no escaping |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n |this is bold\n|this is bold\n #no escaping and default escaping |this is bold\n|this is bold\n <b>this is bold\n |this is bold\n|this is bold\n <b>this is bold\n # mixing escape and default |flpper|fl<i>pper |flpper|fl<i>pper |flpper|fl<i>pper |undef|UNKNOWN VALUE |undef|UNKNOWN VALUE |undef|UNKNOWN VALUE |flpper|fl<i>pper |flpper|fl<i>pper |flpper|fl<i>pper |undef|UNKNOWN VALUE |undef|UNKNOWN VALUE |undef|UNKNOWN VALUE |flpper|fl<i>pper |flpper|fl<i>pper |flpper|fl<i>pper |undef|UNKNOWN VALUE |undef|UNKNOWN VALUE |undef|UNKNOWN VALUE HTML-Template-2.97/t/11-non-file-templates.t0000644000175000017500000000261513107402001016454 0ustar samsamuse strict; use Test::More qw(no_plan); # tests => 6; use_ok('HTML::Template'); my ($output, $template, $result); my ($fh, $template_string, @template_array, $stemplate, $atemplate, $ftemplate, $fhtemplate, $typetemplate); $template = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', debug => 0 ); open $fh, 'templates/simple.tmpl' or die "Couldn't open simple.tmpl for reading: $!"; { local $/; $template_string = <$fh>; seek $fh, 0, 0; } @template_array = <$fh>; seek $fh, 0, 0; $stemplate = HTML::Template->new_scalar_ref(\$template_string, debug => 0); $atemplate = HTML::Template->new_array_ref(\@template_array, debug => 0); $ftemplate = HTML::Template->new_file( 'simple.tmpl', path => 'templates', debug => 0 ); $fhtemplate = HTML::Template->new_filehandle($fh, debug => 0); $typetemplate = HTML::Template->new( type => 'filename', path => 'templates', source => 'simple.tmpl', debug => 0 ); for my $t ($template, $stemplate, $atemplate, $ftemplate, $fhtemplate, $typetemplate) { $t->param('ADJECTIVE', 'very'); $output = $t->output; ok(($output !~ /ADJECTIVE/ and $t->param('ADJECTIVE') eq 'very'), 'simple template passes'); } =head1 NAME t/11-non-file-templates.t =head1 OBJECTIVE Test whether simple output is correctly created when the template source is a string, array or a filehandle. =cut HTML-Template-2.97/t/testlib/0000775000175000017500000000000013107402001014011 5ustar samsamHTML-Template-2.97/t/testlib/IO/0000775000175000017500000000000013107402001014320 5ustar samsamHTML-Template-2.97/t/testlib/IO/Capture.pm0000644000175000017500000002633713107402001016272 0ustar samsampackage IO::Capture; $VERSION = 0.05; use strict; use Carp; =head1 NAME C - Abstract Base Class to build modules to capture output. =head1 DESCRIPTION The C Module defines an abstract base class that can be used to build modules that capture output being sent on a filehandle such as STDOUT or STDERR. Several modules that come with the distribution do just that. I.e., Capture STDOUT and STDERR. Also see James Keenan's C on CPAN. See L for a discussion of these modules and examples of how to build a module to sub-class from C yourself. If after reading the overview, you would like to build a class from C, look here for details on the internals. =head1 METHODS These are the methods defined in the C Module. This page will be discussing the module from the point of view of someone who wants to build a sub-class of C. Each method defined in the C Module defines a public method, that then calls one or more private methods. I<(Names starting with an underscore)> This allows you to override methods at a finer level of granularity, re-using as much of the functionality provided in the module as possible. Of these internal methods, three are abstract methods that your will B override if you want your module to B anything. The three are C<_start()>, C<_retrieve_captured_text()>. and C<_stop()>. Below are the public methods with the private methods that each uses immediately following. =head2 new The C method creates a new C object, and returns it to its caller. The object is implemented with a hash. Each key used by C is named with the class name. I.e., 'IO::Capture::'. This is to prevent name clashes with keys added by sub-class authors. Attributes can be set in the object by passing a hash reference as a single argument to new(). my $capture = IO::Capture->new( { Key => 'value' } ); All elements from this hash will be added to the object, and will be available for use by children of IO::Capture. my $key = $self->{'Key'}; The internal methods used are: =over 4 =item C<_initialize()> C<_initialize> is called as soon as the empty object has been blessed. It adds the structure to the object that it will need. The C module adds the following IO::Capture::messages => [] IO::Capture::line_pointer => 1 IO::Capture::status => 'Ready', # Busy when capturing =back =head2 start The C method is responsible for saving the current state of the filehandle and or signal hander, and starting the data capture. Start cannot be called if there is already a capture in progress. The C must be called first. These internal methods are called in this order. =over 4 =item C<_check_pre_conditions> C<_check_pre_conditions> is used to make sure all the preconditions are met before starting a capture. The only precondition checked in C, is to insure the "Ready" flag is "on". I.e., There is not already a capture in progress. If your module needs to make some checks, and you override this method, make sure you call the parent class C<_check_pre_conditions> and check the results. sub _check_pre_conditions { my $self = shift; return unless $self->SUPER::_check_pre_conditions; An example of something you might want to check would be, to make sure STDERR is not already I if you are going to be using C on it. B return a boolean true for success, or false for failure. If a failure is indicated, an C will be returned to the calling function, and an remaining private methods for C will B be run. =item C<_save_current_configuration()> C<_save_current_configuration> in C will save the state of C, C, and $SIG{__WARN__}. They are saved in the hash keys 'IO::Capture::stderr_save', 'IO::Capture::stdout_save', and 'IO::Capture::handler_save'. # Save WARN handler $self->{'IO::Capture::handler_save'} = $SIG{__WARN__}; # Dup stdout open STDOUT_SAVE, ">&STDOUT"; # Save ref to dup $self->{'IO::Capture::stdout_save'} = *STDOUT_SAVE; # Dup stderr open STDERR_SAVE, ">&STDOUT"; # Save ref to dup $self->{'IO::Capture::stderr_save'} = *STDERR_SAVE; These saved values can be used in the C<_stop> method to restore the original value to any you changed. $SIG{__WARN__} = $self->{'IO::Capture::handler_save'}; STDOUT = $self->{'IO::Capture::stdout_save'}; STDERR = $self->{'IO::Capture::stderr_save'}; B return a boolean true for success, or false for failure. If a failure is indicated, an C will be returned to the calling function. =item C<_start> B This is only an abstract method in C. It will print a warning if called. Which should not happen, as the author of the sub-class will always be sure to override it with her/his own. :-) This is the first of the three you need to define. You will likely use tie here. The included module C (see L or other module of your own or from CPAN. You will read it from the tied module and put it into the object in C<_retrieve_captured_text>. See L<_retrieve_captured_text> B return a boolean true for success, or false for failure. If a failure is indicated, an C will be returned to the calling function. =back =head2 stop Stop capturing and return any filehandles and interrupt handlers that were changed, to their pre-start state. This B be called B calling C. If you are looking for a way to interact with the process on the other side of the filehandle, take a look at the L<"Other Modules on CPAN">. B return a boolean true for success, or false for failure. If a failure is indicated, an C will be returned to the calling function. =over 4 =item C<_retrieve_captured_text()> Copy any text captured into the object here. For example, The modules in this package tie the filehandle to the (included) C to collect the text. The data needs to be read out of the tied object before the filehandle is untied, so that is done here. In short, if you need to do any work before C<_stop> is called, do it here. The C<_retrieve_capture_text> in this base class just returns true without doing anything. B return a boolean true for success, or false for failure. If a failure is indicated, an C will be returned to the calling function. The C<_stop> internal method will be called first. =item C<_stop> Do what needs to be done to put things back. Such as untie filehandles and put interrupt handlers back to what they were. The default C<_stop> method defined in won't do anything, so you should. B return a boolean true for success, or false for failure. If a failure is indicated, an C will be returned to the calling function. =back =head2 read The C method is responsible for returning the data captured in the object. These internal methods will be run, in this order. =over 4 =item C<_read()> The internal method used to return the captured text. If called in I, an array will be returned. (Could be a lot if you captured a lot) or called in I, the line pointed to by the I will be returned and the I incremented. =back =head1 Other Modules on CPAN If this module is not exactly what you were looking for, take a look at these. Maybe one of them will fit the bill. =over 4 =item * IO::Filter - Generic input/output filters for Perl IO handles =item * Expect - Expect for Perl =item * Tie::Syslog - Tie a filehandle to Syslog. If you Tie STDERR, then all STDERR errors are automatically caught, or you can debug by Carp'ing to STDERR, etc. (Good for CGI error logging.) =item * FileHandle::Rollback - FileHandle with commit and rollback =back =head1 See Also L L L =head1 AUTHORS Mark Reynolds reynoldssgi.com Jon Morgan jmorgansgi.com =head1 MAINTAINED Maintained by Mark Reynolds. reynoldssgi.com =head1 COPYRIGHT Copyright (c) 2003 Mark Reynolds and Jon Morgan Copyright (c) 2004-2005 Mark Reynolds All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. =cut sub new { my $class = shift; if (ref $class) { carp "WARNING: " . __PACKAGE__ . "::new cannot be called from existing object. (cloned)"; return; } my $object = shift || {}; bless $object, $class; $object->_initialize; } sub _check_pre_conditions { my $self = shift; if( $self->{'IO::Capture::status'} ne "Ready") { carp "Start issued on an in progress capture ". ref($self); return; } return 1; } sub _initialize { my $self = shift; if (!ref $self) { carp "WARNING: _initialize was called, but not called from a valid object"; return; } $self->{'IO::Capture::messages'} = []; $self->{'IO::Capture::line_pointer'} = 1; $self->{'IO::Capture::status'} = "Ready"; return $self; } sub start { my $self = shift; if (! $self->_check_pre_conditions) { carp "Error: failed _check_pre_confitions in ". ref($self); return; } if (! $self->_save_current_configuration ) { carp "Error saving configuration in " . ref($self); return; } $self->{'IO::Capture::status'} = "Busy"; if (! $self->_start(@_)) { carp "Error starting capture in " . ref($self); return; } return 1; } sub stop { my $self = shift; if( $self->{'IO::Capture::status'} ne "Busy") { carp "Stop issued on an unstarted capture ". ref($self); return; } if (! $self->_retrieve_captured_text() ) { carp "Error retreaving captured text in " . ref($self); return; } if (!$self->_stop() ) { carp "Error return from _stop() " . ref($self) . "\n"; return; } $self->{'IO::Capture::status'} = "Ready"; return 1; } sub read { my $self = shift; $self->_read; } # # Internal start routine. This needs to be overriden with instance # method # sub _start { my $self = shift; return 1; } sub _read { my $self = shift; my $messages = \@{$self->{'IO::Capture::messages'}}; my $line_pointer = \$self->{'IO::Capture::line_pointer'}; if ($self->{'IO::Capture::status'} ne "Ready") { carp "Read cannot be done while capture is in progress". ref($self); return; } return if $$line_pointer > @$messages; return wantarray ? @$messages : $messages->[($$line_pointer++)-1]; } sub _retrieve_captured_text { return 1; } sub _save_current_configuration { my $self = shift; $self->{'IO::Capture::handler_save'} = $SIG{__WARN__}; open STDOUT_SAVE, ">&STDOUT"; $self->{'IO::Capture::stdout_save'} = *STDOUT_SAVE; open STDERR_SAVE, ">&STDOUT"; $self->{'IO::Capture::stderr_save'} = *STDERR_SAVE; return $self; } sub _stop { my $self = shift; return 1; } sub line_pointer { my $self = shift; my $new_number = shift; $self->{'IO::Capture::line_pointer'} = $new_number if $new_number; return $self->{'IO::Capture::line_pointer'}; } 1; HTML-Template-2.97/t/testlib/IO/Capture/0000775000175000017500000000000013107402001015723 5ustar samsamHTML-Template-2.97/t/testlib/IO/Capture/ErrorMessages.pm0000644000175000017500000000700013107402001021035 0ustar samsampackage IO::Capture::ErrorMessages; use Carp; use base qw/IO::Capture/; use IO::Capture::Tie_STDx; sub _start { my $self = shift; $self->line_pointer(1); $SIG{__WARN__} = sub {print STDERR @_;}; tie *STDERR, "IO::Capture::Tie_STDx"; } sub _retrieve_captured_text { my $self = shift; my $messages = \@{$self->{'IO::Capture::messages'}}; @$messages = ; return 1; } sub _check_pre_conditions { my $self = shift; return unless $self->SUPER::_check_pre_conditions; if (tied *STDERR) { # if SIG{__WARN__} is already captured, this carp isn't seen until # you read the capture that holds it carp "WARNING: STDERR already tied, unable to capture"; return; } return 1; } sub _stop { my $self = shift; untie *STDERR; $SIG{__WARN__} = $self->{'IO::Capture::handler_save'}; return 1; } 1; =head1 NAME C - Capture output from C and C =head1 SYNOPSYS # Generic example (Just to give the overall view) use IO::Capture::Stderr; my $capture = IO::Capture::ErrorMessages->new(); $capture->start(); print STDERR "Test Line One\n"; print STDERR "Test Line Two\n"; print STDERR "Test Line Three\n"; warn "Test line Four\n"; printf STDERR ("Test Line %08d\n", 5); $capture->stop(); $line = $capture->read; print "$line"; # prints "Test Line One" $line = $capture->read; print "$line"; # prints "Test Line Two" $capture->line_pointer(4); $line = $capture->read; print "$line"; # prints "Test Line Four" $current_line_position = $capture->line_pointer; # More useful example 1 - "Using in module tests" # Note: If you don't want to make users install # the IO::Capture module just for your tests, # you can just install in the t/lib directory # of your module and use the lib pragma in # your tests. use lib "t/lib"; use IO::Capture::ErrorMessages; use Test::More; my $capture = IO::Capture::ErrorMessages->new; $capture->start # execute with a bad parameter to make sure get # an error. ok( ! $test("Bad Parameter") ); $capture->stop(); # More useful example 2 - "Use with GUI like Tk" # If you are calling a CPAN module that may # print some messages that you don't want going # to the shell window, or being lost, you can # capture them and then put to a log file or # print in a text frame =head1 DESCRIPTION The module C, is derived from the abstract class in C. L It captures all output sent to STDERR and installs a signal handler to capture the output sent via the C function (and friends - such as C). We primarily use it in module tests, where the test will cause some warning to be printed. To keep the output from cluttering up the nice neat row of 'ok's. ;-) Note: This module won't work with the perl function, C, or any other operation involing a C. If you want to capture the output from a system command, it is faster to use C or backticks. my $output = `/usr/sbin/ls -l 2>&1`; =head1 METHODS =head1 AUTHORS Mark Reynolds reynolds@sgi.com Jon Morgan jmorgan@sgi.com =head1 COPYRIGHT Copyright (c) 2003, Mark Reynolds and Jon Morgan. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. =cut HTML-Template-2.97/t/testlib/IO/Capture/Tie_STDx.pm0000644000175000017500000000143613107402001017706 0ustar samsampackage IO::Capture::Tie_STDx; sub TIEHANDLE { my $class = shift; bless [], $class; } sub PRINTF { my $self = shift; my $format = shift; $self->PRINT( sprintf( $format, @_ ) ); } sub PRINT { my $self = shift; push @$self, join '',@_; } sub READLINE { my $self = shift; return wantarray ? @$self : shift @$self; } sub CLOSE { my $self = shift; return close $self; } =head1 NAME IO::Capture::Tie_STDx; =head1 SYNOPSIS use IO::Capture::Tie_STDx; tie *STDOUT, "IO::Capture::Tie_STDx"; @$messages = ; untie *STDOUT; =head1 DESCRIPTION The module C is a small utility module for use by C derived modules. See L It is used to tie STDOUT or STDERR. =cut 1; HTML-Template-2.97/t/testlib/IO/Capture/Stderr.pm0000644000175000017500000002144713107402001017532 0ustar samsampackage IO::Capture::Stderr; use strict; use warnings; use Carp; use base qw/IO::Capture/; use IO::Capture::Tie_STDx; sub _start { my $self = shift; $self->line_pointer(1); if ( _capture_warn_check() ) { $self->{'IO::Capture::handler_save'} = defined $SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT'; $SIG{__WARN__} = sub {print STDERR @_;}; } else { $self->{'IO::Capture::handler_save'} = undef; } tie *STDERR, "IO::Capture::Tie_STDx"; } sub _retrieve_captured_text { my $self = shift; my $messages = \@{$self->{'IO::Capture::messages'}}; @$messages = ; return 1; } sub _check_pre_conditions { my $self = shift; return unless $self->SUPER::_check_pre_conditions; if (tied *STDERR) { carp "WARNING: STDERR already tied, unable to capture"; return; } return 1; } sub _stop { my $self = shift; untie *STDERR; $SIG{__WARN__} = $self->{'IO::Capture::handler_save'} if defined $self->{'IO::Capture::handler_save'}; return 1; } # _capture_warn_check # # Check to see if SIG{__WARN__} handler should be set to direct output # from warn() to IO::Capture::Stderr. # There are three things to take into consideration. # # 1) Is the version of perl less than 5.8? # - Before 5.8, there was a bug that caused output from warn() # not to be sent to STDERR if it (STDERR) was tied. # So, we need to put a handler in to send warn() text to # STDERR so IO::Capture::Stderr will capture it. # 2) Is there a handler set already? # - The default handler for SIG{__WARN__} is to send to STDERR. # But, if it is set by the program, it may do otherwise, and # we don't want to break that. # 3) FORCE_CAPTURE_WARN => 1 # - To allow users to override a previous handler that was set on # SIG{__WARN__}, there is a variable that can be set. If set, # when there is a handler set on IO::Capture::Stderr startup, # it will be saved and a new hander set that captures output to # IO::Capture::Stderr. On stop, it will restore the programs # handler. # # # # Perl | FORCE_CAPTURE_WARN | Program has | Set our own # < 5.8 | is set | handler set | handler # --------+----------------------+----------------+------------ # | | | # --------+----------------------+----------------+------------ # X | | | X (1) # --------+----------------------+----------------+------------ # | X | | # --------+----------------------+----------------+------------ # X | X | | X (1) # --------+----------------------+----------------+------------ # | | X | # --------+----------------------+----------------+------------ # X | | X | # --------+----------------------+----------------+------------ # | X | X | X (2) # --------+----------------------+----------------+------------ # X | X | X | X (2) # --------+----------------------+----------------+------------ # (1) WAR to get around bug # (2) Replace programs handler with our own sub _capture_warn_check { my $self = shift; if (!defined $SIG{__WARN__} ) { return $^V lt v5.8 ? 1 : 0; } return $self->{'FORCE_CAPTURE_WARN'} ? 1 : 0; } 1; __END__ =head1 NAME C - Capture all output sent to C =head1 SYNOPSIS use IO::Capture::Stderr; $capture = IO::Capture::Stderr->new(); $capture->start(); # STDERR Output captured print STDERR "Test Line One\n"; print STDERR "Test Line Two\n"; print STDERR "Test Line Three\n"; $capture->stop(); # STDERR output sent to wherever it was before 'start' # In 'scalar context' returns next line $line = $capture->read; print "$line"; # prints "Test Line One" $line = $capture->read; print "$line"; # prints "Test Line Two" # move line pointer to line 1 $capture->line_pointer(1); $line = $capture->read; print "$line"; # prints "Test Line One" # Find out current line number $current_line_position = $capture->line_pointer; # In 'List Context' return an array(list) @all_lines = $capture->read; # Example 1 - "Using in module tests" # Note: If you don't want to make users install # the IO::Capture module just for your tests, # you can just install in the t/lib directory # of your module and use the lib pragma in # your tests. use lib "t/lib"; use IO::Capture:Stderr; use Test::More; # Create new capture object. Showing FORCE_CAPTURE_WARN being cleared # for example, but 0 is the default, so you don't need to specify # unless you want to set. my $capture = IO::Capture:Stderr->new( {FORCE_CAPTURE_WARN => 0} ); $capture->start # execute with a bad parameter to make sure get # an error. ok( ! $test("Bad Parameter") ); $capture->stop(); =head1 DESCRIPTION The module C, is derived from the abstract class C. See L. The purpose of the module (as the name suggests) is to capture any output sent to C. After the capture is stopped, the STDOUT filehandle will be reset to the previous location. E.g., If previously redirected to a file, when Cstop> is called, output will start going into that file again. Note: This module won't work with the perl function, system(), or any other operation involving a fork(). If you want to capture the output from a system command, it is faster to use open() or back-ticks. my $output = `/usr/sbin/ls -l 2>&1`; =head1 METHODS =head2 new =over 4 =item * Creates a new capture object. =item * An object can be reused as needed, so will only need to do one of these. =over 4 =item * Be aware, any data previously captured will be discarded if a new capture session is started. =back =back =head2 start =over 4 =item * Start capturing data into the C Object. =item * Can B be called on an object that is already capturing. =item * Can B be called while STDERR tied to an object. =item * C will be returned on an error. =back =head2 stop =over 4 =item * Stop capturing data and point STDERR back to it's previous output location I.e., untie STDERR =back =head2 read =over 4 =item * In I =over 4 =item * Lines are read from the buffer at the position of the C, and the pointer is incremented by one. $next_line = $capture->read; =back =item * In I =over 4 =item * The array is returned. The C is not affected. @buffer = $capture->read; =back =item * Data lines are returned exactly as they were captured. You may want to use C on them if you don't want the end of line character(s) while (my $line = $capture->read) { chomp $line; $cat_line = join '', $cat_line, $line; } =back =head2 line_pointer =over 4 =item * Reads or sets the C. my $current_line = $capture->line_pointer; $capture->line_pointer(1); =back =head1 ARGUMENTS Pass any arguments to new() in a single array reference. IO::Capture::Stderr->new( {FORCE_CAPTURE_WARN => 1} ); =head2 FORCE_CAPTURE_WARN =over 4 Normally, IO::Capture::Stderr will capture text from I function calls. This is because output from I is normally directed to STDERR. If you wish to force IO::Capture::Stderr to grab the text from I, set FORCE_CAPTURE_WARN to a 1. Then C will save the handle that C<$SIG{__WARN__}> was set to, redirect it to itself on C, and then set C<$SIG{__WARN__}> back after C is called. =back =head1 SUB-CLASSING =head2 Adding Features If you would like to sub-class this module to add a feature (method) or two, here is a couple of easy steps. Also see L. =over 4 =item 1 Give your package a name package MyPackage; =item 2 Use this C as your base class like this: package MyPackage; use base qw/IO::Capture::Stderr/; =item 3 Add your new method like this package MyPackage; use base qw/IO::Capture::Stderr/; sub grep { my $self = shift; for $line ( } =back =head1 See Also L L L =head1 AUTHORS Mark Reynolds reynolds@sgi.com Jon Morgan jmorgan@sgi.com =head1 COPYRIGHT Copyright (c) 2003, Mark Reynolds. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. =cut HTML-Template-2.97/t/testlib/IO/Capture/Stdout.pm0000644000175000017500000001232513107402001017544 0ustar samsampackage IO::Capture::Stdout; use Carp; use base qw/IO::Capture/; use IO::Capture::Tie_STDx; sub _start { my $self = shift; $self->line_pointer(1); tie *STDOUT, "IO::Capture::Tie_STDx"; } sub _retrieve_captured_text { my $self = shift; my $messages = \@{$self->{'IO::Capture::messages'}}; @$messages = ; #$self->line_pointer(1); return 1; } sub _check_pre_conditions { my $self = shift; return unless $self->SUPER::_check_pre_conditions; if (tied *STDOUT) { carp "WARNING: STDOUT already tied, unable to capture"; return; } return 1; } sub _stop { untie *STDOUT; } 1; =head1 NAME IO::Capture::Stdout - Capture any output sent to STDOUT =head1 SYNOPSIS # Generic example (Just to give the overall view) use IO::Capture::Stdout; $capture = IO::Capture::Stdout->new(); $capture->start(); # STDOUT Output captured print STDOUT "Test Line One\n"; print STDOUT "Test Line Two\n"; print STDOUT "Test Line Three\n"; $capture->stop(); # STDOUT output sent to wherever it was before 'start' # In 'scalar context' returns next line $line = $capture->read; print "$line"; # prints "Test Line One" $line = $capture->read; print "$line"; # prints "Test Line Two" # move line pointer to line 1 $capture->line_pointer(1); $line = $capture->read; print "$line"; # prints "Test Line One" # Find out current line number $current_line_position = $capture->line_pointer; # In 'List Context' return an array(list) @all_lines = $capture->read; # More useful example 1 - "Using in module tests" # Note: If you don't want to make users install # the IO::Capture module just for your tests, # you can just install in the t/lib directory # of your module and use the lib pragma in # your tests. use lib "t/lib"; use IO::Capture::Stdout; use Test::More; my $capture = IO::Capture::Stdout->new; $capture->start # execute with a bad parameter to make sure get # an error. ok( ! $test("Bad Parameter") ); $capture->stop(); =head1 DESCRIPTION The module C, is derived from the abstract class C. See L. The purpose of the module (as the name suggests) is to capture any output sent to C. After the capture is stopped, the STDOUT filehandle will be reset to the previous location. E.g., If previously redirected to a file, when Cstop> is called, output will start going into that file again. Note: This module won't work with the perl function, system(), or any other operation involving a fork(). If you want to capture the output from a system command, it is faster to use open() or back-ticks. my $output = `/usr/sbin/ls -l 2>&1`; =head1 METHODS =head2 new =over 4 =item * Creates a new capture object. =item * An object can be reused as needed, so will only need to do one of these. =over 4 =item * Be aware, any data previously captured will be discarded if a new capture session is started. =back =back =head2 start =over 4 =item * Start capturing data into the C Object. =item * Can B be called on an object that is already capturing. =item * Can B be called while STDOUT tied to an object. =item * C will be returned on an error. =back =head2 stop =over 4 =item * Stop capturing data and point STDOUT back to it's previous output location I.e., untie STDOUT =back =head2 read =over 4 =item * In I =over 4 =item * Lines are read from the buffer at the position of the C, and the pointer is incremented by one. $next_line = $capture->read; =back =item * In I =over 4 =item * The array is returned. The C is not affected. @buffer = $capture->read; =back =item * Data lines are returned exactly as they were captured. You may want to use C on them if you don't want the end of line character(s) while (my $line = $capture->read) { chomp $line; $cat_line = join '', $cat_line, $line; } =back =head2 line_pointer =over 4 =item * Reads or sets the C. my $current_line = $capture->line_pointer; $capture->line_pointer(1); =back =head1 SUB-CLASSING =head2 Adding Features If you would like to sub-class this module to add a feature (method) or two, here is a couple of easy steps. Also see L. =over 4 =item 1 Give your package a name package MyPackage; =item 2 Use this C as your base class like this: package MyPackage; use base qw/IO::Capture::Stdout/; =item 3 Add your new method like this package MyPackage; use base qw/IO::Capture::Stdout/; sub grep { my $self = shift; for $line ( } =back =head1 See Also L L L =head1 AUTHORS Mark Reynolds reynolds@sgi.com Jon Morgan jmorgan@sgi.com =head1 COPYRIGHT Copyright (c) 2003, Mark Reynolds. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. =cut HTML-Template-2.97/t/testlib/_Auxiliary.pm0000644000175000017500000000674513107402001016467 0ustar samsampackage _Auxiliary; # Contains auxiliary subroutines for testing of HTML::Template. # As of: Sat May 14 09:59:29 EDT 2005 use strict; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw( _setup_array_fh capture_template get_cache_key ); our %EXPORT_TAGS = (); =head1 NAME _Auxiliary - Miscellaneous subroutines used in HTML::Template test suite =head1 DESCRIPTION =head2 GENERAL The subroutines contained herein are used at various places in the HTML::Template test suite. Each is exported on demand only; there are no export tags permitting export of groups of these subroutines. In certain cases they exist only to eliminate duplicated code. In other cases they serve as wrappers around small functionalities drawn from other modules such as HTML::Template itself or IO::Capture::Stderr. =head2 C<_setup_array_fh> ($fh, $template_string, $template_array_ref) = _setup_array_fh('/path/to/some/file'); Reads the file specified by the argument and returns a list consisting of a filehandle, a string and a reference to an array, each of which are used to create dummy templates for testing in the cases where HTML::Template gets its source material from a filehandle, string or array, respectively. Currently used in F. =cut sub _setup_array_fh { my $file = shift; my ($fh, $template_string, @template_array); open $fh, $file or die "Couldn't open $file for reading: $!"; { local $/; $template_string = <$fh>; seek $fh, 0, 0; } @template_array = <$fh>; seek $fh, 0, 0; return ($fh, $template_string, \@template_array); } =head2 C $capture = IO::Capture::Stderr->new(); $template_args_ref = { path => ['templates/'], filename => 'simple.tmpl', cache => 1, cache_debug => 1, }; ($template, $cache_load_or_hit) = capture_template($capture, $template_args_ref); Used in conjunction with IO::Capture::Stderr to prepare for test which analyze data emitted by HTML::Template to standard error when certain debugging options are activated. Takes a list of two arguments: an IO::Capture::Stderr object and a reference to a hash holding the options to be passed to C. Returns a list of two arguments: an HTML::Template object and the (first) string printed to STDERR. The template can then be further used like any such HTML::Template, while the string may be tested in comparison with the expected debugging message. Currently used in F. =cut sub capture_template { my $capture = shift; my $template_args_ref = shift; $capture->start; my $template = HTML::Template->new( %{$template_args_ref}); $capture->stop; return ($template, $capture->read); } =head2 C ($template, $cache_load_or hit) = capture_template($capture, $template_args_ref); $cache_keys[0] = get_cache_key($cache_load_or_hit); Used to extract information from debugging messages for further testing. Takes a single argument of a string which is the STDERR message captured by IO::Capture::Stderr inside C above. Returns the last Perl 'word' in that string. Why the I word? Because that's where the cache key or cache file name currently appears in the error messages for those features in HTML::Template. Currently used in F. =cut sub get_cache_key { my @temp = split(/\s+/, +shift); return $temp[-1]; } 1; HTML-Template-2.97/t/08-cache-debug.t0000644000175000017500000000536713107402001015115 0ustar samsamuse strict; use warnings; use Test::More tests => 12; use File::Temp; use lib("./t/testlib"); use_ok('HTML::Template'); use_ok('IO::Capture::Stderr'); use_ok( '_Auxiliary', qw{ capture_template get_cache_key } ); my ($output, $template); my ($capture, $cache_load, $cache_hit, $template_args_ref); my (@cache_keys); my $tmp_dir = File::Temp->newdir(); $capture = IO::Capture::Stderr->new(); isa_ok($capture, 'IO::Capture::Stderr'); $template_args_ref = { path => ['templates/'], filename => 'simple.tmpl', cache => 1, cache_debug => 1, debug => 0, }; ($template, $cache_load) = capture_template($capture, $template_args_ref); like($cache_load, qr/### HTML::Template Cache Debug ### CACHE LOAD/, "cache_debug CACHE LOAD message printed"); $cache_keys[0] = get_cache_key($cache_load); $template->param(ADJECTIVE => sub { return 'v' . '1e' . '2r' . '3y' }); $output = $template->output; ($template, $cache_hit) = capture_template($capture, $template_args_ref); like($cache_hit, qr/### HTML::Template Cache Debug ### CACHE HIT/, "cache_debug CACHE HIT message printed"); $cache_keys[1] = get_cache_key($cache_hit); ok($output =~ /v1e2r3y/, "basic test of caching"); is($cache_keys[0], $cache_keys[1], "cache keys match as expected"); $template_args_ref = { path => ['templates/'], filename => 'simple.tmpl', file_cache_dir => $tmp_dir, file_cache => 1, cache_debug => 1, }; ($template, $cache_load) = capture_template($capture, $template_args_ref); like($cache_load, qr/### HTML::Template Cache Debug ### FILE CACHE LOAD/, "cache_debug FILE CACHE LOAD message printed"); $cache_keys[0] = get_cache_key($cache_load); $template->param(ADJECTIVE => sub { "3y" }); $output = $template->output; ($template, $cache_hit) = capture_template($capture, $template_args_ref); like($cache_hit, qr/### HTML::Template Cache Debug ### FILE CACHE HIT/, "cache_debug FILE CACHE HIT message printed"); $cache_keys[1] = get_cache_key($cache_hit); ok($output =~ /3y/, "output from file caching is as predicted"); is($cache_keys[0], $cache_keys[1], "cache keys match as expected"); =head1 NAME t/08-cache-debug.t =head1 OBJECTIVE The tests in this file automate testing of the validity of information printed to STDERR when the C option to C is turned on. The versions of these tests in F were "non automated," I, in order to assess their results, you would have had to turn the option on and visually inspect STDERR as the test were displayed on the terminal. Now the output is captured with subroutines based on CPAN module L. The relevant packages for that module have been placed in the F subdirectory. =cut HTML-Template-2.97/t/16-config.t0000644000175000017500000001575113107402001014230 0ustar samsamuse strict; use warnings; use Test::More ('no_plan'); use_ok('HTML::Template'); my %config = HTML::Template->config(); is_deeply( \%config, { 'associate' => [], 'blind_cache' => 0, 'cache' => 0, 'cache_debug' => 0, 'cache_lazy_loops' => 0, 'cache_lazy_vars' => 0, 'case_sensitive' => 0, 'debug' => 0, 'die_on_bad_params' => 1, 'die_on_missing_include' => 1, 'double_cache' => 0, 'double_file_cache' => 0, 'file_cache' => 0, 'file_cache_dir' => '', 'file_cache_dir_mode' => 448, 'filter' => [], 'force_untaint' => 0, 'global_vars' => 0, 'ipc_key' => 'TMPL', 'ipc_max_size' => 0, 'ipc_mode' => 438, 'ipc_segment_size' => 65536, 'loop_context_vars' => 0, 'max_includes' => 10, 'memory_debug' => 0, 'no_includes' => 0, 'open_mode' => '', 'path' => [], 'search_path_on_include' => 0, 'shared_cache' => 0, 'shared_cache_debug' => 0, 'stack_debug' => 0, 'strict' => 1, 'timing' => 0, 'utf8' => 0, 'vanguard_compatibility_mode' => 0 }, 'correct defaults' ); # no path so we shouldn't be able to find it my $tmpl = eval { HTML::Template->new(filename => 'utf8-test.tmpl') }; ok($@, 'exception thrown for not finding filename'); like($@, qr/file not found/, 'file not found'); # now try again after setting path via config HTML::Template->config(path => 'templates'); $tmpl = eval { HTML::Template->new(filename => 'utf8-test.tmpl') }; ok(!$@, 'no exception thrown'); isa_ok($tmpl, 'HTML::Template'); my $output = $tmpl->output; chomp($output); is(sprintf('%vd', $output), "195.164", 'no utf8 config set, so just bytes'); # now try again after setting utf8 via config() HTML::Template->config(utf8 => 1); $tmpl = eval { HTML::Template->new(filename => 'utf8-test.tmpl') }; ok(!$@, 'no exception thrown'); isa_ok($tmpl, 'HTML::Template'); $output = $tmpl->output; chomp($output); is($output, chr(228), 'correct UTF8 encoded character'); # make sure options pass down into loops HTML::Template->config(global_vars => 1, die_on_bad_params => 0); $tmpl = HTML::Template->new_scalar_ref(\' : :: '); $tmpl->param(foo => 'A', bar => [{baz => 'B', fiz => [{fuz => 'Z'},{fuz => 'Y'}]},{baz => 'C', flop => 'D', fiz => [{fuz => 'X', flo => 'D'}]}]); $output = $tmpl->output; is($output, 'A B:A B:A:ZB:A:Y C:A C:A:X ', 'options passed down into loops'); is($output, $tmpl->output, 'calling it twice results in the same thing'); # make sure the config hash has changed %config = HTML::Template->config(); is_deeply( \%config, { 'associate' => [], 'blind_cache' => 0, 'cache' => 0, 'cache_debug' => 0, 'cache_lazy_loops' => 0, 'cache_lazy_vars' => 0, 'case_sensitive' => 0, 'debug' => 0, 'die_on_bad_params' => 0, 'die_on_missing_include' => 1, 'double_cache' => 0, 'double_file_cache' => 0, 'file_cache' => 0, 'file_cache_dir' => '', 'file_cache_dir_mode' => 448, 'filter' => [], 'force_untaint' => 0, 'global_vars' => 1, 'ipc_key' => 'TMPL', 'ipc_max_size' => 0, 'ipc_mode' => 438, 'ipc_segment_size' => 65536, 'loop_context_vars' => 0, 'max_includes' => 10, 'memory_debug' => 0, 'no_includes' => 0, 'open_mode' => '', 'path' => ['templates'], 'search_path_on_include' => 0, 'shared_cache' => 0, 'shared_cache_debug' => 0, 'stack_debug' => 0, 'strict' => 1, 'timing' => 0, 'utf8' => 1, 'vanguard_compatibility_mode' => 0 }, 'correct changed defaults' ); # make sure that options passed to new() don't effect the global configs $tmpl = eval { HTML::Template->new(filename => 'utf8-test.tmpl', utf8 => 0) }; ok(!$@, 'no exception thrown'); isa_ok($tmpl, 'HTML::Template'); $output = $tmpl->output; chomp($output); is(sprintf('%vd', $output), "195.164", 'no utf8 config set, so just bytes'); # make sure the config hash hasn't changed %config = HTML::Template->config(); is_deeply( \%config, { 'associate' => [], 'blind_cache' => 0, 'cache' => 0, 'cache_debug' => 0, 'cache_lazy_loops' => 0, 'cache_lazy_vars' => 0, 'case_sensitive' => 0, 'debug' => 0, 'die_on_bad_params' => 0, 'die_on_missing_include' => 1, 'double_cache' => 0, 'double_file_cache' => 0, 'file_cache' => 0, 'file_cache_dir' => '', 'file_cache_dir_mode' => 448, 'filter' => [], 'force_untaint' => 0, 'global_vars' => 1, 'ipc_key' => 'TMPL', 'ipc_max_size' => 0, 'ipc_mode' => 438, 'ipc_segment_size' => 65536, 'loop_context_vars' => 0, 'max_includes' => 10, 'memory_debug' => 0, 'no_includes' => 0, 'open_mode' => '', 'path' => ['templates'], 'search_path_on_include' => 0, 'shared_cache' => 0, 'shared_cache_debug' => 0, 'stack_debug' => 0, 'strict' => 1, 'timing' => 0, 'utf8' => 1, 'vanguard_compatibility_mode' => 0 }, 'defaults unchanged' ); HTML-Template-2.97/t/07-double-file-cache.t0000644000175000017500000000311213107402001016177 0ustar samsamuse strict; use warnings; use Test::More (tests => 3); use Data::Dumper; use File::Temp; use_ok('HTML::Template'); my $tmp_dir = File::Temp->newdir(); my ($template, $output); # test file cache - non automated, requires turning on debug watching STDERR! $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', double_file_cache => 1, file_cache_dir => $tmp_dir, ); $template->param(ADJECTIVE => sub { "3y"; }); $output = $template->output; $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', double_file_cache => 1, file_cache_dir => $tmp_dir, ); ok($output =~ /3y/, "double_file_cache option provides expected output"); $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', cache => 1, ); $template->param(ADJECTIVE => sub { return 't' . 'i' . '1m' . '2e' . '3l' . '4y'; }); $output = $template->output; $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', double_file_cache => 1, file_cache_dir => $tmp_dir, ); ok($output =~ /ti1m2e3l4y/, "double_file_cache option provides expected output"); =head1 NAME t/07-double-file-cache.t =head1 OBJECTIVE Test the previous untested C option to C. $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', double_file_cache => 1, file_cache_dir => './blib/temp_cache_dir', ); =cut HTML-Template-2.97/t/12-query.t0000644000175000017500000000424713107402001014122 0ustar samsamuse strict; use Test::More qw(no_plan); use_ok('HTML::Template'); my $template = HTML::Template->new( path => 'templates', filename => 'query-test.tmpl', ); my @results = sort $template->query(); is_deeply(\@results, [qw(example_loop var)], 'no args, returns top level items'); is($template->query(name => 'var'), 'VAR', 'name for a variable'); ok(!$template->query(name => 'var2'), 'no name for a non existent var'); is($template->query(name => 'example_loop'), 'LOOP', 'name for a loop'); is($template->query(name => ['example_loop', 'bop']), 'VAR', 'name for a var inside a loop'); is($template->query(name => ['example_loop', 'example_inner_loop']), 'LOOP', 'name for a loop inside a loop'); is($template->query(name => ['example_loop', 'example_inner_loop', 'inner_bee']), 'VAR', 'name for a var inside a loop inside a loop'); @results = sort $template->query(loop => 'example_loop'); is_deeply(\@results, [qw(bee bop example_inner_loop)], 'loop on an outer loop'); @results = sort $template->query(loop => ['example_loop', 'example_inner_loop']); is_deeply(\@results, [qw(inner_bee inner_bop)], 'loop on an inner loop'); eval { $template->query(loop => 'var') }; ok($@ =~ /error/, 'loop on a var fails'); # another template $template = HTML::Template->new(path => 'templates', filename => 'query-test2.tmpl'); @results = sort $template->query(); is_deeply(\@results, [qw(loop_foo)], 'no args, returns only top level item'); is($template->query(name => 'loop_foo'), 'LOOP', 'name for a loop'); is($template->query(name => ['loop_foo', 'loop_bar']), 'LOOP', 'name for a loop inside a loop'); is($template->query(name => ['loop_foo', 'loop_bar', 'foo']), 'VAR', 'name for a var inside loop inside a loop'); is($template->query(name => ['loop_foo', 'loop_bar', 'bar']), 'VAR', 'name for a var inside loop inside a loop'); is($template->query(name => ['loop_foo', 'loop_bar', 'bash']), 'VAR', 'name for a var inside loop inside a loop'); @results = sort $template->query(loop => 'loop_foo'); is_deeply(\@results, [qw(loop_bar)], 'loop on a loop'); @results = sort $template->query(loop => ['loop_foo', 'loop_bar']); is_deeply(\@results, [qw(bar bash foo)], 'loop on an innner loop'); HTML-Template-2.97/t/15-comment.t0000644000175000017500000000172213107402001014415 0ustar samsamuse strict; use warnings; #use Test::More tests => 4; use Test::More skip_all => 'not implemented yet'; use_ok('HTML::Template'); # normal loop with values my $tmpl_string = 'Hello enemy friend'; my $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( name => 'Fred'); my $output = $template->output; is($output, 'Hello friend', 'simple comment'); # comment with a var next to it $tmpl_string = 'Hello enemy friend '; $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( name => 'Fred'); $output = $template->output; is($output, 'Hello friend Fred', 'comment with var'); # comment with a var in it $tmpl_string = 'Hello friend'; $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( name => 'Fred'); $output = $template->output; is($output, 'Hello friend', 'comment hiding var'); HTML-Template-2.97/t/06-file-cache-dir.t0000644000175000017500000000403113107402001015503 0ustar samsamuse strict; use warnings; use Test::More # qw(no_plan); tests => 4; use_ok('HTML::Template'); my ($template); eval { $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', # file_cache_dir => './blib/temp_cache_dir', file_cache_dir => '', file_cache => 1, #cache_debug => 1, #debug => 0, ); }; like($@, qr/^You must specify the file_cache_dir option/, "file_cache_dir option fails due to zero-length string"); eval { $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', file_cache_dir => './blib/temp_cache_dir', file_cache =>, # missing value; should generate error #cache_debug => 1, #debug => 0, ); }; like( $@, qr/HTML::Template->new\(\) called with odd number of option parameters - should be of the form option => value/, "odd number of arguments causes constructor to fail" ); eval { $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', file_cache_dir => './blib/temp_cache_dir', file_cache => undef, # 'undef' counts as a missing value; should generate error #cache_debug => 1, #debug => 0, ); }; like( $@, qr/HTML::Template->new\(\) called with odd number of option parameters - should be of the form option => value/, "odd number of arguments causes constructor to fail" ); =head1 NAME t/06-file-cache-dir.t =head1 OBJECTIVE Test edge cases in use of C and C options to constructor C. Example: test case where C option is set to C but a C value is provided; examine error message. =cut HTML-Template-2.97/t/04-type-source.t0000644000175000017500000000341113107402001015225 0ustar samsamuse strict; use warnings; use Test::More # qw(no_plan); tests => 5; BEGIN { use_ok('HTML::Template'); } my ($fh, $template_string, @template_array); my ($typetemplate, $stemplate, $atemplate, $fhtemplate); my ($output); open $fh, 'templates/simple.tmpl' or die "Couldn't open simple.tmpl for reading: $!"; { local $/; $template_string = <$fh>; seek $fh, 0, 0; } @template_array = <$fh>; seek $fh, 0, 0; # next is same as at t/99-old-test-pl.t line 48 $typetemplate = HTML::Template->new( type => 'filename', path => 'templates', source => 'simple.tmpl', debug => 0 ); # next 3 HTML::Template objects are same as above, only testing each # variant of the 'type' option $stemplate = HTML::Template->new( type => 'scalarref', source => \$template_string, debug => 0, ); $atemplate = HTML::Template->new( type => 'arrayref', source => \@template_array, debug => 0, ); $fhtemplate = HTML::Template->new( type => 'filehandle', source => $fh, debug => 0, ); for my $tmpl ($typetemplate, $stemplate, $atemplate, $fhtemplate,) { $tmpl->param('ADJECTIVE', 'very'); $output = $tmpl->output; ok( ($output !~ /ADJECTIVE/ and $tmpl->param('ADJECTIVE') eq 'very'), "'type-source' version of constructor functioning properly" ); } =head1 NAME t/04-type-source.t =head1 OBJECTIVE Test the 'type-source' style of constructor C. $stemplate = HTML::Template->new( type => 'scalarref', source => \$template_string, ); $atemplate = HTML::Template->new( type => 'arrayref', source => \@template_array, ); $fhtemplate = HTML::Template->new( type => 'filehandle', source => $fh, ); =cut HTML-Template-2.97/t/10-param.t0000644000175000017500000000436513107402001014054 0ustar samsamuse strict; use warnings; use Test::More (tests => 10); use_ok('HTML::Template'); my $tmpl_string = ""; my $template = HTML::Template->new_scalar_ref(\$tmpl_string); # test for non existing param eval { my $value = $template->param('FOOBAR') }; like( $@, qr/HTML::Template : Attempt to get nonexistent parameter/, "attempt to get nonexistent parameter caught with die_on_bad_params == 1" ); $template = HTML::Template->new_scalar_ref(\$tmpl_string, die_on_bad_params => 0); ok(!defined($template->param('FOOBAR')), "if bad params permitted, bad param results in undef"); $template->param('FOOBAR' => undef); ok(!defined($template->param('FOOBAR')), "undef param results in undef"); # test for bad call to ->param with non scalar/non-hashref arg # dha wants to send it a puppy eval { my $value = $template->param(bless ['FOOBAR'], "Puppy") }; like($@, qr/Single reference arg to param\(\) must be a hash-ref/, "Single reference arg to param() must be a hash-ref!"); # test for passing eval { $template->param(bless {'FOOBAR' => 42}, "Puppy") }; ok(!$@, "param() doesn't die with blessed hash as first arg"); # make sure we can't pass a reference to a reference eval { $template->param(\{}) }; like($@, qr/must be a hash-ref/i, 'reference to a hash-ref is still bad'); # odd number of params eval { my $value = $template->param('foo' => 1, 'bar') }; like($@, qr/You gave me an odd number of parameters to param/, "odd number of args to param"); # value is a reference to a reference $template = HTML::Template->new_scalar_ref(\''); eval { $template->param(foo => \{}) }; like($@, qr/a reference to a reference/i, 'trying to use a reference to a reference'); # setting multiple values, multiple calls $template = HTML::Template->new_scalar_ref(\' - '); $template->param(foo => 1, baz => 2); $template->param(bar => 2, baz => 3, frob => [{fooey => 'a', blah => 'b'}, {fooey => 'c', blah => 'd'}]); is($template->output, '1 2 3 a-b c-d ', 'can set multiple params at once'); =head1 NAME t/10-param.t =head1 OBJECTIVE Test edge cases in use of C. More tests will probably be added as we understand this function better. =cut HTML-Template-2.97/t/03-else_else_bug.t0000644000175000017500000000053213107402001015543 0ustar samsam use Test::More qw/no_plan/; use HTML::Template; my $text = qq{Before. 1. 2. 3. After.}; eval { my $template = HTML::Template->new(debug => 0, scalarref => \$text,); }; like($@, qr/found second tag/, "including 2 tags for one tmpl_if should throw an error"); HTML-Template-2.97/t/01-bad-args.t0000644000175000017500000000711613107402001014431 0ustar samsamuse strict; use Test::More qw(no_plan); # tests => 6; use_ok('HTML::Template'); my $tmpl; eval { $tmpl = HTML::Template->new() }; like($@, qr/\QHTML::Template->new called with multiple (or no) template sources specified!/, 'new() with no args dies'); eval { $tmpl = HTML::Template->new('file') }; like($@, qr/\QHTML::Template->new() called with odd number of option parameters/, 'new() with odd number of args dies'); eval { $tmpl = HTML::Template->new(type => 'filename') }; like($@, qr/\Qcalled with 'type' parameter set, but no 'source'!/, "new(type => 'filename') dies without source"); eval { $tmpl = HTML::Template->new(type => 'frobnitz', source => '../templates/simple.tmpl') }; like($@, qr/\Qtype parameter must be set to 'filename', 'arrayref', 'scalarref' or 'filehandle'!/, 'new() dies with invalid type'); eval { $tmpl = HTML::Template->new(filename => 'simple.tmpl', path => 'templates', associate => 'Class::With::No::Param'); }; like( $@, qr/called with associate option, containing object of type.*\Qwhich lacks a param() method!/, 'associate() object with no param() method' ); eval { $tmpl = HTML::Template->new(filename => 'simple.tmpl', path => 'templates', 'debug') }; like( $@, qr/\Qcalled with odd number of option parameters - should be of the form option => value/, 'new() called with option with no value' ); =head1 NAME t/01-bad-args.t =head1 OBJECTIVE Test whether constructor fails with appropriate messages if passed bad or missing arguments. =cut __END__ # Below this point are tests which ... use Test::Exception; # Applying Test::Exception to this case; # Note idiosyncratic syntax: # no parens surrounding block and test description; white space is optional # block holding method to be tested; # no comma between block and test description # test description dies_ok {$tmpl = HTML::Template->new()} 'new() with no args dies' ; dies_ok {HTML::Template->new()} 'new() with no args dies'; dies_ok{$tmpl = HTML::Template->new()} 'new() with no args dies' ; dies_ok{HTML::Template->new()} 'new() with no args dies'; # Customary Test::More syntax; parens around arguments to ok() are optional. ok(1, 'return a true value'); ok 1, 'return a true value'; throws_ok { $tmpl = HTML::Template->new('file') } qr/\QHTML::Template->new() called with odd number of option parameters/, 'new() with odd number of args dies'; throws_ok {$tmpl = HTML::Template->new(type => 'filename') } qr/\Qcalled with 'type' parameter set, but no 'source'!/, "new(type => 'filename') dies without source"; throws_ok { $tmpl = HTML::Template->new( type => 'frobnitz', source => '../templates/simple.tmpl' ) } qr/\Qtype parameter must be set to 'filename', 'arrayref', 'scalarref' or 'filehandle'!/, 'new() dies with invalid type'; throws_ok {$tmpl = HTML::Template->new(filename => 'simple.tmpl', path => 'templates', associate => 'Class::With::No::Param' ) } qr/called with associate option, containing object of type.*\Qwhich lacks a param() method!/, 'associate() object with no param() method'; throws_ok {$tmpl = HTML::Template->new( filename => 'simple.tmpl', path => 'templates', 'debug' ) } qr/\Qcalled with odd number of option parameters - should be of the form option => value/, 'new() called with option with no value'; HTML-Template-2.97/t/05-nested_global.t0000644000175000017500000000201013107402001015543 0ustar samsamuse Test::More qw/no_plan/; use HTML::Template; # test that global-vars works for loops within loops my $text = < Foo: END my $template = HTML::Template->new( scalarref => \$text, die_on_bad_params => 0, global_vars => 1 ); $template->param(outer => [{foo => 1, inner => [{hell => [{}]}]}]); my $output = $template->output; like($output, qr/Foo: 1/); # test another similar case my $text2 = < END $template = HTML::Template->new( scalarref => \$text2, die_on_bad_params => 0, global_vars => 1 ); $template->param(BLA => 'bla1'); $template->param(OUTER_LOOP => [{INNER_LOOP => [{INNER_LOOP2 => [{BLA4 => 'test'},]}]}]); $output = $template->output; like($output, qr/bla1.*bla1/s); HTML-Template-2.97/t/12-open_mode.t0000644000175000017500000000354313107402001014720 0ustar samsamuse strict; use warnings; use File::Temp qw(tempdir); use Test::More ($] < 5.007001 ? (skip_all => 'open_mode needs at least perl 5.7.1') : (tests => 5)); use_ok('HTML::Template'); my $cache_dir = tempdir(CLEANUP => 1); # test with raw encoding my $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', open_mode => '<:raw', ); my $output = $tmpl->output; is(sprintf('%vd', $output), "195.164.10", 'correct raw bytes'); # test with UTF-8 encoding $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', open_mode => '<:encoding(utf-8)', ); $output = $tmpl->output; chomp $output; is($output, chr(228), 'correct UTF8 encoded character'); # same as before, this time we test file_cache $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', open_mode => '<:encoding(utf-8)', cache => 0, file_cache => 1, file_cache_dir => $cache_dir, ); # trigger cache storage: $output = $tmpl->output; # this time it will implicitly read from the cache $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', open_mode => '<:encoding(utf-8)', cache => 0, file_cache => 1, file_cache_dir => $cache_dir, ); $output = $tmpl->output; chomp $output; is($output, chr(228), 'correct UTF8 encoded character from cache'); # this time it will implicitly read from the cache w/out open_mode # which means it won't be correct UTF8. $tmpl = HTML::Template->new( path => 'templates', filename => 'utf8-test.tmpl', cache => 0, file_cache => 1, file_cache_dir => $cache_dir, ); $output = $tmpl->output; chomp $output; is(sprintf('%vd', $output), "195.164", 'correct non-UTF8 bytes: different open_mode, no cache'); HTML-Template-2.97/t/05-blind-cache.t0000644000175000017500000000250113107402001015077 0ustar samsamuse strict; use warnings; use File::Copy; use File::Temp; use File::Spec::Functions qw(curdir catfile); use Test::More tests => 4; use_ok('HTML::Template'); # use a temp file for the one that changes my $tmp = File::Temp->new(UNLINK => 1, SUFFIX => '.tmpl'); ok(copy(catfile(curdir, 'templates', 'simple.tmpl'), $tmp), "copied simple.tmpl to temp file"); my ($output, $template); # test cache - non automated, requires turning on debug watching STDERR! $template = HTML::Template->new( filename => $tmp, blind_cache => 1, debug => 0, cache_debug => 0, ); $template->param(ADJECTIVE => sub { return 'v' . '1e' . '2r' . '3y'; }); $output = $template->output; sleep 1; # overwrite our temp file with a different template ok(copy(catfile(curdir, 'templates', 'simplemod.tmpl'), $tmp), "poured new content into template to test blind_cache"); $template = HTML::Template->new( filename => $tmp, blind_cache => 1, debug => 0, cache_debug => 0, ); ok($output =~ /v1e2r3y/, "output unchanged as expected"); =head1 NAME t/05-blind-cache.t =head1 OBJECTIVE Test the previously untested C option to constructor C. $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', blind_cache => 1, ); =cut HTML-Template-2.97/t/04-default_with_escape.t0000644000175000017500000000047013107402001016747 0ustar samsamuse Test::More qw/no_plan/; use HTML::Template; my $text = qq{Foo: }; my $template = HTML::Template->new( # debug => 1, # stack_debug => 1, scalarref => \$text, ); $template->param(foo => 1); my $output = $template->output; is($output, "Foo: 1"); HTML-Template-2.97/t/14-includes.t0000644000175000017500000001233013107402001014555 0ustar samsamuse strict; use warnings; use File::Temp; use Test::More (tests => 20); use_ok('HTML::Template'); # simple include my $tmpl_string = q|1 2 3 |; my $template = HTML::Template->new_scalar_ref(\$tmpl_string); my $output = $template->output; is(clean($output), '1 2 3 5 5 5', 'simple include'); # nested includes $tmpl_string = q|1 2 3 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5', 'nested includes'); # simple include w/path $tmpl_string = q|1 2 3 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string, path => 'templates'); $output = $template->output; is(clean($output), '1 2 3 5 5 5', 'simple include w/path'); # nested includes w/path $tmpl_string = q|1 2 3 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string, path => 'templates'); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5', 'nested includes w/path'); # multiple same includes $tmpl_string = q|1 2 3 6 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string); $output = $template->output; is(clean($output), '1 2 3 5 5 5 6 5 5 5', 'multiple same includes'); # multiple different includes $tmpl_string = q|1 2 3 6 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string); $output = $template->output; is(clean($output), '1 2 3 5 5 5 6 6 6 6', 'multiple different includes'); # multiple different includes w/path $tmpl_string = q|1 2 3 6 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string, path => 'templates'); $output = $template->output; is(clean($output), '1 2 3 5 5 5 6 6 6 6', 'multiple different includes w/path'); # multiple same nested includes $tmpl_string = q|1 2 3 6 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5 6 4 4 4 5 5 5', 'multiple same nested includes'); # multiple same nested includes w/path $tmpl_string = q|1 2 3 6 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string, path => 'templates'); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5 6 4 4 4 5 5 5', 'multiple same nested includes w/path'); # multiple different nested includes $tmpl_string = q|1 2 3 6 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5 6 5 5 5', 'multiple different nested includes'); # multiple different nested includes w/path $tmpl_string = q|1 2 3 6 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string, path => 'templates'); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5 6 5 5 5', 'multiple different nested includes w/path'); # lots of different nested includes $tmpl_string = q|1 2 3 6 7 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5 6 5 5 5 7 6 6 6', 'lots of different nested includes'); # lots of different nested includes w/path $tmpl_string = q|1 2 3 6 7 |; $template = HTML::Template->new_scalar_ref(\$tmpl_string, path => 'templates'); $output = $template->output; is(clean($output), '1 2 3 4 4 4 5 5 5 6 5 5 5 7 6 6 6', 'lots of different nested includes w/path'); # missing file $tmpl_string = q|1 2 3 4 5 6|; eval { HTML::Template->new_scalar_ref(\$tmpl_string) }; like($@, qr/Cannot open included file/i, 'missing included file'); # missing file with false die_on_missing_include $template = eval { HTML::Template->new_scalar_ref(\$tmpl_string, die_on_missing_include => 0) }; $output = $template->output; ok(!$@, 'didnt die'); is(clean($output), '1 2 3 4 5 6', 'missing include just gets ignored'); # missing include in a level down my $tmp = File::Temp->new(UNLINK => 1, SUFFIX => '.tmpl'); print $tmp $tmpl_string; close $tmp; $tmpl_string = "0 0 9 9"; eval { HTML::Template->new_scalar_ref(\$tmpl_string) }; like($@, qr/Cannot open included file/i, 'missing included file'); # missing include in a level down with false die_on_missing_include $template = eval { HTML::Template->new_scalar_ref(\$tmpl_string, die_on_missing_include => 0) }; $output = $template->output; ok(!$@, 'didnt die'); is(clean($output), '0 0 1 2 3 4 5 6 9 9', 'missing include in a level down just gets ignored'); sub clean { my $string = shift; $string =~ s/\s+/ /g; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } HTML-Template-2.97/t/author-pod-syntax.t0000644000175000017500000000050313107402001016132 0ustar samsam#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for testing by the author'); } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); HTML-Template-2.97/t/99-old-test-pl.t0000644000175000017500000006063313107402001015141 0ustar samsamuse strict; use Test::More qw(no_plan); use File::Temp; use_ok('HTML::Template'); my ($output, $template, $result); my $tmp_dir = File::Temp->newdir(); my $tmp_file = File::Temp->new(); # test a simple template $template = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', debug => 0 ); $template->param('ADJECTIVE', 'very'); $output = $template->output; ok($output !~ /ADJECTIVE/ and $template->param('ADJECTIVE') eq 'very'); # try something a bit larger $template = HTML::Template->new( path => 'templates', filename => 'medium.tmpl', # debug => 1, ); $template->param('ALERT', 'I am alert.'); $template->param('COMPANY_NAME', "MY NAME IS"); $template->param('COMPANY_ID', "10001"); $template->param('OFFICE_ID', "10103214"); $template->param('NAME', 'SAM I AM'); $template->param('ADDRESS', '101011 North Something Something'); $template->param('CITY', 'NEW York'); $template->param('STATE', 'NEw York'); $template->param('ZIP', '10014'); $template->param('PHONE', '212-929-4315'); $template->param('PHONE2', ''); $template->param('SUBCATEGORIES', 'kfldjaldsf'); $template->param('DESCRIPTION', "dsa;kljkldasfjkldsajflkjdsfklfjdsgkfld\nalskdjklajsdlkajfdlkjsfd\n\talksjdklajsfdkljdsf\ndsa;klfjdskfj"); $template->param('WEBSITE', 'http://www.assforyou.com/'); $template->param('INTRANET_URL', 'http://www.something.com'); $template->param('REMOVE_BUTTON', ""); $template->param('COMPANY_ADMIN_AREA', "Manage Office Administrators"); $template->param('CASESTUDIES_LIST', "adsfkljdskldszfgfdfdsgdsfgfdshghdmfldkgjfhdskjfhdskjhfkhdsakgagsfjhbvdsaj hsgbf jhfg sajfjdsag ffasfj hfkjhsdkjhdsakjfhkj kjhdsfkjhdskfjhdskjfkjsda kjjsafdkjhds kjds fkj skjh fdskjhfkj kj kjhf kjh sfkjhadsfkj hadskjfhkjhs ajhdsfkj akj fkj kj kj kkjdsfhk skjhadskfj haskjh fkjsahfkjhsfk ksjfhdkjh sfkjhdskjfhakj shiou weryheuwnjcinuc 3289u4234k 5 i 43iundsinfinafiunai saiufhiudsaf afiuhahfwefna uwhf u auiu uh weiuhfiuh iau huwehiucnaiuncianweciuninc iuaciun iucniunciunweiucniuwnciwe" ); $template->param('NUMBER_OF_CONTACTS', "aksfjdkldsajfkljds"); $template->param('COUNTRY_SELECTOR', "klajslkjdsafkljds"); $template->param('LOGO_LINK', "dsfpkjdsfkgljdsfkglj"); $template->param('PHOTO_LINK', "lsadfjlkfjdsgkljhfgklhasgh"); $output = $template->output; ok($output !~ /new( path => 'templates', filename => 'simple-loop.tmpl', # debug => 1, ); $template->param('ADJECTIVE_LOOP', [{ADJECTIVE => 'really'}, {ADJECTIVE => 'very'}]); $output = $template->output; ok($output !~ /ADJECTIVE_LOOP/ and $output =~ /really.*very/s); # test a simple loop template $template = HTML::Template->new( path => 'templates', filename => 'simple-loop-nonames.tmpl', # debug => 1, ); $template->param('ADJECTIVE_LOOP', [{ADJECTIVE => 'really'}, {ADJECTIVE => 'very'}]); $output = $template->output; ok($output !~ /ADJECTIVE_LOOP/ and $output =~ /really.*very/s); # test a long loop template - mostly here to use timing on. $template = HTML::Template->new( path => 'templates', filename => 'long_loops.tmpl', # debug => 1, ); $output = $template->output; ok(1); # test a template with TMPL_INCLUDE $template = HTML::Template->new( path => 'templates', filename => 'include.tmpl', # debug => 1, ); $output = $template->output; ok(not(!($output =~ /5/) || !($output =~ /6/))); # test a template with TMPL_INCLUDE and cacheing. $template = HTML::Template->new( path => 'templates', filename => 'include.tmpl', cache => 1, # cache_debug => 1, # debug => 1, ); $output = $template->output; ok(not(!($output =~ /5/) || !($output =~ /6/))); # stimulates a cache miss # system('touch templates/included2.tmpl'); my $template2 = HTML::Template->new( path => 'templates', filename => 'include.tmpl', cache => 1, # cache_debug => 1, # debug => 1, ); $output = $template->output; ok(not(!($output =~ /5/) || !($output =~ /6/))); # test associate my $template_one = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', # debug => 1, ); $template_one->param('ADJECTIVE', 'very'); my $template_two = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', associate => $template_one, # debug => 1, ); $output = $template_two->output; ok($output !~ /ADJECTIVE/ and $output =~ /very/); # test a simple loop template my $template_l = HTML::Template->new( path => 'templates', filename => 'other-loop.tmpl', # debug => 1, ); # $template_l->param('ADJECTIVE_LOOP', [ { ADJECTIVE => 'really' }, { ADJECTIVE => 'very' } ] ); $output = $template_l->output; ok($output !~ /INSIDE/); # test a simple if template my $template_i = HTML::Template->new( path => 'templates', filename => 'if.tmpl', # debug => 1, ); # $template_l->param('ADJECTIVE_LOOP', [ { ADJECTIVE => 'really' }, { ADJECTIVE => 'very' } ] ); $output = $template_i->output; ok($output !~ /INSIDE/); # test a simple if template my $template_i2 = HTML::Template->new( path => 'templates', filename => 'if.tmpl', # stack_debug => 1, # debug => 1, ); $template_i2->param(BOOL => 1); $output = $template_i2->output; ok($output =~ /INSIDE/); # test a simple if/else template my $template_ie = HTML::Template->new( path => 'templates', filename => 'ifelse.tmpl', # debug => 1, ); $output = $template_ie->output; ok($output =~ /INSIDE ELSE/); # test a simple if/else template my $template_ie2 = HTML::Template->new( path => 'templates', filename => 'ifelse.tmpl', # debug => 1, ); $template_ie2->param(BOOL => 1); $output = $template_ie2->output; ok($output =~ /INSIDE IF/ and $output !~ /INSIDE ELSE/); # test a bug involving two loops with the same name $template = HTML::Template->new( path => 'templates', filename => 'double_loop.tmpl', # debug => 1, ); $template->param('myloop', [{var => 'first'}, {var => 'second'}, {var => 'third'}]); $output = $template->output; ok($output =~ /David/); # test escapeing $template = HTML::Template->new( path => 'templates', filename => 'html-escape.tmpl', # debug => 1, ); $template->param(STUFF => '<>"\''); #" $output = $template->output; ok($output !~ /[<>"']/); #" # test a simple template, using new param() call format $template = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', # debug => 1, ); $template->param({'ADJECTIVE' => 'very'}); $output = $template->output; ok($output !~ /ADJECTIVE/ and $output =~ /very/); # test a recursively including template eval { $template = HTML::Template->new( path => 'templates', filename => 'recursive.tmpl', ); $output = $template->output; }; ok(defined($@) and ($@ =~ /recursive/)); # test a template using unless $template = HTML::Template->new( path => 'templates', filename => 'unless.tmpl', # debug => 1 ); $template->param(BOOL => 1); $output = $template->output; ok($output !~ /INSIDE UNLESS/ and $output =~ /INSIDE ELSE/); # test a template using unless $template = HTML::Template->new( path => 'templates', filename => 'unless.tmpl', #debug => 1, #debug_stack => 1 ); $template->param(BOOL => 0); $output = $template->output; ok($output =~ /INSIDE UNLESS/ and $output !~ /INSIDE ELSE/); # test a template using loop_context_vars $template = HTML::Template->new( path => 'templates', filename => 'context.tmpl', loop_context_vars => 1, #debug => 1, #debug_stack => 1 ); $template->param(FRUIT => [{KIND => 'Apples'}, {KIND => 'Oranges'}, {KIND => 'Brains'}, {KIND => 'Toes'}, {KIND => 'Kiwi'}]); $template->param(PINGPONG => [{}, {}, {}, {}, {}, {}]); $output = $template->output; ok($output =~ /Apples, Oranges, Brains, Toes, and Kiwi./ and $output =~ /pingpongpingpongpingpong/); $template = HTML::Template->new( path => 'templates', filename => 'loop-if.tmpl', #debug => 1, #debug_stack => 1 ); $output = $template->output; ok($output =~ /Loop not filled in/); $template = HTML::Template->new( path => 'templates', filename => 'loop-if.tmpl', #debug => 1, #debug_stack => 1 ); $template->param(LOOP_ONE => [{VAR => "foo"}]); $output = $template->output; ok($output !~ /Loop not filled in/); # test shared memory - enable by setting the environment variable # TEST_SHARED_MEMORY to 1. SKIP: { skip "Skipping shared memory cache test. See README to enable\n", 2 if (!exists($ENV{TEST_SHARED_MEMORY}) or !$ENV{TEST_SHARED_MEMORY}); require 'IPC/SharedCache.pm'; my $template_prime = HTML::Template->new( filename => 'simple-loop.tmpl', path => ['templates/'], shared_cache => 1, ipc_key => 'TEST', #cache_debug => 1, ); my $template = HTML::Template->new( filename => 'simple-loop.tmpl', path => ['templates/'], shared_cache => 1, ipc_key => 'TEST', #cache_debug => 1, ); $template->param('ADJECTIVE_LOOP', [{ADJECTIVE => 'really'}, {ADJECTIVE => 'very'}]); $output = $template->output; ok($output !~ /ADJECTIVE_LOOP/ and $output =~ /really.*very/s); my $template_prime2 = HTML::Template->new( filename => 'simple-loop.tmpl', path => ['templates/'], double_cache => 1, ipc_key => 'TEST', #cache_debug => 1, ); my $template2 = HTML::Template->new( filename => 'simple-loop.tmpl', path => ['templates/'], double_cache => 1, ipc_key => 'TEST', #cache_debug => 1, ); $template->param('ADJECTIVE_LOOP', [{ADJECTIVE => 'really'}, {ADJECTIVE => 'very'}]); $output = $template->output; ok($output !~ /ADJECTIVE_LOOP/ and $output =~ /really.*very/s); IPC::SharedCache::remove('TEST'); } # test CGI associate bug eval { require 'CGI.pm'; }; SKIP: { skip "Skipping associate tests, need CGI.pm to test associate\n", 1 if ($@); my $query = CGI->new(''); $query->param('AdJecTivE' => 'very'); $template = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', debug => 0, associate => $query, ); $output = $template->output; ok($output =~ /very/); } # test subroutine as VAR $template = HTML::Template->new( path => 'templates', filename => 'simple.tmpl', debug => 0, ); $template->param(ADJECTIVE => sub { return 'v' . '1e' . '2r' . '3y'; }); $output = $template->output; ok($output =~ /v1e2r3y/); # test cache - non automated, requires turning on debug watching STDERR! $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', cache => 1, # cache_debug => 1, debug => 0, ); $template->param(ADJECTIVE => sub { return 'v' . '1e' . '2r' . '3y'; }); $output = $template->output; $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', cache => 1, # cache_debug => 1, debug => 0, ); ok($output =~ /v1e2r3y/); # test URL escapeing $template = HTML::Template->new( path => 'templates', filename => 'urlescape.tmpl', # debug => 1, # stack_debug => 1, ); $template->param(STUFF => '<>"; %FA'); #" $output = $template->output; ok($output !~ /[<>"]/); #" # test query() $template = HTML::Template->new( path => 'templates', filename => 'query-test.tmpl', ); my %params = map { $_ => 1 } $template->query(loop => 'EXAMPLE_LOOP'); my @result; eval { @result = $template->query(loop => ['EXAMPLE_LOOP', 'BEE']); }; ok( $@ =~ /error/ and $template->query(name => 'var') eq 'VAR' and $template->query(name => 'EXAMPLE_LOOP') eq 'LOOP' and exists $params{bee} and exists $params{bop} and exists $params{example_inner_loop} and $template->query(name => ['EXAMPLE_LOOP', 'EXAMPLE_INNER_LOOP']) eq 'LOOP'); # test query() $template = HTML::Template->new( path => 'templates', filename => 'query-test2.tmpl', ); my %p = map { $_ => 1 } $template->query(loop => ['LOOP_FOO', 'LOOP_BAR']); ok(exists $p{foo} and exists $p{bar} and exists $p{bash}); # test global_vars $template = HTML::Template->new( path => 'templates', filename => 'globals.tmpl', global_vars => 1, ); $template->param(outer_loop => [{loop => [{'LOCAL' => 'foo'}]}]); $template->param(global => 'bar'); $template->param(hidden_global => 'foo'); $result = $template->output(); ok($result =~ /foobar/); $template = HTML::Template->new( path => 'templates', filename => 'vanguard1.tmpl', vanguard_compatibility_mode => 1, ); $template->param(FOO => 'bar'); $template->param(BAZ => 'bop'); $result = $template->output(); ok($result =~ /bar/ and $result =~ /bop/); $template = HTML::Template->new( path => 'templates', filename => 'loop-context.tmpl', loop_context_vars => 1, ); $template->param(TEST_LOOP => [{NUM => 1}]); $result = $template->output(); ok($result =~ /1:FIRST::LAST:ODD/); # test a TMPL_INCLUDE from a later path directory back up to an earlier one # when using the search_path_on_include option $template = HTML::Template->new( path => ['templates/searchpath/', 'templates/'], search_path_on_include => 1, filename => 'include.tmpl', ); $output = $template->output; ok($output =~ /9/ and $output =~ /6/); # test no_includes eval { $template = HTML::Template->new(path => ['templates/'], filename => 'include.tmpl', no_includes => 1,); }; ok(defined $@ and $@ =~ /no_includes/); # test file cache - non automated, requires turning on debug watching STDERR! $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', file_cache_dir => $tmp_dir, file_cache => 1, #cache_debug => 1, #debug => 0, ); $template->param(ADJECTIVE => sub { "3y"; }); $output = $template->output; $template = HTML::Template->new( path => ['templates/'], filename => 'simple.tmpl', file_cache_dir => $tmp_dir, file_cache => 1, #cache_debug => 1, #debug => 0, ); ok($output =~ /3y/); my $x; $template = HTML::Template->new( filename => 'templates/simple-loop.tmpl', filter => { sub => sub { $x = 1; for (@{$_[0]}) { $_ = "$x : $_"; $x++; } }, format => 'array', }, file_cache_dir => $tmp_dir, file_cache => 1, global_vars => 1, ); $template->param('ADJECTIVE_LOOP', [{ADJECTIVE => 'really'}, {ADJECTIVE => 'very'}]); $output = $template->output; ok($output =~ /very/); $template = HTML::Template->new(filename => './templates/include_path/a.tmpl'); $output = $template->output; ok($output =~ /Bar/); open(OUT, ">$tmp_file") or die $!; $template = HTML::Template->new(filename => './templates/include_path/a.tmpl'); $template->output(print_to => *OUT); close(OUT); open(OUT, "<$tmp_file") or die $!; $output = join('', ); close(OUT); ok($output =~ /Bar/); my $test = 39; # test with case sensitive params on my $template_source = < simple template. END_OF_TMPL $template = HTML::Template->new( scalarref => \$template_source, case_sensitive => 1, debug => 0 ); $template->param('adverb', 'very'); $template->param('ADVERB', 'painfully'); $output = $template->output; ok( $output !~ /ADVERB/i and $template->param('ADVERB') eq 'painfully' and $template->param('adverb') eq 'very' and $output =~ /very painfully/); # test with case sensitive params off $template_source = < simple template. END_OF_TMPL $template = HTML::Template->new( scalarref => \$template_source, case_sensitive => 0, debug => 0 ); $template->param('adverb', 'very'); $template->param('ADVERB', 'painfully'); $output = $template->output; ok( $output !~ /ADVERB/i and $template->param('ADVERB') eq 'painfully' and $template->param('adverb') eq 'painfully' and $output =~ /painfully painfully/); $template = HTML::Template->new( filename => './templates/include_path/a.tmpl', filter => sub { ${$_[0]} =~ s/Bar/Zanzabar/g; } ); $output = $template->output; ok($output =~ /Zanzabar/); $template = HTML::Template->new( filename => './templates/include_path/a.tmpl', filter => [ { sub => sub { ${$_[0]} =~ s/Bar/Zanzabar/g; }, format => 'scalar' }, { sub => sub { ${$_[0]} =~ s/bar/bar!!!/g; }, format => 'scalar' } ] ); $output = $template->output; ok($output =~ /Zanzabar!!!/); $template = HTML::Template->new( filename => './templates/include_path/a.tmpl', filter => { sub => sub { $x = 1; for (@{$_[0]}) { $_ = "$x : $_"; $x++; } }, format => 'array', } ); $output = $template->output; ok($output =~ /1 : Foo/); $template = HTML::Template->new(scalarref => \"\n",); $template->param(ADJECTIVE => "3y"); $output = $template->output(); ok($output =~ /3y/); $template = HTML::Template->new( path => ['templates'], filename => 'newline_test1.tmpl', filter => sub { }, ); $output = $template->output(); ok($output =~ /STARTincludeEND/); # test multiline tags $template = HTML::Template->new( path => ['templates'], filename => 'multiline_tags.tmpl', global_vars => 1, ); $template->param(FOO => 'foo!', bar => [{}, {}]); $output = $template->output(); ok($output =~ /foo!\n/); ok($output =~ /foo!foo!\nfoo!foo!/); # test new() from filehandle open(TEMPLATE, "templates/simple.tmpl"); $template = HTML::Template->new(filehandle => *TEMPLATE); $template->param('ADJECTIVE', 'very'); $output = $template->output; ok($output !~ /ADJECTIVE/ and $template->param('ADJECTIVE') eq 'very'); close(TEMPLATE); # test new_() from filehandle open(TEMPLATE, "templates/simple.tmpl"); $template = HTML::Template->new_filehandle(*TEMPLATE); $template->param('ADJECTIVE', 'very'); $output = $template->output; ok($output !~ /ADJECTIVE/ and $template->param('ADJECTIVE') eq 'very'); close(TEMPLATE); # test case sensitive loop variables $template = HTML::Template->new( path => ['templates'], filename => 'case_loop.tmpl', case_sensitive => 1, ); $template->param(loop => [{foo => 'bar', FOO => 'BAR'}]); $output = $template->output(); ok($output =~ /bar BAR/); # test ifs with code refd $template = HTML::Template->new( path => ['templates'], filename => 'if.tmpl' ); $template->param(bool => sub { 0 }); $output = $template->output(); ok($output !~ /INSIDE/ and $output =~ /unless/); # test global_vars for loops within loops $template = HTML::Template->new( path => ['templates'], filename => 'global-loops.tmpl', global_vars => 1 ); $template->param(global => "global val"); $template->param( outer_loop => [ { foo => 'foo val 1', inner_loop => [{bar => 'bar val 1'}, {bar => 'bar val 2'},], }, { foo => 'foo val 2', inner_loop => [{bar => 'bar val 3'}, {bar => 'bar val 4'},], } ] ); $output = $template->output; ok($output =~ /inner loop foo: foo val 1/ and $output =~ /inner loop foo: foo val 2/); # test nested include path handling $template = HTML::Template->new( path => ['templates'], filename => 'include_path/one.tmpl' ); $output = $template->output; ok($output =~ /ONE/ and $output =~ /TWO/ and $output =~ /THREE/); # test using HTML_TEMPLATE_ROOT with path { local $ENV{HTML_TEMPLATE_ROOT} = "templates"; $template = HTML::Template->new( path => ['searchpath'], filename => 'three.tmpl', ); $output = $template->output; ok($output =~ /THREE/); } # test __counter__ $template = HTML::Template->new( path => ['templates'], filename => 'counter.tmpl', loop_context_vars => 1 ); $template->param(foo => [{a => 'a'}, {a => 'b'}, {a => 'c'}]); $template->param(outer => [{inner => [{a => 'a'}, {a => 'b'}, {a => 'c'}]}, {inner => [{a => 'x'}, {a => 'y'}, {a => 'z'}]},]); $output = $template->output; ok($output =~ /^1a2b3c$/m); ok($output =~ /^11a2b3c21x2y3z$/m); # test default $template = HTML::Template->new( path => ['templates'], filename => 'default.tmpl' ); $template->param(cl => 'clothes'); $template->param(start => 'start'); $output = $template->output; ok($output =~ /cause it's getting hard to think, and my clothes are starting to shrink/); # test invalid eval { my $template = HTML::Template->new(scalarref => \''); }; ok($@ =~ /No NAME given/); # test a case where a different path should stimulate a cache miss # even though the main template is the same $template = HTML::Template->new( path => ['templates', 'templates/include_path'], filename => 'outer.tmpl', search_path_on_include => 1, cache => 1, # cache_debug => 1, ); $output = $template->output; ok($output =~ /I AM OUTER/); ok($output =~ /I AM INNER 1/); $template = HTML::Template->new( path => ['templates', 'templates/include_path2'], filename => 'outer.tmpl', search_path_on_include => 1, cache => 1, # cache_debug => 1, ); $output = $template->output; ok($output =~ /I AM OUTER/); ok($output =~ /I AM INNER 2/); # try the same thing with the file cache $template = HTML::Template->new( path => ['templates', 'templates/include_path'], filename => 'outer.tmpl', search_path_on_include => 1, file_cache_dir => $tmp_dir, file_cache => 1, # cache_debug => 1, ); $output = $template->output; ok($output =~ /I AM OUTER/); ok($output =~ /I AM INNER 1/); $template = HTML::Template->new( path => ['templates', 'templates/include_path2'], filename => 'outer.tmpl', search_path_on_include => 1, file_cache_dir => $tmp_dir, file_cache => 1, # cache_debug => 1, ); $output = $template->output; ok($output =~ /I AM OUTER/); ok($output =~ /I AM INNER 2/); # test javascript escaping $template = HTML::Template->new( path => ['templates'], filename => 'js.tmpl' ); $template->param(msg => qq{"He said 'Hello'.\n\r"}); $output = $template->output(); is($output, q{\\"He said \\'Hello\\'.\\n\\r\\"}); # test empty filename eval { $template = $template = HTML::Template->new(path => ['templates'], filename => ''); }; like($@, qr/empty filename/); # test default escaping ok(!exists $template->{options}->{default_escape}, "default default_escape"); $template = HTML::Template->new( path => ['templates'], filename => 'default_escape.tmpl', default_escape => 'UrL' ); is($template->{options}->{default_escape}, 'URL'); $template->param(STUFF => q{Joined with space}); $output = $template->output(); like($output, qr{^Joined%20with%20space}); $template = HTML::Template->new( path => ['templates'], filename => 'default_escape_off.tmpl', default_escape => 'UrL' ); is($template->{options}->{default_escape}, 'URL'); $template->param(STUFF => q{Joined with space}); $output = $template->output(); like($output, qr{^Joined with space}); $template = HTML::Template->new( path => ['templates'], filename => 'default_escape.tmpl', default_escape => 'html' ); $template->param(STUFF => q{Joined&with"cruft}); $template->param(LOOP => [{MORE_STUFF => '<&>'}, {MORE_STUFF => '>&<'}]); $template->param(a => ''); $output = $template->output(); like($output, qr{^Joined&with"cruft}); like($output, qr{<&>>&<}); like($output, qr{because it's <b>}); eval { $template = HTML::Template->new(path => ['templates'], filename => 'default_escape.tmpl', default_escape => 'wml'); }; like($@, qr/Invalid setting for default_escape/); HTML-Template-2.97/t/04-default-escape.t0000644000175000017500000000075313107402001015636 0ustar samsamuse strict; use Test::More; use HTML::Template; { my $t = HTML::Template->new( scalarref => \'', default_escape => 'html', ); $t->param( foo => '<' ); is( $t->output, '<', "test default_escape => 'html'"); } { my $t = HTML::Template->new( scalarref => \'', default_escape => 'none', ); $t->param( foo => '<' ); is( $t->output, '<', "test default_escape => 'none'"); } done_testing(); HTML-Template-2.97/t/13-loop-repeated.t0000644000175000017500000000567413107402001015523 0ustar samsamuse strict; use warnings; use Test::More (tests => 7); use_ok('HTML::Template'); # normal loop with values my $tmpl_string = ': '; my $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( foo => [{a => 1, b =>2}, {a => 3, b => 4}]); my $output = $template->output; is(clean($output), '1:2 3:4', 'normal loop'); # repeated loop with same vars $tmpl_string = ': : '; $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( foo => [{a => 1, b =>2}, {a => 3, b => 4}]); $output = $template->output; is(clean($output), '1:2 3:4 1:2 3:4', 'repeated loop, same vars'); # repeated loop with different vars: more in 1st $tmpl_string = ': :0 '; $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( foo => [{a => 1, b =>2}, {a => 3, b => 4}]); $output = $template->output; is(clean($output), '1:2 3:4 1:0 3:0', 'repeated loop, different vars, more in 1st'); # repeated loop with different vars: more in 2nd $tmpl_string = ':0 : '; $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( foo => [{a => 1, b =>2}, {a => 3, b => 4}]); $output = $template->output; is(clean($output), '1:0 3:0 1:2 3:4', 'repeated loop, different vars, more in 2nd'); # repeat loop 3 times with different vars in each $tmpl_string = ':0 : : '; $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( foo => [{a => 1, b =>2, c => 3}, {a => 3, b => 4, c => 5}]); $output = $template->output; is(clean($output), '1:0 3:0 1:2 3:4 2:3 4:5', 'repeated loop 3x, different vars'); # repeat loop 3 times with different vars and conditionals $tmpl_string = q| :0 ?! : !? : |; $template = HTML::Template->new_scalar_ref( \$tmpl_string ); $template->param( foo => [{a => 1, b =>2, c => 3, d => 1}, {a => 3, b => 4, c => 5, e => 1}]); $output = $template->output; is(clean($output), '1:0 3:0 ? 1:2 ! 3:4 ? 2:3 ! 4:5', 'repeated loop 3x, w/conditionals'); sub clean { my $string = shift; $string =~ s/\s+/ /g; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } =head1 NAME t/13-loop-boolean.t =head1 OBJECTIVE Provide a test to show that loops (full or empty) should be able to be used as booleans in a TMPL_IF along with using an empty loop. =cut HTML-Template-2.97/t/09-caching-precluded.t0000644000175000017500000000432513107402001016321 0ustar samsamuse strict; use warnings; use Test::More # qw(no_plan); tests => 4; use_ok('HTML::Template'); my ($fh, $template_string, @template_array); my ($template); my ($type, $cache_option); open $fh, 'templates/simple.tmpl' or die "Couldn't open simple.tmpl for reading: $!"; { local $/; $template_string = <$fh>; seek $fh, 0, 0; } @template_array = <$fh>; seek $fh, 0, 0; test_caching_precluded('scalarref', \$template_string, 'cache'); test_caching_precluded('arrayref', \@template_array, 'double_cache'); test_caching_precluded('filehandle', $fh, 'file_cache'); sub test_caching_precluded { my ($type, $source, $cache_option) = @_; my ($template); eval { $template = HTML::Template->new(type => $type, source => $source, $cache_option => 1,); }; like($@, qr/Cannot have caching when template source is not file/, "Cannot have caching when template source is not file"); } =head1 NAME t/09-caching-precluded.t =head1 OBJECTIVE In HTML::Template v2.7, it was in principle possible to pass to the constructor an option which called for caching even in cases where the template source was I a file. $template = HTML::Template->new( type => 'scalarref', source => \$template_string, cache => 1, ); The documentation indicated it was not possible to cache results coming from a filehandle, string or array, but the module itself did not handle a violation of this rule cleanly. If you attempted to construct an HTML::Template object such as the example above, you would get three distinct and confusing error messages. Phalanx has modified C to preclude the possibility of any of the six cache options having a true value if the template source is a filehandle, string or array. The constructor now does additional error-checking and, if a violation is found, the program dies and an appropriate error message is emitted via C and analyzed. =cut __END__ #use lib("./t/testlib"); #use_ok('_Auxiliary', qw{ # test_caching_precluded #}); # my ($warn, $template); # local $SIG{__WARN__} = sub {$warn = $_[0]}; # like( $warn, # qr/$cache_option option automatically reset to zero when template source is not file/, HTML-Template-2.97/Makefile.PL0000644000175000017500000000236213107402001014053 0ustar samsam# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.043. use strict; use warnings; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "Perl module to use HTML-like templating language", "AUTHOR" => "Michael Peters ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "HTML-Template", "LICENSE" => "perl", "NAME" => "HTML::Template", "PREREQ_PM" => { "CGI" => 0, "Carp" => 0, "Digest::MD5" => 0, "File::Spec" => "0.82", "Scalar::Util" => 0 }, "TEST_REQUIRES" => { "File::Temp" => 0, "Test::More" => 0, "Test::Pod" => 0 }, "VERSION" => "2.97", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "CGI" => 0, "Carp" => 0, "Digest::MD5" => 0, "File::Spec" => "0.82", "File::Temp" => 0, "Scalar::Util" => 0, "Test::More" => 0, "Test::Pod" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); HTML-Template-2.97/META.yml0000644000175000017500000000131213107402001013344 0ustar samsam--- abstract: 'Perl module to use HTML-like templating language' author: - 'Michael Peters ' build_requires: File::Temp: '0' Test::More: '0' Test::Pod: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 5.043, CPAN::Meta::Converter version 2.150005' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: HTML-Template requires: CGI: '0' Carp: '0' Digest::MD5: '0' File::Spec: '0.82' Scalar::Util: '0' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=HTML-Template repository: git://github.com/mpeters/html-template.git version: '2.97' HTML-Template-2.97/dist.ini0000644000175000017500000000135113107402001013542 0ustar samsamname = HTML-Template main_modules = lib/HTML/Template.pm author = Michael Peters license = Perl_5 copyright_holder = Michael Peters copyright_year = 2012 abstract = Perl module to use HTML-like templating language [@Basic] [PruneFiles] match = ^file_cache/* [Prereqs] Carp = 0 File::Spec = 0.82 Digest::MD5 = 0 Scalar::Util = 0 CGI = 0 [Prereqs / TestRequires] File::Temp = 0 Test::More = 0 Test::Pod = 0 [MetaResources] bugtracker.web = https://rt.cpan.org/Public/Dist/Display.html?Name=HTML-Template repository.url = git://github.com/mpeters/html-template.git repository.web = https://github.com/mpeters/html-template repository.type = git [VersionFromModule] [PodSyntaxTests] HTML-Template-2.97/LICENSE0000644000175000017500000004366313107402001013117 0ustar samsamThis software is copyright (c) 2012 by Michael Peters. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2012 by Michael Peters. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2012 by Michael Peters. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End HTML-Template-2.97/lib/0000775000175000017500000000000013107402001012646 5ustar samsamHTML-Template-2.97/lib/HTML/0000775000175000017500000000000013107402001013412 5ustar samsamHTML-Template-2.97/lib/HTML/Template.pm0000644000175000017500000040613413107402001015531 0ustar samsampackage HTML::Template; $HTML::Template::VERSION = '2.97'; =head1 NAME HTML::Template - Perl module to use HTML-like templating language =head1 SYNOPSIS First you make a template - this is just a normal HTML file with a few extra tags, the simplest being C<< >> For example, test.tmpl: Test Template My Home Directory is

My Path is set to Now you can use it in a small CGI program: #!/usr/bin/perl -w use HTML::Template; # open the html template my $template = HTML::Template->new(filename => 'test.tmpl'); # fill in some parameters $template->param(HOME => $ENV{HOME}); $template->param(PATH => $ENV{PATH}); # send the obligatory Content-Type and print the template output print "Content-Type: text/html\n\n", $template->output; If all is well in the universe this should show something like this in your browser when visiting the CGI: My Home Directory is /home/some/directory My Path is set to /bin;/usr/bin =head1 DESCRIPTION This module attempts to make using HTML templates simple and natural. It extends standard HTML with a few new HTML-esque tags - C<< >> C<< >>, C<< >>, C<< >>, C<< >> and C<< >>. The file written with HTML and these new tags is called a template. It is usually saved separate from your script - possibly even created by someone else! Using this module you fill in the values for the variables, loops and branches declared in the template. This allows you to separate design - the HTML - from the data, which you generate in the Perl script. This module is licensed under the same terms as Perl. See the LICENSE section below for more details. =head1 TUTORIAL If you're new to HTML::Template, I suggest you start with the introductory article available on Perl Monks: http://www.perlmonks.org/?node_id=65642 =head1 FAQ Please see L =head1 MOTIVATION It is true that there are a number of packages out there to do HTML templates. On the one hand you have things like L which allows you freely mix Perl with HTML. On the other hand lie home-grown variable substitution solutions. Hopefully the module can find a place between the two. One advantage of this module over a full L-esque solution is that it enforces an important divide - design and programming. By limiting the programmer to just using simple variables and loops in the HTML, the template remains accessible to designers and other non-perl people. The use of HTML-esque syntax goes further to make the format understandable to others. In the future this similarity could be used to extend existing HTML editors/analyzers to support HTML::Template. An advantage of this module over home-grown tag-replacement schemes is the support for loops. In my work I am often called on to produce tables of data in html. Producing them using simplistic HTML templates results in programs containing lots of HTML since the HTML itself cannot represent loops. The introduction of loop statements in the HTML simplifies this situation considerably. The designer can layout a single row and the programmer can fill it in as many times as necessary - all they must agree on is the parameter names. For all that, I think the best thing about this module is that it does just one thing and it does it quickly and carefully. It doesn't try to replace Perl and HTML, it just augments them to interact a little better. And it's pretty fast. =head1 THE TAGS =head2 TMPL_VAR The C<< >> tag is very simple. For each C<< >> tag in the template you call: $template->param(PARAMETER_NAME => "VALUE") When the template is output the C<< >> is replaced with the VALUE text you specified. If you don't set a parameter it just gets skipped in the output. You can also specify the value of the parameter as a code reference in order to have "lazy" variables. These sub routines will only be referenced if the variables are used. See L for more information. =head3 Attributes The following "attributes" can also be specified in template var tags: =over =item * escape This allows you to escape the value before it's put into the output. This is useful when you want to use a TMPL_VAR in a context where those characters would cause trouble. For example: If you called C with a value like C you'll get in trouble with HTML's idea of a double-quote. On the other hand, if you use C, like this: You'll get what you wanted no matter what value happens to be passed in for param. The following escape values are supported: =over =item * html Replaces the following characters with their HTML entity equivalent: C<&>, C<">, C<'>, C<< < >>, C<< > >> =item * js Escapes (with a backslash) the following characters: C<\>, C<'>, C<">, C<\n>, C<\r> =item * url URL escapes any ASCII characters except for letters, numbers, C<_>, C<.> and C<->. =item * none Performs no escaping. This is the default, but it's useful to be able to explicitly turn off escaping if you are using the C option. =back =item * default With this attribute you can assign a default value to a variable. For example, this will output "the devil gave me a taco" if the C variable is not set. gave me a taco. =back =head2 TMPL_LOOP ... The C<< >> tag is a bit more complicated than C<< >>. The C<< >> tag allows you to delimit a section of text and give it a name. Inside this named loop you place C<< >>s. Now you pass to C a list (an array ref) of parameter assignments (hash refs) for this loop. The loop iterates over the list and produces output from the text block for each pass. Unset parameters are skipped. Here's an example: In the template: Name:
Job:

In your Perl code: $template->param( EMPLOYEE_INFO => [{name => 'Sam', job => 'programmer'}, {name => 'Steve', job => 'soda jerk'}] ); print $template->output(); The output is: Name: Sam Job: programmer Name: Steve Job: soda jerk As you can see above the C<< >> takes a list of variable assignments and then iterates over the loop body producing output. Often you'll want to generate a C<< >>'s contents programmatically. Here's an example of how this can be done (many other ways are possible!): # a couple of arrays of data to put in a loop: my @words = qw(I Am Cool); my @numbers = qw(1 2 3); my @loop_data = (); # initialize an array to hold your loop while (@words and @numbers) { my %row_data; # get a fresh hash for the row data # fill in this row $row_data{WORD} = shift @words; $row_data{NUMBER} = shift @numbers; # the crucial step - push a reference to this row into the loop! push(@loop_data, \%row_data); } # finally, assign the loop data to the loop param, again with a reference: $template->param(THIS_LOOP => \@loop_data); The above example would work with a template like: Word: Number: It would produce output like: Word: I Number: 1 Word: Am Number: 2 Word: Cool Number: 3 C<< >>s within C<< >>s are fine and work as you would expect. If the syntax for the C call has you stumped, here's an example of a param call with one nested loop: $template->param( LOOP => [ { name => 'Bobby', nicknames => [{name => 'the big bad wolf'}, {name => 'He-Man'}], }, ], ); Basically, each C<< >> gets an array reference. Inside the array are any number of hash references. These hashes contain the name=>value pairs for a single pass over the loop template. Inside a C<< >>, the only variables that are usable are the ones from the C<< >>. The variables in the outer blocks are not visible within a template loop. For the computer-science geeks among you, a C<< >> introduces a new scope much like a perl subroutine call. If you want your variables to be global you can use C option to C described below. =head2 TMPL_INCLUDE This tag includes a template directly into the current template at the point where the tag is found. The included template contents are used exactly as if its contents were physically included in the master template. The file specified can be an absolute path (beginning with a '/' under Unix, for example). If it isn't absolute, the path to the enclosing file is tried first. After that the path in the environment variable C is tried, if it exists. Next, the "path" option is consulted, first as-is and then with C prepended if available. As a final attempt, the filename is passed to C directly. See below for more information on C and the C option to C. As a protection against infinitely recursive includes, an arbitrary limit of 10 levels deep is imposed. You can alter this limit with the C option. See the entry for the C option below for more details. =head2 TMPL_IF ... The C<< >> tag allows you to include or not include a block of the template based on the value of a given parameter name. If the parameter is given a value that is true for Perl - like '1' - then the block is included in the output. If it is not defined, or given a false value - like '0' - then it is skipped. The parameters are specified the same way as with C<< >>. Example Template: Some text that only gets displayed if BOOL is true! Now if you call C<< $template->param(BOOL => 1) >> then the above block will be included by output. C<< >> blocks can include any valid HTML::Template construct - Cs and Cs and other C/C blocks. Note, however, that intersecting a C<< >> and a C<< >> is invalid. Not going to work: If the name of a C<< >> is used in a C<< >>, the C block will output if the loop has at least one row. Example: This will output if the loop is not empty. .... WARNING: Much of the benefit of HTML::Template is in decoupling your Perl and HTML. If you introduce numerous cases where you have Cs and matching Perl Cs, you will create a maintenance problem in keeping the two synchronized. I suggest you adopt the practice of only using C if you can do so without requiring a matching C in your Perl code. =head2 TMPL_ELSE ... ... You can include an alternate block in your C<< >> block by using C<< >>. NOTE: You still end the block with C<< >>, not C<< >>! Example: Some text that is included only if BOOL is true Some text that is included only if BOOL is false =head2 TMPL_UNLESS ... This tag is the opposite of C<< >>. The block is output if the C is set false or not defined. You can use C<< >> with C<< >> just as you can with C<< >>. Example: Some text that is output only if BOOL is FALSE. Some text that is output only if BOOL is TRUE. If the name of a C<< >> is used in a C<< >>, the C<< >> block output if the loop has zero rows. This will output if the loop is empty. .... =cut =head2 NOTES HTML::Template's tags are meant to mimic normal HTML tags. However, they are allowed to "break the rules". Something like: is not really valid HTML, but it is a perfectly valid use and will work as planned. The C in the tag is optional, although for extensibility's sake I recommend using it. Example - C<< >> is acceptable. If you're a fanatic about valid HTML and would like your templates to conform to valid HTML syntax, you may optionally type template tags in the form of HTML comments. This may be of use to HTML authors who would like to validate their templates' HTML syntax prior to HTML::Template processing, or who use DTD-savvy editing tools. In order to realize a dramatic savings in bandwidth, the standard (non-comment) tags will be used throughout this documentation. =head1 METHODS =head2 new Call C to create a new Template object: my $template = HTML::Template->new( filename => 'file.tmpl', option => 'value', ); You must call C with at least one C value> pair specifying how to access the template text. You can use C<< filename => 'file.tmpl' >> to specify a filename to be opened as the template. Alternately you can use: my $t = HTML::Template->new( scalarref => $ref_to_template_text, option => 'value', ); and my $t = HTML::Template->new( arrayref => $ref_to_array_of_lines, option => 'value', ); These initialize the template from in-memory resources. In almost every case you'll want to use the filename parameter. If you're worried about all the disk access from reading a template file just use mod_perl and the cache option detailed below. You can also read the template from an already opened filehandle, either traditionally as a glob or as a L: my $t = HTML::Template->new(filehandle => *FH, option => 'value'); The four C calling methods can also be accessed as below, if you prefer. my $t = HTML::Template->new_file('file.tmpl', option => 'value'); my $t = HTML::Template->new_scalar_ref($ref_to_template_text, option => 'value'); my $t = HTML::Template->new_array_ref($ref_to_array_of_lines, option => 'value'); my $t = HTML::Template->new_filehandle($fh, option => 'value'); And as a final option, for those that might prefer it, you can call new as: my $t = HTML::Template->new( type => 'filename', source => 'file.tmpl', ); Which works for all three of the source types. If the environment variable C is set and your filename doesn't begin with "/", then the path will be relative to the value of c. B - if the environment variable C is set to F and I call C<< HTML::Template->new() >> with filename set to "sam.tmpl", HTML::Template will try to open F to access the template file. You can also affect the search path for files with the C option to C - see below for more information. You can modify the Template object's behavior with C. The options are available: =head3 Error Detection Options =over =item * die_on_bad_params If set to 0 the module will let you call: $template->param(param_name => 'value') even if 'param_name' doesn't exist in the template body. Defaults to 1. =item * force_untaint If set to 1 the module will not allow you to set unescaped parameters with tainted values. If set to 2 you will have to untaint all parameters, including ones with the escape attribute. This option makes sure you untaint everything so you don't accidentally introduce e.g. cross-site-scripting (XSS) vulnerabilities. Requires taint mode. Defaults to 0. =item * strict - if set to 0 the module will allow things that look like they might be TMPL_* tags to get by without dieing. Example: Would normally cause an error, but if you call new with C<< strict => 0 >> HTML::Template will ignore it. Defaults to 1. =item * vanguard_compatibility_mode If set to 1 the module will expect to see C<< >>s that look like C<%NAME%> in addition to the standard syntax. Also sets C 0>. If you're not at Vanguard Media trying to use an old format template don't worry about this one. Defaults to 0. =back =head3 Caching Options =over =item * cache If set to 1 the module will cache in memory the parsed templates based on the filename parameter, the modification date of the file and the options passed to C. This only applies to templates opened with the filename parameter specified, not scalarref or arrayref templates. Caching also looks at the modification times of any files included using C<< >> tags, but again, only if the template is opened with filename parameter. This is mainly of use in a persistent environment like Apache/mod_perl. It has absolutely no benefit in a normal CGI environment since the script is unloaded from memory after every request. For a cache that does work for a non-persistent environment see the C option below. My simplistic testing shows that using cache yields a 90% performance increase under mod_perl. Cache defaults to 0. =item * shared_cache If set to 1 the module will store its cache in shared memory using the L module (available from CPAN). The effect of this will be to maintain a single shared copy of each parsed template for all instances of HTML::Template on the same machine to use. This can be a significant reduction in memory usage in an environment with a single machine but multiple servers. As an example, on one of our systems we use 4MB of template cache and maintain 25 httpd processes - shared_cache results in saving almost 100MB! Of course, some reduction in speed versus normal caching is to be expected. Another difference between normal caching and shared_cache is that shared_cache will work in a non-persistent environment (like normal CGI) - normal caching is only useful in a persistent environment like Apache/mod_perl. By default HTML::Template uses the IPC key 'TMPL' as a shared root segment (0x4c504d54 in hex), but this can be changed by setting the C C parameter to another 4-character or integer key. Other options can be used to affect the shared memory cache correspond to L options - C, C and C. See L for a description of how these work - in most cases you shouldn't need to change them from the defaults. For more information about the shared memory cache system used by HTML::Template see L. =item * double_cache If set to 1 the module will use a combination of C and normal cache mode for the best possible caching. Of course, it also uses the most memory of all the cache modes. All the same ipc_* options that work with C apply to C as well. Defaults to 0. =item * blind_cache If set to 1 the module behaves exactly as with normal caching but does not check to see if the file has changed on each request. This option should be used with caution, but could be of use on high-load servers. My tests show C performing only 1 to 2 percent faster than cache under mod_perl. B: Combining this option with shared_cache can result in stale templates stuck permanently in shared memory! =item * file_cache If set to 1 the module will store its cache in a file using the L module. It uses no additional memory, and my simplistic testing shows that it yields a 50% performance advantage. Like C, it will work in a non-persistent environments (like CGI). Default is 0. If you set this option you must set the C option. See below for details. B: L uses C to ensure safe access to cache files. Using C on a system or filesystem (like NFS) without C support is dangerous. =item * file_cache_dir Sets the directory where the module will store the cache files if C is enabled. Your script will need write permissions to this directory. You'll also need to make sure the sufficient space is available to store the cache files. =item * file_cache_dir_mode Sets the file mode for newly created C directories and subdirectories. Defaults to "0700" for security but this may be inconvenient if you do not have access to the account running the webserver. =item * double_file_cache If set to 1 the module will use a combination of C and normal C mode for the best possible caching. The file_cache_* options that work with file_cache apply to C as well. Defaults to 0. =item * cache_lazy_vars The option tells HTML::Template to cache the values returned from code references used for Cs. See L for details. =item * cache_lazy_loops The option tells HTML::Template to cache the values returned from code references used for Cs. See L for details. =back =head3 Filesystem Options =over =item * path You can set this variable with a list of paths to search for files specified with the C option to C and for files included with the C<< >> tag. This list is only consulted when the filename is relative. The C environment variable is always tried first if it exists. Also, if C is set then an attempt will be made to prepend C onto paths in the path array. In the case of a C<< >> file, the path to the including file is also tried before path is consulted. Example: my $template = HTML::Template->new( filename => 'file.tmpl', path => ['/path/to/templates', '/alternate/path'], ); B: the paths in the path list must be expressed as UNIX paths, separated by the forward-slash character ('/'). =item * search_path_on_include If set to a true value the module will search from the top of the array of paths specified by the path option on every C<< >> and use the first matching template found. The normal behavior is to look only in the current directory for a template to include. Defaults to 0. =item * utf8 Setting this to true tells HTML::Template to treat your template files as UTF-8 encoded. This will apply to any file's passed to C or any included files. It won't do anything special to scalars templates passed to C since you should be doing the encoding on those yourself. my $template = HTML::Template->new( filename => 'umlauts_are_awesome.tmpl', utf8 => 1, ); Most templates are either ASCII (the default) or UTF-8 encoded Unicode. But if you need some other encoding other than these 2, look at the C option. B: The C and C options cannot be used at the same time. =item * open_mode You can set this option to an opening mode with which all template files will be opened. For example, if you want to use a template that is UTF-16 encoded unicode: my $template = HTML::Template->new( filename => 'file.tmpl', open_mode => '<:encoding(UTF-16)', ); That way you can force a different encoding (than the default ASCII or UTF-8), CR/LF properties etc. on the template files. See L for details. B: this only works in perl 5.7.1 and above. B: you have to supply an opening mode that actually permits reading from the file handle. B: The C and C options cannot be used at the same time. =back =head3 Debugging Options =over =item * debug If set to 1 the module will write random debugging information to STDERR. Defaults to 0. =item * stack_debug If set to 1 the module will use Data::Dumper to print out the contents of the parse_stack to STDERR. Defaults to 0. =item * cache_debug If set to 1 the module will send information on cache loads, hits and misses to STDERR. Defaults to 0. =item * shared_cache_debug If set to 1 the module will turn on the debug option in L. Defaults to 0. =item * memory_debug If set to 1 the module will send information on cache memory usage to STDERR. Requires the L module. Defaults to 0. =back =head3 Miscellaneous Options =over =item * associate This option allows you to inherit the parameter values from other objects. The only requirement for the other object is that it have a C method that works like HTML::Template's C. A good candidate would be a L query object. Example: my $query = CGI->new; my $template = HTML::Template->new( filename => 'template.tmpl', associate => $query, ); Now, C<< $template->output() >> will act as though $template->param(form_field => $cgi->param('form_field')); had been specified for each key/value pair that would be provided by the C<< $cgi->param() >> method. Parameters you set directly take precedence over associated parameters. You can specify multiple objects to associate by passing an anonymous array to the associate option. They are searched for parameters in the order they appear: my $template = HTML::Template->new( filename => 'template.tmpl', associate => [$query, $other_obj], ); B: The parameter names are matched in a case-insensitive manner. If you have two parameters in a CGI object like 'NAME' and 'Name' one will be chosen randomly by associate. This behavior can be changed by the C option. =item * case_sensitive Setting this option to true causes HTML::Template to treat template variable names case-sensitively. The following example would only set one parameter without the C option: my $template = HTML::Template->new( filename => 'template.tmpl', case_sensitive => 1 ); $template->param( FieldA => 'foo', fIELDa => 'bar', ); This option defaults to off. B: with C and C the special loop variables are available in lower-case only. =item * loop_context_vars When this parameter is set to true (it is false by default) extra variables that depend on the loop's context are made available inside a loop. These are: =over =item * __first__ Value that is true for the first iteration of the loop and false every other time. =item * __last__ Value that is true for the last iteration of the loop and false every other time. =item * __inner__ Value that is true for the every iteration of the loop except for the first and last. =item * __outer__ Value that is true for the first and last iterations of the loop. =item * __odd__ Value that is true for the every odd iteration of the loop. =item * __even__ Value that is true for the every even iteration of the loop. =item * __counter__ An integer (starting from 1) whose value increments for each iteration of the loop. =item * __index__ An integer (starting from 0) whose value increments for each iteration of the loop. =back Just like any other Cs these variables can be used in C<< >>, C<< >> and C<< >> to control how a loop is output. Example: This only outputs on the first pass. This outputs every other pass, on the odd passes. This outputs every other pass, on the even passes. This outputs on passes that are neither first nor last. This is pass number . This only outputs on the last pass. One use of this feature is to provide a "separator" similar in effect to the perl function C. Example: and , . Would output something like: Apples, Oranges, Brains, Toes, and Kiwi. Given an appropriate C call, of course. B: A loop with only a single pass will get both C<__first__> and C<__last__> set to true, but not C<__inner__>. =item * no_includes Set this option to 1 to disallow the C<< >> tag in the template file. This can be used to make opening untrusted templates B less dangerous. Defaults to 0. =item * max_includes Set this variable to determine the maximum depth that includes can reach. Set to 10 by default. Including files to a depth greater than this value causes an error message to be displayed. Set to 0 to disable this protection. =item * die_on_missing_include If true, then HTML::Template will die if it can't find a file for a C<< >>. This defaults to true. =item * global_vars Normally variables declared outside a loop are not available inside a loop. This option makes C<< >>s like global variables in Perl - they have unlimited scope. This option also affects C<< >> and C<< >>. Example: This is a normal variable: .

Here it is inside the loop:

Normally this wouldn't work as expected, since C<< >>'s value outside the loop is not available inside the loop. The global_vars option also allows you to access the values of an enclosing loop within an inner loop. For example, in this loop the inner loop will have access to the value of C in the correct iteration: OUTER: INNER: INSIDE OUT: One side-effect of C is that variables you set with C that might otherwise be ignored when C is off will stick around. This is necessary to allow inner loops to access values set for outer loops that don't directly use the value. B: C is not C (which does not exist). That means that loops you declare at one scope are not available inside other loops even when C is on. =item * filter This option allows you to specify a filter for your template files. A filter is a subroutine that will be called after HTML::Template reads your template file but before it starts parsing template tags. In the most simple usage, you simply assign a code reference to the filter parameter. This subroutine will receive a single argument - a reference to a string containing the template file text. Here is an example that accepts templates with tags that look like C and transforms them into HTML::Template tags: my $filter = sub { my $text_ref = shift; $$text_ref =~ s/!!!ZAP_(.*?)!!!//g; }; # open zap.tmpl using the above filter my $template = HTML::Template->new( filename => 'zap.tmpl', filter => $filter, ); More complicated usages are possible. You can request that your filter receives the template text as an array of lines rather than as a single scalar. To do that you need to specify your filter using a hash-ref. In this form you specify the filter using the C key and the desired argument format using the C key. The available formats are C and C. Using the C format will incur a performance penalty but may be more convenient in some situations. my $template = HTML::Template->new( filename => 'zap.tmpl', filter => { sub => $filter, format => 'array', } ); You may also have multiple filters. This allows simple filters to be combined for more elaborate functionality. To do this you specify an array of filters. The filters are applied in the order they are specified. my $template = HTML::Template->new( filename => 'zap.tmpl', filter => [ { sub => \&decompress, format => 'scalar', }, { sub => \&remove_spaces, format => 'array', }, ] ); The specified filters will be called for any Ced files just as they are for the main template file. =item * default_escape Set this parameter to a valid escape type (see the C option) and HTML::Template will apply the specified escaping to all variables unless they declare a different escape in the template. =back =cut use integer; # no floating point math so far! use strict; # and no funny business, either. use Carp; # generate better errors with more context use File::Spec; # generate paths that work on all platforms use Digest::MD5 qw(md5_hex); # generate cache keys use Scalar::Util qw(tainted); # define accessor constants used to improve readability of array # accesses into "objects". I used to use 'use constant' but that # seems to cause occasional irritating warnings in older Perls. package HTML::Template::LOOP; sub TEMPLATE_HASH () { 0 } sub PARAM_SET () { 1 } package HTML::Template::COND; sub VARIABLE () { 0 } sub VARIABLE_TYPE () { 1 } sub VARIABLE_TYPE_VAR () { 0 } sub VARIABLE_TYPE_LOOP () { 1 } sub JUMP_IF_TRUE () { 2 } sub JUMP_ADDRESS () { 3 } sub WHICH () { 4 } sub UNCONDITIONAL_JUMP () { 5 } sub IS_ELSE () { 6 } sub WHICH_IF () { 0 } sub WHICH_UNLESS () { 1 } # back to the main package scope. package HTML::Template; my %OPTIONS; # set the default options BEGIN { %OPTIONS = ( debug => 0, stack_debug => 0, timing => 0, search_path_on_include => 0, cache => 0, blind_cache => 0, file_cache => 0, file_cache_dir => '', file_cache_dir_mode => 0700, force_untaint => 0, cache_debug => 0, shared_cache_debug => 0, memory_debug => 0, die_on_bad_params => 1, vanguard_compatibility_mode => 0, associate => [], path => [], strict => 1, loop_context_vars => 0, max_includes => 10, shared_cache => 0, double_cache => 0, double_file_cache => 0, ipc_key => 'TMPL', ipc_mode => 0666, ipc_segment_size => 65536, ipc_max_size => 0, global_vars => 0, no_includes => 0, case_sensitive => 0, filter => [], open_mode => '', utf8 => 0, cache_lazy_vars => 0, cache_lazy_loops => 0, die_on_missing_include => 1, ); } # open a new template and return an object handle sub new { my $pkg = shift; my $self; { my %hash; $self = bless(\%hash, $pkg); } # the options hash my $options = {}; $self->{options} = $options; # set default parameters in options hash %$options = %OPTIONS; # load in options supplied to new() $options = _load_supplied_options([@_], $options); # blind_cache = 1 implies cache = 1 $options->{blind_cache} and $options->{cache} = 1; # shared_cache = 1 implies cache = 1 $options->{shared_cache} and $options->{cache} = 1; # file_cache = 1 implies cache = 1 $options->{file_cache} and $options->{cache} = 1; # double_cache is a combination of shared_cache and cache. $options->{double_cache} and $options->{cache} = 1; $options->{double_cache} and $options->{shared_cache} = 1; # double_file_cache is a combination of file_cache and cache. $options->{double_file_cache} and $options->{cache} = 1; $options->{double_file_cache} and $options->{file_cache} = 1; # vanguard_compatibility_mode implies die_on_bad_params = 0 $options->{vanguard_compatibility_mode} and $options->{die_on_bad_params} = 0; # handle the "type", "source" parameter format (does anyone use it?) if (exists($options->{type})) { exists($options->{source}) or croak("HTML::Template->new() called with 'type' parameter set, but no 'source'!"); ( $options->{type} eq 'filename' or $options->{type} eq 'scalarref' or $options->{type} eq 'arrayref' or $options->{type} eq 'filehandle' ) or croak("HTML::Template->new() : type parameter must be set to 'filename', 'arrayref', 'scalarref' or 'filehandle'!"); $options->{$options->{type}} = $options->{source}; delete $options->{type}; delete $options->{source}; } # make sure taint mode is on if force_untaint flag is set if ($options->{force_untaint}) { if ($] < 5.008000) { warn("HTML::Template->new() : 'force_untaint' option needs at least Perl 5.8.0!"); } elsif (!${^TAINT}) { croak("HTML::Template->new() : 'force_untaint' option set but perl does not run in taint mode!"); } } # associate should be an array of one element if it's not # already an array. if (ref($options->{associate}) ne 'ARRAY') { $options->{associate} = [$options->{associate}]; } # path should be an array if it's not already if (ref($options->{path}) ne 'ARRAY') { $options->{path} = [$options->{path}]; } # filter should be an array if it's not already if (ref($options->{filter}) ne 'ARRAY') { $options->{filter} = [$options->{filter}]; } # make sure objects in associate area support param() foreach my $object (@{$options->{associate}}) { defined($object->can('param')) or croak("HTML::Template->new called with associate option, containing object of type " . ref($object) . " which lacks a param() method!"); } # check for syntax errors: my $source_count = 0; exists($options->{filename}) and $source_count++; exists($options->{filehandle}) and $source_count++; exists($options->{arrayref}) and $source_count++; exists($options->{scalarref}) and $source_count++; if ($source_count != 1) { croak( "HTML::Template->new called with multiple (or no) template sources specified! A valid call to new() has exactly one filename => 'file' OR exactly one scalarref => \\\$scalar OR exactly one arrayref => \\\@array OR exactly one filehandle => \*FH" ); } # check that cache options are not used with non-cacheable templates croak "Cannot have caching when template source is not file" if grep { exists($options->{$_}) } qw( filehandle arrayref scalarref) and grep { $options->{$_} } qw( cache blind_cache file_cache shared_cache double_cache double_file_cache ); # check that filenames aren't empty if (exists($options->{filename})) { croak("HTML::Template->new called with empty filename parameter!") unless length $options->{filename}; } # do some memory debugging - this is best started as early as possible if ($options->{memory_debug}) { # memory_debug needs GTop eval { require GTop; }; croak("Could not load GTop. You must have GTop installed to use HTML::Template in memory_debug mode. The error was: $@") if ($@); $self->{gtop} = GTop->new(); $self->{proc_mem} = $self->{gtop}->proc_mem($$); print STDERR "\n### HTML::Template Memory Debug ### START ", $self->{proc_mem}->size(), "\n"; } if ($options->{file_cache}) { # make sure we have a file_cache_dir option croak("You must specify the file_cache_dir option if you want to use file_cache.") unless length $options->{file_cache_dir}; # file_cache needs some extra modules loaded eval { require Storable; }; croak( "Could not load Storable. You must have Storable installed to use HTML::Template in file_cache mode. The error was: $@" ) if ($@); } if ($options->{shared_cache}) { # shared_cache needs some extra modules loaded eval { require IPC::SharedCache; }; croak( "Could not load IPC::SharedCache. You must have IPC::SharedCache installed to use HTML::Template in shared_cache mode. The error was: $@" ) if ($@); # initialize the shared cache my %cache; tie %cache, 'IPC::SharedCache', ipc_key => $options->{ipc_key}, load_callback => [\&_load_shared_cache, $self], validate_callback => [\&_validate_shared_cache, $self], debug => $options->{shared_cache_debug}, ipc_mode => $options->{ipc_mode}, max_size => $options->{ipc_max_size}, ipc_segment_size => $options->{ipc_segment_size}; $self->{cache} = \%cache; } if ($options->{default_escape}) { $options->{default_escape} = uc $options->{default_escape}; unless ($options->{default_escape} =~ /^(NONE|HTML|URL|JS)$/i) { croak( "HTML::Template->new(): Invalid setting for default_escape - '$options->{default_escape}'. Valid values are 'none', 'html', 'url', or 'js'." ); } } # no 3 args form of open before perl 5.7.1 if ($options->{open_mode} && $] < 5.007001) { croak("HTML::Template->new(): open_mode cannot be used in Perl < 5.7.1"); } if($options->{utf8}) { croak("HTML::Template->new(): utf8 cannot be used in Perl < 5.7.1") if $] < 5.007001; croak("HTML::Template->new(): utf8 and open_mode cannot be used at the same time") if $options->{open_mode}; # utf8 is just a short-cut for a common open_mode $options->{open_mode} = '<:encoding(utf8)'; } print STDERR "### HTML::Template Memory Debug ### POST CACHE INIT ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; # initialize data structures $self->_init; print STDERR "### HTML::Template Memory Debug ### POST _INIT CALL ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; # drop the shared cache - leaving out this step results in the # template object evading garbage collection since the callbacks in # the shared cache tie hold references to $self! This was not easy # to find, by the way. delete $self->{cache} if $options->{shared_cache}; return $self; } sub _load_supplied_options { my $argsref = shift; my $options = shift; for (my $x = 0 ; $x < @{$argsref} ; $x += 2) { defined(${$argsref}[($x + 1)]) or croak("HTML::Template->new() called with odd number of option parameters - should be of the form option => value"); $options->{lc(${$argsref}[$x])} = ${$argsref}[($x + 1)]; } return $options; } # an internally used new that receives its parse_stack and param_map as input sub _new_from_loop { my $pkg = shift; my $self; { my %hash; $self = bless(\%hash, $pkg); } # the options hash my $options = { debug => $OPTIONS{debug}, stack_debug => $OPTIONS{stack_debug}, die_on_bad_params => $OPTIONS{die_on_bad_params}, associate => [@{$OPTIONS{associate}}], loop_context_vars => $OPTIONS{loop_context_vars}, }; $self->{options} = $options; $options = _load_supplied_options([@_], $options); $self->{param_map} = $options->{param_map}; $self->{parse_stack} = $options->{parse_stack}; delete($options->{param_map}); delete($options->{parse_stack}); return $self; } # a few shortcuts to new(), of possible use... sub new_file { my $pkg = shift; return $pkg->new('filename', @_); } sub new_filehandle { my $pkg = shift; return $pkg->new('filehandle', @_); } sub new_array_ref { my $pkg = shift; return $pkg->new('arrayref', @_); } sub new_scalar_ref { my $pkg = shift; return $pkg->new('scalarref', @_); } # initializes all the object data structures, either from cache or by # calling the appropriate routines. sub _init { my $self = shift; my $options = $self->{options}; if ($options->{double_cache}) { # try the normal cache, return if we have it. $self->_fetch_from_cache(); return if (defined $self->{param_map} and defined $self->{parse_stack}); # try the shared cache $self->_fetch_from_shared_cache(); # put it in the local cache if we got it. $self->_commit_to_cache() if (defined $self->{param_map} and defined $self->{parse_stack}); } elsif ($options->{double_file_cache}) { # try the normal cache, return if we have it. $self->_fetch_from_cache(); return if (defined $self->{param_map}); # try the file cache $self->_fetch_from_file_cache(); # put it in the local cache if we got it. $self->_commit_to_cache() if (defined $self->{param_map}); } elsif ($options->{shared_cache}) { # try the shared cache $self->_fetch_from_shared_cache(); } elsif ($options->{file_cache}) { # try the file cache $self->_fetch_from_file_cache(); } elsif ($options->{cache}) { # try the normal cache $self->_fetch_from_cache(); } # if we got a cache hit, return return if (defined $self->{param_map}); # if we're here, then we didn't get a cached copy, so do a full # init. $self->_init_template(); $self->_parse(); # now that we have a full init, cache the structures if caching is # on. shared cache is already cool. if ($options->{file_cache}) { $self->_commit_to_file_cache(); } $self->_commit_to_cache() if ( ($options->{cache} and not $options->{shared_cache} and not $options->{file_cache}) or ($options->{double_cache}) or ($options->{double_file_cache})); } # Caching subroutines - they handle getting and validating cache # records from either the in-memory or shared caches. # handles the normal in memory cache use vars qw( %CACHE ); sub _fetch_from_cache { my $self = shift; my $options = $self->{options}; # return if there's no file here my $filepath = $self->_find_file($options->{filename}); return unless (defined($filepath)); $options->{filepath} = $filepath; # return if there's no cache entry for this key my $key = $self->_cache_key(); return unless exists($CACHE{$key}); # validate the cache my $mtime = $self->_mtime($filepath); if (defined $mtime) { # return if the mtime doesn't match the cache if (defined($CACHE{$key}{mtime}) and ($mtime != $CACHE{$key}{mtime})) { $options->{cache_debug} and print STDERR "CACHE MISS : $filepath : $mtime\n"; return; } # if the template has includes, check each included file's mtime # and return if different if (exists($CACHE{$key}{included_mtimes})) { foreach my $filename (keys %{$CACHE{$key}{included_mtimes}}) { next unless defined($CACHE{$key}{included_mtimes}{$filename}); my $included_mtime = (stat($filename))[9]; if ($included_mtime != $CACHE{$key}{included_mtimes}{$filename}) { $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### CACHE MISS : $filepath : INCLUDE $filename : $included_mtime\n"; return; } } } } # got a cache hit! $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### CACHE HIT : $filepath => $key\n"; $self->{param_map} = $CACHE{$key}{param_map}; $self->{parse_stack} = $CACHE{$key}{parse_stack}; exists($CACHE{$key}{included_mtimes}) and $self->{included_mtimes} = $CACHE{$key}{included_mtimes}; # clear out values from param_map from last run $self->_normalize_options(); $self->clear_params(); } sub _commit_to_cache { my $self = shift; my $options = $self->{options}; my $key = $self->_cache_key(); my $filepath = $options->{filepath}; $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### CACHE LOAD : $filepath => $key\n"; $options->{blind_cache} or $CACHE{$key}{mtime} = $self->_mtime($filepath); $CACHE{$key}{param_map} = $self->{param_map}; $CACHE{$key}{parse_stack} = $self->{parse_stack}; exists($self->{included_mtimes}) and $CACHE{$key}{included_mtimes} = $self->{included_mtimes}; } # create a cache key from a template object. The cache key includes # the full path to the template and options which affect template # loading. sub _cache_key { my $self = shift; my $options = $self->{options}; # assemble pieces of the key my @key = ($options->{filepath}); push(@key, @{$options->{path}}); push(@key, $options->{search_path_on_include} || 0); push(@key, $options->{loop_context_vars} || 0); push(@key, $options->{global_vars} || 0); push(@key, $options->{open_mode} || 0); # compute the md5 and return it return md5_hex(@key); } # generates MD5 from filepath to determine filename for cache file sub _get_cache_filename { my ($self, $filepath) = @_; # get a cache key $self->{options}{filepath} = $filepath; my $hash = $self->_cache_key(); # ... and build a path out of it. Using the first two characters # gives us 255 buckets. This means you can have 255,000 templates # in the cache before any one directory gets over a few thousand # files in it. That's probably pretty good for this planet. If not # then it should be configurable. if (wantarray) { return (substr($hash, 0, 2), substr($hash, 2)); } else { return File::Spec->join($self->{options}{file_cache_dir}, substr($hash, 0, 2), substr($hash, 2)); } } # handles the file cache sub _fetch_from_file_cache { my $self = shift; my $options = $self->{options}; # return if there's no cache entry for this filename my $filepath = $self->_find_file($options->{filename}); return unless defined $filepath; my $cache_filename = $self->_get_cache_filename($filepath); return unless -e $cache_filename; eval { $self->{record} = Storable::lock_retrieve($cache_filename); }; croak("HTML::Template::new() - Problem reading cache file $cache_filename (file_cache => 1) : $@") if $@; croak("HTML::Template::new() - Problem reading cache file $cache_filename (file_cache => 1) : $!") unless defined $self->{record}; ($self->{mtime}, $self->{included_mtimes}, $self->{param_map}, $self->{parse_stack}) = @{$self->{record}}; $options->{filepath} = $filepath; # validate the cache my $mtime = $self->_mtime($filepath); if (defined $mtime) { # return if the mtime doesn't match the cache if (defined($self->{mtime}) and ($mtime != $self->{mtime})) { $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### FILE CACHE MISS : $filepath : $mtime\n"; ($self->{mtime}, $self->{included_mtimes}, $self->{param_map}, $self->{parse_stack}) = (undef, undef, undef, undef); return; } # if the template has includes, check each included file's mtime # and return if different if (exists($self->{included_mtimes})) { foreach my $filename (keys %{$self->{included_mtimes}}) { next unless defined($self->{included_mtimes}{$filename}); my $included_mtime = (stat($filename))[9]; if ($included_mtime != $self->{included_mtimes}{$filename}) { $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### FILE CACHE MISS : $filepath : INCLUDE $filename : $included_mtime\n"; ($self->{mtime}, $self->{included_mtimes}, $self->{param_map}, $self->{parse_stack}) = (undef, undef, undef, undef); return; } } } } # got a cache hit! $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### FILE CACHE HIT : $filepath\n"; # clear out values from param_map from last run $self->_normalize_options(); $self->clear_params(); } sub _commit_to_file_cache { my $self = shift; my $options = $self->{options}; my $filepath = $options->{filepath}; if (not defined $filepath) { $filepath = $self->_find_file($options->{filename}); confess("HTML::Template->new() : Cannot open included file $options->{filename} : file not found.") unless defined($filepath); $options->{filepath} = $filepath; } my ($cache_dir, $cache_file) = $self->_get_cache_filename($filepath); $cache_dir = File::Spec->join($options->{file_cache_dir}, $cache_dir); if (not -d $cache_dir) { if (not -d $options->{file_cache_dir}) { mkdir($options->{file_cache_dir}, $options->{file_cache_dir_mode}) or croak("HTML::Template->new() : can't mkdir $options->{file_cache_dir} (file_cache => 1): $!"); } mkdir($cache_dir, $options->{file_cache_dir_mode}) or croak("HTML::Template->new() : can't mkdir $cache_dir (file_cache => 1): $!"); } $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### FILE CACHE LOAD : $options->{filepath}\n"; my $result; eval { $result = Storable::lock_store([$self->{mtime}, $self->{included_mtimes}, $self->{param_map}, $self->{parse_stack}], scalar File::Spec->join($cache_dir, $cache_file)); }; croak("HTML::Template::new() - Problem writing cache file $cache_dir/$cache_file (file_cache => 1) : $@") if $@; croak("HTML::Template::new() - Problem writing cache file $cache_dir/$cache_file (file_cache => 1) : $!") unless defined $result; } # Shared cache routines. sub _fetch_from_shared_cache { my $self = shift; my $options = $self->{options}; my $filepath = $self->_find_file($options->{filename}); return unless defined $filepath; # fetch from the shared cache. $self->{record} = $self->{cache}{$filepath}; ($self->{mtime}, $self->{included_mtimes}, $self->{param_map}, $self->{parse_stack}) = @{$self->{record}} if defined($self->{record}); $options->{cache_debug} and defined($self->{record}) and print STDERR "### HTML::Template Cache Debug ### CACHE HIT : $filepath\n"; # clear out values from param_map from last run $self->_normalize_options(), $self->clear_params() if (defined($self->{record})); delete($self->{record}); return $self; } sub _validate_shared_cache { my ($self, $filename, $record) = @_; my $options = $self->{options}; $options->{shared_cache_debug} and print STDERR "### HTML::Template Cache Debug ### SHARED CACHE VALIDATE : $filename\n"; return 1 if $options->{blind_cache}; my ($c_mtime, $included_mtimes, $param_map, $parse_stack) = @$record; # if the modification time has changed return false my $mtime = $self->_mtime($filename); if ( defined $mtime and defined $c_mtime and $mtime != $c_mtime) { $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### SHARED CACHE MISS : $filename : $mtime\n"; return 0; } # if the template has includes, check each included file's mtime # and return false if different if (defined $mtime and defined $included_mtimes) { foreach my $fname (keys %$included_mtimes) { next unless defined($included_mtimes->{$fname}); if ($included_mtimes->{$fname} != (stat($fname))[9]) { $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### SHARED CACHE MISS : $filename : INCLUDE $fname\n"; return 0; } } } # all done - return true return 1; } sub _load_shared_cache { my ($self, $filename) = @_; my $options = $self->{options}; my $cache = $self->{cache}; $self->_init_template(); $self->_parse(); $options->{cache_debug} and print STDERR "### HTML::Template Cache Debug ### SHARED CACHE LOAD : $options->{filepath}\n"; print STDERR "### HTML::Template Memory Debug ### END CACHE LOAD ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; return [$self->{mtime}, $self->{included_mtimes}, $self->{param_map}, $self->{parse_stack}]; } # utility function - given a filename performs documented search and # returns a full path or undef if the file cannot be found. sub _find_file { my ($self, $filename, $extra_path) = @_; my $options = $self->{options}; my $filepath; # first check for a full path return File::Spec->canonpath($filename) if (File::Spec->file_name_is_absolute($filename) and (-e $filename)); # try the extra_path if one was specified if (defined($extra_path)) { $extra_path->[$#{$extra_path}] = $filename; $filepath = File::Spec->canonpath(File::Spec->catfile(@$extra_path)); return File::Spec->canonpath($filepath) if -e $filepath; } # try pre-prending HTML_Template_Root if (defined($ENV{HTML_TEMPLATE_ROOT})) { $filepath = File::Spec->catfile($ENV{HTML_TEMPLATE_ROOT}, $filename); return File::Spec->canonpath($filepath) if -e $filepath; } # try "path" option list.. foreach my $path (@{$options->{path}}) { $filepath = File::Spec->catfile($path, $filename); return File::Spec->canonpath($filepath) if -e $filepath; } # try even a relative path from the current directory... return File::Spec->canonpath($filename) if -e $filename; # try "path" option list with HTML_TEMPLATE_ROOT prepended... if (defined($ENV{HTML_TEMPLATE_ROOT})) { foreach my $path (@{$options->{path}}) { $filepath = File::Spec->catfile($ENV{HTML_TEMPLATE_ROOT}, $path, $filename); return File::Spec->canonpath($filepath) if -e $filepath; } } return undef; } # utility function - computes the mtime for $filename sub _mtime { my ($self, $filepath) = @_; my $options = $self->{options}; return (undef) if ($options->{blind_cache}); # make sure it still exists in the filesystem (-r $filepath) or Carp::confess("HTML::Template : template file $filepath does not exist or is unreadable."); # get the modification time return (stat(_))[9]; } # utility function - enforces new() options across LOOPs that have # come from a cache. Otherwise they would have stale options hashes. sub _normalize_options { my $self = shift; my $options = $self->{options}; my @pstacks = ($self->{parse_stack}); while (@pstacks) { my $pstack = pop(@pstacks); foreach my $item (@$pstack) { next unless (ref($item) eq 'HTML::Template::LOOP'); foreach my $template (values %{$item->[HTML::Template::LOOP::TEMPLATE_HASH]}) { # must be the same list as the call to _new_from_loop... $template->{options}{debug} = $options->{debug}; $template->{options}{stack_debug} = $options->{stack_debug}; $template->{options}{die_on_bad_params} = $options->{die_on_bad_params}; $template->{options}{case_sensitive} = $options->{case_sensitive}; $template->{options}{parent_global_vars} = $options->{parent_global_vars}; push(@pstacks, $template->{parse_stack}); } } } } # initialize the template buffer sub _init_template { my $self = shift; my $options = $self->{options}; print STDERR "### HTML::Template Memory Debug ### START INIT_TEMPLATE ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; if (exists($options->{filename})) { my $filepath = $options->{filepath}; if (not defined $filepath) { $filepath = $self->_find_file($options->{filename}); confess("HTML::Template->new() : Cannot open included file $options->{filename} : file not found.") unless defined($filepath); # we'll need this for future reference - to call stat() for example. $options->{filepath} = $filepath; } # use the open_mode if we have one if (my $mode = $options->{open_mode}) { open(TEMPLATE, $mode, $filepath) || confess("HTML::Template->new() : Cannot open included file $filepath with mode $mode: $!"); } else { open(TEMPLATE, $filepath) or confess("HTML::Template->new() : Cannot open included file $filepath : $!"); } $self->{mtime} = $self->_mtime($filepath); # read into scalar, note the mtime for the record $self->{template} = ""; while (read(TEMPLATE, $self->{template}, 10240, length($self->{template}))) { } close(TEMPLATE); } elsif (exists($options->{scalarref})) { # copy in the template text $self->{template} = ${$options->{scalarref}}; delete($options->{scalarref}); } elsif (exists($options->{arrayref})) { # if we have an array ref, join and store the template text $self->{template} = join("", @{$options->{arrayref}}); delete($options->{arrayref}); } elsif (exists($options->{filehandle})) { # just read everything in in one go local $/ = undef; $self->{template} = readline($options->{filehandle}); delete($options->{filehandle}); } else { confess("HTML::Template : Need to call new with filename, filehandle, scalarref or arrayref parameter specified."); } print STDERR "### HTML::Template Memory Debug ### END INIT_TEMPLATE ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; # handle filters if necessary $self->_call_filters(\$self->{template}) if @{$options->{filter}}; return $self; } # handle calling user defined filters sub _call_filters { my $self = shift; my $template_ref = shift; my $options = $self->{options}; my ($format, $sub); foreach my $filter (@{$options->{filter}}) { croak("HTML::Template->new() : bad value set for filter parameter - must be a code ref or a hash ref.") unless ref $filter; # translate into CODE->HASH $filter = {'format' => 'scalar', 'sub' => $filter} if (ref $filter eq 'CODE'); if (ref $filter eq 'HASH') { $format = $filter->{'format'}; $sub = $filter->{'sub'}; # check types and values croak( "HTML::Template->new() : bad value set for filter parameter - hash must contain \"format\" key and \"sub\" key.") unless defined $format and defined $sub; croak("HTML::Template->new() : bad value set for filter parameter - \"format\" must be either 'array' or 'scalar'") unless $format eq 'array' or $format eq 'scalar'; croak("HTML::Template->new() : bad value set for filter parameter - \"sub\" must be a code ref") unless ref $sub and ref $sub eq 'CODE'; # catch errors eval { if ($format eq 'scalar') { # call $sub->($template_ref); } else { # modulate my @array = map { $_ . "\n" } split("\n", $$template_ref); # call $sub->(\@array); # demodulate $$template_ref = join("", @array); } }; croak("HTML::Template->new() : fatal error occurred during filter call: $@") if $@; } else { croak("HTML::Template->new() : bad value set for filter parameter - must be code ref or hash ref"); } } # all done return $template_ref; } # _parse sifts through a template building up the param_map and # parse_stack structures. # # The end result is a Template object that is fully ready for # output(). sub _parse { my $self = shift; my $options = $self->{options}; $options->{debug} and print STDERR "### HTML::Template Debug ### In _parse:\n"; # setup the stacks and maps - they're accessed by typeglobs that # reference the top of the stack. They are masked so that a loop # can transparently have its own versions. use vars qw(@pstack %pmap @ifstack @ucstack %top_pmap); local (*pstack, *ifstack, *pmap, *ucstack, *top_pmap); # the pstack is the array of scalar refs (plain text from the # template file), VARs, LOOPs, IFs and ELSEs that output() works on # to produce output. Looking at output() should make it clear what # _parse is trying to accomplish. my @pstacks = ([]); *pstack = $pstacks[0]; $self->{parse_stack} = $pstacks[0]; # the pmap binds names to VARs, LOOPs and IFs. It allows param() to # access the right variable. NOTE: output() does not look at the # pmap at all! my @pmaps = ({}); *pmap = $pmaps[0]; *top_pmap = $pmaps[0]; $self->{param_map} = $pmaps[0]; # the ifstack is a temporary stack containing pending ifs and elses # waiting for a /if. my @ifstacks = ([]); *ifstack = $ifstacks[0]; # the ucstack is a temporary stack containing conditions that need # to be bound to param_map entries when their block is finished. # This happens when a conditional is encountered before any other # reference to its NAME. Since a conditional can reference VARs and # LOOPs it isn't possible to make the link right away. my @ucstacks = ([]); *ucstack = $ucstacks[0]; # the loopstack is another temp stack for closing loops. unlike # those above it doesn't get scoped inside loops, therefore it # doesn't need the typeglob magic. my @loopstack = (); # the fstack is a stack of filenames and counters that keeps track # of which file we're in and where we are in it. This allows # accurate error messages even inside included files! # fcounter, fmax and fname are aliases for the current file's info use vars qw($fcounter $fname $fmax); local (*fcounter, *fname, *fmax); my @fstack = ([$options->{filepath} || "/fake/path/for/non/file/template", 1, scalar @{[$self->{template} =~ m/(\n)/g]} + 1]); (*fname, *fcounter, *fmax) = \(@{$fstack[0]}); my $NOOP = HTML::Template::NOOP->new(); my $ESCAPE = HTML::Template::ESCAPE->new(); my $JSESCAPE = HTML::Template::JSESCAPE->new(); my $URLESCAPE = HTML::Template::URLESCAPE->new(); # all the tags that need NAMEs: my %need_names = map { $_ => 1 } qw(TMPL_VAR TMPL_LOOP TMPL_IF TMPL_UNLESS TMPL_INCLUDE); # variables used below that don't need to be my'd in the loop my ($name, $which, $escape, $default); # handle the old vanguard format $options->{vanguard_compatibility_mode} and $self->{template} =~ s/%([-\w\/\.+]+)%//g; # now split up template on '<', leaving them in my @chunks = split(m/(?=<)/, $self->{template}); # all done with template delete $self->{template}; # loop through chunks, filling up pstack my $last_chunk = $#chunks; CHUNK: for (my $chunk_number = 0 ; $chunk_number <= $last_chunk ; $chunk_number++) { next unless defined $chunks[$chunk_number]; my $chunk = $chunks[$chunk_number]; # a general regex to match any and all TMPL_* tags if ( $chunk =~ /^< (?:!--\s*)? ( \/?tmpl_ (?: (?:var) | (?:loop) | (?:if) | (?:else) | (?:unless) | (?:include) ) ) # $1 => $which - start of the tag \s* # DEFAULT attribute (?: default \s*=\s* (?: "([^">]*)" # $2 => double-quoted DEFAULT value " | '([^'>]*)' # $3 => single-quoted DEFAULT value | ([^\s=>]*) # $4 => unquoted DEFAULT value ) )? \s* # ESCAPE attribute (?: escape \s*=\s* (?: ( (?:["']?0["']?)| (?:["']?1["']?)| (?:["']?html["']?) | (?:["']?url["']?) | (?:["']?js["']?) | (?:["']?none["']?) ) # $5 => ESCAPE on ) )* # allow multiple ESCAPEs \s* # DEFAULT attribute (?: default \s*=\s* (?: "([^">]*)" # $6 => double-quoted DEFAULT value " | '([^'>]*)' # $7 => single-quoted DEFAULT value | ([^\s=>]*) # $8 => unquoted DEFAULT value ) )? \s* # NAME attribute (?: (?: name \s*=\s*)? (?: "([^">]*)" # $9 => double-quoted NAME value " | '([^'>]*)' # $10 => single-quoted NAME value | ([^\s=>]*) # $11 => unquoted NAME value ) )? \s* # DEFAULT attribute (?: default \s*=\s* (?: "([^">]*)" # $12 => double-quoted DEFAULT value " | '([^'>]*)' # $13 => single-quoted DEFAULT value | ([^\s=>]*) # $14 => unquoted DEFAULT value ) )? \s* # ESCAPE attribute (?: escape \s*=\s* (?: ( (?:["']?0["']?)| (?:["']?1["']?)| (?:["']?html["']?) | (?:["']?url["']?) | (?:["']?js["']?) | (?:["']?none["']?) ) # $15 => ESCAPE on ) )* # allow multiple ESCAPEs \s* # DEFAULT attribute (?: default \s*=\s* (?: "([^">]*)" # $16 => double-quoted DEFAULT value " | '([^'>]*)' # $17 => single-quoted DEFAULT value | ([^\s=>]*) # $18 => unquoted DEFAULT value ) )? \s* (?:--)?\/?> (.*) # $19 => $post - text that comes after the tag $/isx ) { $which = uc($1); # which tag is it $escape = defined $5 ? $5 : defined $15 ? $15 : (defined $options->{default_escape} && $which eq 'TMPL_VAR') ? $options->{default_escape} : 0; # escape set? # what name for the tag? undef for a /tag at most, one of the # following three will be defined $name = defined $9 ? $9 : defined $10 ? $10 : defined $11 ? $11 : undef; # is there a default? $default = defined $2 ? $2 : defined $3 ? $3 : defined $4 ? $4 : defined $6 ? $6 : defined $7 ? $7 : defined $8 ? $8 : defined $12 ? $12 : defined $13 ? $13 : defined $14 ? $14 : defined $16 ? $16 : defined $17 ? $17 : defined $18 ? $18 : undef; my $post = $19; # what comes after on the line # allow mixed case in filenames, otherwise flatten $name = lc($name) unless (not defined $name or $which eq 'TMPL_INCLUDE' or $options->{case_sensitive}); # die if we need a name and didn't get one die "HTML::Template->new() : No NAME given to a $which tag at $fname : line $fcounter." if ($need_names{$which} and (not defined $name or not length $name)); # die if we got an escape but can't use one die "HTML::Template->new() : ESCAPE option invalid in a $which tag at $fname : line $fcounter." if ($escape and ($which ne 'TMPL_VAR')); # die if we got a default but can't use one die "HTML::Template->new() : DEFAULT option invalid in a $which tag at $fname : line $fcounter." if (defined $default and ($which ne 'TMPL_VAR')); # take actions depending on which tag found if ($which eq 'TMPL_VAR') { print STDERR "### HTML::Template Debug ### $fname : line $fcounter : parsed VAR $name\n" if $options->{debug}; # if we already have this var, then simply link to the existing # HTML::Template::VAR, else create a new one. my $var; if (exists $pmap{$name}) { $var = $pmap{$name}; if( $options->{die_on_bad_params} && ref($var) ne 'HTML::Template::VAR') { die "HTML::Template->new() : Already used param name $name as a TMPL_LOOP, found in a TMPL_VAR at $fname : line $fcounter."; } } else { $var = HTML::Template::VAR->new(); $pmap{$name} = $var; $top_pmap{$name} = HTML::Template::VAR->new() if $options->{global_vars} and not exists $top_pmap{$name}; } # if a DEFAULT was provided, push a DEFAULT object on the # stack before the variable. if (defined $default) { push(@pstack, HTML::Template::DEF->new($default)); } # if ESCAPE was set, push an ESCAPE op on the stack before # the variable. output will handle the actual work. # unless of course, they have set escape=0 or escape=none if ($escape) { if ($escape =~ /^["']?url["']?$/i) { push(@pstack, $URLESCAPE); } elsif ($escape =~ /^["']?js["']?$/i) { push(@pstack, $JSESCAPE); } elsif ($escape =~ /^["']?0["']?$/) { # do nothing if escape=0 } elsif ($escape =~ /^["']?none["']?$/i) { # do nothing if escape=none } else { push(@pstack, $ESCAPE); } } push(@pstack, $var); } elsif ($which eq 'TMPL_LOOP') { # we've got a loop start print STDERR "### HTML::Template Debug ### $fname : line $fcounter : LOOP $name start\n" if $options->{debug}; # if we already have this loop, then simply link to the existing # HTML::Template::LOOP, else create a new one. my $loop; if (exists $pmap{$name}) { $loop = $pmap{$name}; if( $options->{die_on_bad_params} && ref($loop) ne 'HTML::Template::LOOP') { die "HTML::Template->new() : Already used param name $name as a TMPL_VAR, TMPL_IF or TMPL_UNLESS, found in a TMPL_LOOP at $fname : line $fcounter!"; } } else { # store the results in a LOOP object - actually just a # thin wrapper around another HTML::Template object. $loop = HTML::Template::LOOP->new(); $pmap{$name} = $loop; } # get it on the loopstack, pstack of the enclosing block push(@pstack, $loop); push(@loopstack, [$loop, $#pstack]); # magic time - push on a fresh pmap and pstack, adjust the typeglobs. # this gives the loop a separate namespace (i.e. pmap and pstack). push(@pstacks, []); *pstack = $pstacks[$#pstacks]; push(@pmaps, {}); *pmap = $pmaps[$#pmaps]; push(@ifstacks, []); *ifstack = $ifstacks[$#ifstacks]; push(@ucstacks, []); *ucstack = $ucstacks[$#ucstacks]; # auto-vivify __FIRST__, __LAST__ and __INNER__ if # loop_context_vars is set. Otherwise, with # die_on_bad_params set output() will might cause errors # when it tries to set them. if ($options->{loop_context_vars}) { $pmap{__first__} = HTML::Template::VAR->new(); $pmap{__inner__} = HTML::Template::VAR->new(); $pmap{__outer__} = HTML::Template::VAR->new(); $pmap{__last__} = HTML::Template::VAR->new(); $pmap{__odd__} = HTML::Template::VAR->new(); $pmap{__even__} = HTML::Template::VAR->new(); $pmap{__counter__} = HTML::Template::VAR->new(); $pmap{__index__} = HTML::Template::VAR->new(); } } elsif ($which eq '/TMPL_LOOP') { $options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : LOOP end\n"; my $loopdata = pop(@loopstack); die "HTML::Template->new() : found with no matching at $fname : line $fcounter!" unless defined $loopdata; my ($loop, $starts_at) = @$loopdata; # resolve pending conditionals foreach my $uc (@ucstack) { my $var = $uc->[HTML::Template::COND::VARIABLE]; if (exists($pmap{$var})) { $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var}; } else { $pmap{$var} = HTML::Template::VAR->new(); $top_pmap{$var} = HTML::Template::VAR->new() if $options->{global_vars} and not exists $top_pmap{$var}; $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var}; } if (ref($pmap{$var}) eq 'HTML::Template::VAR') { $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_VAR; } else { $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_LOOP; } } # get pmap and pstack for the loop, adjust the typeglobs to # the enclosing block. my $param_map = pop(@pmaps); *pmap = $pmaps[$#pmaps]; my $parse_stack = pop(@pstacks); *pstack = $pstacks[$#pstacks]; scalar(@ifstack) and die "HTML::Template->new() : Dangling or in loop ending at $fname : line $fcounter."; pop(@ifstacks); *ifstack = $ifstacks[$#ifstacks]; pop(@ucstacks); *ucstack = $ucstacks[$#ucstacks]; # instantiate the sub-Template, feeding it parse_stack and # param_map. This means that only the enclosing template # does _parse() - sub-templates get their parse_stack and # param_map fed to them already filled in. $loop->[HTML::Template::LOOP::TEMPLATE_HASH]{$starts_at} = ref($self)->_new_from_loop( parse_stack => $parse_stack, param_map => $param_map, debug => $options->{debug}, die_on_bad_params => $options->{die_on_bad_params}, loop_context_vars => $options->{loop_context_vars}, case_sensitive => $options->{case_sensitive}, force_untaint => $options->{force_untaint}, parent_global_vars => ($options->{global_vars} || $options->{parent_global_vars} || 0) ); # if this loop has been used multiple times we need to merge the "param_map" between them # all so that die_on_bad_params doesn't complain if we try to use different vars in # each instance of the same loop if ($options->{die_on_bad_params}) { my $loops = $loop->[HTML::Template::LOOP::TEMPLATE_HASH]; my @loop_keys = sort { $a <=> $b } keys %$loops; if (@loop_keys > 1) { my $last_loop = pop(@loop_keys); foreach my $loop (@loop_keys) { # make sure all the params in the last loop are also in this loop foreach my $param (keys %{$loops->{$last_loop}->{param_map}}) { next if $loops->{$loop}->{param_map}->{$param}; $loops->{$loop}->{param_map}->{$param} = $loops->{$last_loop}->{param_map}->{$param}; } # make sure all the params in this loop are also in the last loop foreach my $param (keys %{$loops->{$loop}->{param_map}}) { next if $loops->{$last_loop}->{param_map}->{$param}; $loops->{$last_loop}->{param_map}->{$param} = $loops->{$loop}->{param_map}->{$param}; } } } } } elsif ($which eq 'TMPL_IF' or $which eq 'TMPL_UNLESS') { $options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : $which $name start\n"; # if we already have this var, then simply link to the existing # HTML::Template::VAR/LOOP, else defer the mapping my $var; if (exists $pmap{$name}) { $var = $pmap{$name}; } else { $var = $name; } # connect the var to a conditional my $cond = HTML::Template::COND->new($var); if ($which eq 'TMPL_IF') { $cond->[HTML::Template::COND::WHICH] = HTML::Template::COND::WHICH_IF; $cond->[HTML::Template::COND::JUMP_IF_TRUE] = 0; } else { $cond->[HTML::Template::COND::WHICH] = HTML::Template::COND::WHICH_UNLESS; $cond->[HTML::Template::COND::JUMP_IF_TRUE] = 1; } # push unconnected conditionals onto the ucstack for # resolution later. Otherwise, save type information now. if ($var eq $name) { push(@ucstack, $cond); } else { if (ref($var) eq 'HTML::Template::VAR') { $cond->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_VAR; } else { $cond->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_LOOP; } } # push what we've got onto the stacks push(@pstack, $cond); push(@ifstack, $cond); } elsif ($which eq '/TMPL_IF' or $which eq '/TMPL_UNLESS') { $options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : $which end\n"; my $cond = pop(@ifstack); die "HTML::Template->new() : found with no matching at $fname : line $fcounter." unless defined $cond; if ($which eq '/TMPL_IF') { die "HTML::Template->new() : found incorrectly terminating a (use ) at $fname : line $fcounter.\n" if ($cond->[HTML::Template::COND::WHICH] == HTML::Template::COND::WHICH_UNLESS); } else { die "HTML::Template->new() : found incorrectly terminating a (use ) at $fname : line $fcounter.\n" if ($cond->[HTML::Template::COND::WHICH] == HTML::Template::COND::WHICH_IF); } # connect the matching to this "address" - place a NOOP to # hold the spot. This allows output() to treat an IF in the # assembler-esque "Conditional Jump" mode. push(@pstack, $NOOP); $cond->[HTML::Template::COND::JUMP_ADDRESS] = $#pstack; } elsif ($which eq 'TMPL_ELSE') { $options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : ELSE\n"; my $cond = pop(@ifstack); die "HTML::Template->new() : found with no matching or at $fname : line $fcounter." unless defined $cond; die "HTML::Template->new() : found second tag for or at $fname : line $fcounter." if $cond->[HTML::Template::COND::IS_ELSE]; my $else = HTML::Template::COND->new($cond->[HTML::Template::COND::VARIABLE]); $else->[HTML::Template::COND::WHICH] = $cond->[HTML::Template::COND::WHICH]; $else->[HTML::Template::COND::UNCONDITIONAL_JUMP] = 1; $else->[HTML::Template::COND::IS_ELSE] = 1; # need end-block resolution? if (defined($cond->[HTML::Template::COND::VARIABLE_TYPE])) { $else->[HTML::Template::COND::VARIABLE_TYPE] = $cond->[HTML::Template::COND::VARIABLE_TYPE]; } else { push(@ucstack, $else); } push(@pstack, $else); push(@ifstack, $else); # connect the matching to this "address" - thus the if, # failing jumps to the ELSE address. The else then gets # elaborated, and of course succeeds. On the other hand, if # the IF fails and falls though, output will reach the else # and jump to the /if address. $cond->[HTML::Template::COND::JUMP_ADDRESS] = $#pstack; } elsif ($which eq 'TMPL_INCLUDE') { # handle TMPL_INCLUDEs $options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : INCLUDE $name \n"; # no includes here, bub $options->{no_includes} and croak("HTML::Template : Illegal attempt to use TMPL_INCLUDE in template file : (no_includes => 1)"); my $filename = $name; # look for the included file... my $filepath; if ($options->{search_path_on_include}) { $filepath = $self->_find_file($filename); } else { $filepath = $self->_find_file($filename, [File::Spec->splitdir($fstack[-1][0])]); } die "HTML::Template->new() : Cannot open included file $filename : file not found." if !defined $filepath && $options->{die_on_missing_include}; my $included_template = ""; if( $filepath ) { # use the open_mode if we have one if (my $mode = $options->{open_mode}) { open(TEMPLATE, $mode, $filepath) || confess("HTML::Template->new() : Cannot open included file $filepath with mode $mode: $!"); } else { open(TEMPLATE, $filepath) or confess("HTML::Template->new() : Cannot open included file $filepath : $!"); } # read into the array while (read(TEMPLATE, $included_template, 10240, length($included_template))) { } close(TEMPLATE); } # call filters if necessary $self->_call_filters(\$included_template) if @{$options->{filter}}; if ($included_template) { # not empty # handle the old vanguard format - this needs to happen here # since we're not about to do a next CHUNKS. $options->{vanguard_compatibility_mode} and $included_template =~ s/%([-\w\/\.+]+)%//g; # collect mtimes for included files if ($options->{cache} and !$options->{blind_cache}) { $self->{included_mtimes}{$filepath} = (stat($filepath))[9]; } # adjust the fstack to point to the included file info push(@fstack, [$filepath, 1, scalar @{[$included_template =~ m/(\n)/g]} + 1]); (*fname, *fcounter, *fmax) = \(@{$fstack[$#fstack]}); # make sure we aren't infinitely recursing die "HTML::Template->new() : likely recursive includes - parsed $options->{max_includes} files deep and giving up (set max_includes higher to allow deeper recursion)." if ($options->{max_includes} and (scalar(@fstack) > $options->{max_includes})); # stick the remains of this chunk onto the bottom of the # included text. $included_template .= $post; $post = undef; # move the new chunks into place. splice(@chunks, $chunk_number, 1, split(m/(?=<)/, $included_template)); # recalculate stopping point $last_chunk = $#chunks; # start in on the first line of the included text - nothing # else to do on this line. $chunk = $chunks[$chunk_number]; redo CHUNK; } } else { # zuh!? die "HTML::Template->new() : Unknown or unmatched TMPL construct at $fname : line $fcounter."; } # push the rest after the tag if (defined($post)) { if (ref($pstack[$#pstack]) eq 'SCALAR') { ${$pstack[$#pstack]} .= $post; } else { push(@pstack, \$post); } } } else { # just your ordinary markup # make sure we didn't reject something TMPL_* but badly formed if ($options->{strict}) { die "HTML::Template->new() : Syntax error in tag at $fname : $fcounter." if ($chunk =~ /<(?:!--\s*)?\/?tmpl_/i); } # push the rest and get next chunk if (defined($chunk)) { if (ref($pstack[$#pstack]) eq 'SCALAR') { ${$pstack[$#pstack]} .= $chunk; } else { push(@pstack, \$chunk); } } } # count newlines in chunk and advance line count $fcounter += scalar(@{[$chunk =~ m/(\n)/g]}); # if we just crossed the end of an included file # pop off the record and re-alias to the enclosing file's info pop(@fstack), (*fname, *fcounter, *fmax) = \(@{$fstack[$#fstack]}) if ($fcounter > $fmax); } # next CHUNK # make sure we don't have dangling IF or LOOP blocks scalar(@ifstack) and die "HTML::Template->new() : At least one or not terminated at end of file!"; scalar(@loopstack) and die "HTML::Template->new() : At least one not terminated at end of file!"; # resolve pending conditionals foreach my $uc (@ucstack) { my $var = $uc->[HTML::Template::COND::VARIABLE]; if (exists($pmap{$var})) { $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var}; } else { $pmap{$var} = HTML::Template::VAR->new(); $top_pmap{$var} = HTML::Template::VAR->new() if $options->{global_vars} and not exists $top_pmap{$var}; $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var}; } if (ref($pmap{$var}) eq 'HTML::Template::VAR') { $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_VAR; } else { $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_LOOP; } } # want a stack dump? if ($options->{stack_debug}) { require 'Data/Dumper.pm'; print STDERR "### HTML::Template _param Stack Dump ###\n\n", Data::Dumper::Dumper($self->{parse_stack}), "\n"; } # get rid of filters - they cause runtime errors if Storable tries # to store them. This can happen under global_vars. delete $options->{filter}; } # a recursive sub that associates each loop with the loops above # (treating the top-level as a loop) sub _globalize_vars { my $self = shift; # associate with the loop (and top-level templates) above in the tree. push(@{$self->{options}{associate}}, @_); # recurse down into the template tree, adding ourself to the end of # list. push(@_, $self); map { $_->_globalize_vars(@_) } map { values %{$_->[HTML::Template::LOOP::TEMPLATE_HASH]} } grep { ref($_) eq 'HTML::Template::LOOP' } @{$self->{parse_stack}}; } # method used to recursively un-hook associate sub _unglobalize_vars { my $self = shift; # disassociate $self->{options}{associate} = undef; # recurse down into the template tree disassociating map { $_->_unglobalize_vars() } map { values %{$_->[HTML::Template::LOOP::TEMPLATE_HASH]} } grep { ref($_) eq 'HTML::Template::LOOP' } @{$self->{parse_stack}}; } =head2 config A package method that is used to set/get the global default configuration options. For instance, if you want to set the C flag to always be on for every template loaded by this process you would do: HTML::Template->config(utf8 => 1); Or if you wanted to check if the C flag was on or not, you could do: my %config = HTML::Template->config; if( $config{utf8} ) { ... } Any configuration options that are valid for C are acceptable to be passed to this method. =cut sub config { my ($pkg, %options) = @_; foreach my $opt (keys %options) { if( $opt eq 'associate' || $opt eq 'filter' || $opt eq 'path' ) { push(@{$OPTIONS{$opt}}, $options{$opt}); } else { $OPTIONS{$opt} = $options{$opt}; } } return %OPTIONS; } =head2 param C can be called in a number of ways =over =item 1 - To return a list of parameters in the template : my @parameter_names = $self->param(); =item 2 - To return the value set to a param : my $value = $self->param('PARAM'); =item 3 - To set the value of a parameter : # For simple TMPL_VARs: $self->param(PARAM => 'value'); # with a subroutine reference that gets called to get the value # of the scalar. The sub will receive the template object as a # parameter. $self->param(PARAM => sub { return 'value' }); # And TMPL_LOOPs: $self->param(LOOP_PARAM => [{PARAM => VALUE_FOR_FIRST_PASS}, {PARAM => VALUE_FOR_SECOND_PASS}]); =item 4 - To set the value of a number of parameters : # For simple TMPL_VARs: $self->param( PARAM => 'value', PARAM2 => 'value' ); # And with some TMPL_LOOPs: $self->param( PARAM => 'value', PARAM2 => 'value', LOOP_PARAM => [{PARAM => VALUE_FOR_FIRST_PASS}, {PARAM => VALUE_FOR_SECOND_PASS}], ANOTHER_LOOP_PARAM => [{PARAM => VALUE_FOR_FIRST_PASS}, {PARAM => VALUE_FOR_SECOND_PASS}], ); =item 5 - To set the value of a number of parameters using a hash-ref : $self->param( { PARAM => 'value', PARAM2 => 'value', LOOP_PARAM => [{PARAM => VALUE_FOR_FIRST_PASS}, {PARAM => VALUE_FOR_SECOND_PASS}], ANOTHER_LOOP_PARAM => [{PARAM => VALUE_FOR_FIRST_PASS}, {PARAM => VALUE_FOR_SECOND_PASS}], } ); An error occurs if you try to set a value that is tainted if the C option is set. =back =cut sub param { my $self = shift; my $options = $self->{options}; my $param_map = $self->{param_map}; # the no-parameter case - return list of parameters in the template. return keys(%$param_map) unless scalar(@_); my $first = shift; my $type = ref $first; # the one-parameter case - could be a parameter value request or a # hash-ref. if (!scalar(@_) and !length($type)) { my $param = $options->{case_sensitive} ? $first : lc $first; # check for parameter existence $options->{die_on_bad_params} and !exists($param_map->{$param}) and croak( "HTML::Template : Attempt to get nonexistent parameter '$param' - this parameter name doesn't match any declarations in the template file : (die_on_bad_params set => 1)" ); return undef unless (exists($param_map->{$param}) and defined($param_map->{$param})); return ${$param_map->{$param}} if (ref($param_map->{$param}) eq 'HTML::Template::VAR'); return $param_map->{$param}[HTML::Template::LOOP::PARAM_SET]; } if (!scalar(@_)) { croak("HTML::Template->param() : Single reference arg to param() must be a hash-ref! You gave me a $type.") unless $type eq 'HASH' or UNIVERSAL::isa($first, 'HASH'); push(@_, %$first); } else { unshift(@_, $first); } croak("HTML::Template->param() : You gave me an odd number of parameters to param()!") unless ((@_ % 2) == 0); # strangely, changing this to a "while(@_) { shift, shift }" type # loop causes perl 5.004_04 to die with some nonsense about a # read-only value. for (my $x = 0 ; $x <= $#_ ; $x += 2) { my $param = $options->{case_sensitive} ? $_[$x] : lc $_[$x]; my $value = $_[($x + 1)]; # check that this param exists in the template $options->{die_on_bad_params} and !exists($param_map->{$param}) and croak( "HTML::Template : Attempt to set nonexistent parameter '$param' - this parameter name doesn't match any declarations in the template file : (die_on_bad_params => 1)" ); # if we're not going to die from bad param names, we need to ignore # them... unless (exists($param_map->{$param})) { next if not $options->{parent_global_vars}; # ... unless global vars is on - in which case we can't be # sure we won't need it in a lower loop. if (ref($value) eq 'ARRAY') { $param_map->{$param} = HTML::Template::LOOP->new(); } else { $param_map->{$param} = HTML::Template::VAR->new(); } } # figure out what we've got, taking special care to allow for # objects that are compatible underneath. my $type = ref $value || ''; if ($type eq 'REF') { croak("HTML::Template::param() : attempt to set parameter '$param' with a reference to a reference!"); } elsif ($type && ($type eq 'ARRAY' || ($type !~ /^(CODE)|(HASH)|(SCALAR)$/ && $value->isa('ARRAY')))) { ref($param_map->{$param}) eq 'HTML::Template::LOOP' || croak( "HTML::Template::param() : attempt to set parameter '$param' with an array ref - parameter is not a TMPL_LOOP!"); $param_map->{$param}[HTML::Template::LOOP::PARAM_SET] = [@{$value}]; } elsif( $type eq 'CODE' ) { # code can be used for a var or a loop if( ref($param_map->{$param}) eq 'HTML::Template::LOOP' ) { $param_map->{$param}[HTML::Template::LOOP::PARAM_SET] = $value; } else { ${$param_map->{$param}} = $value; } } else { ref($param_map->{$param}) eq 'HTML::Template::VAR' || croak( "HTML::Template::param() : attempt to set parameter '$param' with a scalar - parameter is not a TMPL_VAR!"); ${$param_map->{$param}} = $value; } } } =head2 clear_params Sets all the parameters to undef. Useful internally, if nowhere else! =cut sub clear_params { my $self = shift; my $type; foreach my $name (keys %{$self->{param_map}}) { $type = ref($self->{param_map}{$name}); undef(${$self->{param_map}{$name}}) if ($type eq 'HTML::Template::VAR'); undef($self->{param_map}{$name}[HTML::Template::LOOP::PARAM_SET]) if ($type eq 'HTML::Template::LOOP'); } } # obsolete implementation of associate sub associateCGI { my $self = shift; my $cgi = shift; (ref($cgi) eq 'CGI') or croak("Warning! non-CGI object was passed to HTML::Template::associateCGI()!\n"); push(@{$self->{options}{associate}}, $cgi); return 1; } =head2 output C returns the final result of the template. In most situations you'll want to print this, like: print $template->output(); When output is called each occurrence of C<< >> is replaced with the value assigned to "name" via C. If a named parameter is unset it is simply replaced with ''. C<< >>s are evaluated once per parameter set, accumulating output on each pass. Calling C is guaranteed not to change the state of the HTML::Template object, in case you were wondering. This property is mostly important for the internal implementation of loops. You may optionally supply a filehandle to print to automatically as the template is generated. This may improve performance and lower memory consumption. Example: $template->output(print_to => *STDOUT); The return value is undefined when using the C option. =cut use vars qw(%URLESCAPE_MAP); sub output { my $self = shift; my $options = $self->{options}; local $_; croak("HTML::Template->output() : You gave me an odd number of parameters to output()!") unless ((@_ % 2) == 0); my %args = @_; print STDERR "### HTML::Template Memory Debug ### START OUTPUT ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; $options->{debug} and print STDERR "### HTML::Template Debug ### In output\n"; # want a stack dump? if ($options->{stack_debug}) { require 'Data/Dumper.pm'; print STDERR "### HTML::Template output Stack Dump ###\n\n", Data::Dumper::Dumper($self->{parse_stack}), "\n"; } # globalize vars - this happens here to localize the circular # references created by global_vars. $self->_globalize_vars() if ($options->{global_vars}); # support the associate magic, searching for undefined params and # attempting to fill them from the associated objects. if (scalar(@{$options->{associate}})) { # prepare case-mapping hashes to do case-insensitive matching # against associated objects. This allows CGI.pm to be # case-sensitive and still work with associate. my (%case_map, $lparam); foreach my $associated_object (@{$options->{associate}}) { # what a hack! This should really be optimized out for case_sensitive. if ($options->{case_sensitive}) { map { $case_map{$associated_object}{$_} = $_ } $associated_object->param(); } else { map { $case_map{$associated_object}{lc($_)} = $_ } $associated_object->param(); } } foreach my $param (keys %{$self->{param_map}}) { unless (defined($self->param($param))) { OBJ: foreach my $associated_object (reverse @{$options->{associate}}) { $self->param($param, scalar $associated_object->param($case_map{$associated_object}{$param})), last OBJ if (exists($case_map{$associated_object}{$param})); } } } } use vars qw($line @parse_stack); local (*line, *parse_stack); # walk the parse stack, accumulating output in $result *parse_stack = $self->{parse_stack}; my $result = ''; tie $result, 'HTML::Template::PRINTSCALAR', $args{print_to} if defined $args{print_to} && !eval { tied *{$args{print_to}} }; my $type; my $parse_stack_length = $#parse_stack; for (my $x = 0 ; $x <= $parse_stack_length ; $x++) { *line = \$parse_stack[$x]; $type = ref($line); if ($type eq 'SCALAR') { $result .= $$line; } elsif ($type eq 'HTML::Template::VAR' and ref($$line) eq 'CODE') { if (defined($$line)) { my $tmp_val = $$line->($self); croak("HTML::Template->output() : 'force_untaint' option but coderef returns tainted value") if $options->{force_untaint} && tainted($tmp_val); $result .= $tmp_val; # change the reference to point to the value now not the code reference $$line = $tmp_val if $options->{cache_lazy_vars} } } elsif ($type eq 'HTML::Template::VAR') { if (defined $$line) { if ($options->{force_untaint} && tainted($$line)) { croak("HTML::Template->output() : tainted value with 'force_untaint' option"); } $result .= $$line; } } elsif ($type eq 'HTML::Template::LOOP') { if (defined($line->[HTML::Template::LOOP::PARAM_SET])) { eval { $result .= $line->output($x, $options->{loop_context_vars}); }; croak("HTML::Template->output() : fatal error in loop output : $@") if $@; } } elsif ($type eq 'HTML::Template::COND') { if ($line->[HTML::Template::COND::UNCONDITIONAL_JUMP]) { $x = $line->[HTML::Template::COND::JUMP_ADDRESS]; } else { if ($line->[HTML::Template::COND::JUMP_IF_TRUE]) { if ($line->[HTML::Template::COND::VARIABLE_TYPE] == HTML::Template::COND::VARIABLE_TYPE_VAR) { if (defined ${$line->[HTML::Template::COND::VARIABLE]}) { if (ref(${$line->[HTML::Template::COND::VARIABLE]}) eq 'CODE') { my $tmp_val = ${$line->[HTML::Template::COND::VARIABLE]}->($self); $x = $line->[HTML::Template::COND::JUMP_ADDRESS] if $tmp_val; ${$line->[HTML::Template::COND::VARIABLE]} = $tmp_val if $options->{cache_lazy_vars}; } else { $x = $line->[HTML::Template::COND::JUMP_ADDRESS] if ${$line->[HTML::Template::COND::VARIABLE]}; } } } else { # if it's a code reference, execute it to get the values my $loop_values = $line->[HTML::Template::COND::VARIABLE][HTML::Template::LOOP::PARAM_SET]; if (defined $loop_values && ref $loop_values eq 'CODE') { $loop_values = $loop_values->($self); $line->[HTML::Template::COND::VARIABLE][HTML::Template::LOOP::PARAM_SET] = $loop_values if $options->{cache_lazy_loops}; } # if we have anything for the loop, jump to the next part if (defined $loop_values && @$loop_values) { $x = $line->[HTML::Template::COND::JUMP_ADDRESS]; } } } else { if ($line->[HTML::Template::COND::VARIABLE_TYPE] == HTML::Template::COND::VARIABLE_TYPE_VAR) { if (defined ${$line->[HTML::Template::COND::VARIABLE]}) { if (ref(${$line->[HTML::Template::COND::VARIABLE]}) eq 'CODE') { my $tmp_val = ${$line->[HTML::Template::COND::VARIABLE]}->($self); $x = $line->[HTML::Template::COND::JUMP_ADDRESS] unless $tmp_val; ${$line->[HTML::Template::COND::VARIABLE]} = $tmp_val if $options->{cache_lazy_vars}; } else { $x = $line->[HTML::Template::COND::JUMP_ADDRESS] unless ${$line->[HTML::Template::COND::VARIABLE]}; } } else { $x = $line->[HTML::Template::COND::JUMP_ADDRESS]; } } else { # if we don't have anything for the loop, jump to the next part my $loop_values = $line->[HTML::Template::COND::VARIABLE][HTML::Template::LOOP::PARAM_SET]; if(!defined $loop_values) { $x = $line->[HTML::Template::COND::JUMP_ADDRESS]; } else { # check to see if the loop is a code ref and if it is execute it to get the values if( ref $loop_values eq 'CODE' ) { $loop_values = $line->[HTML::Template::COND::VARIABLE][HTML::Template::LOOP::PARAM_SET]->($self); $line->[HTML::Template::COND::VARIABLE][HTML::Template::LOOP::PARAM_SET] = $loop_values if $options->{cache_lazy_loops}; } # if we don't have anything in the loop, jump to the next part if(!@$loop_values) { $x = $line->[HTML::Template::COND::JUMP_ADDRESS]; } } } } } } elsif ($type eq 'HTML::Template::NOOP') { next; } elsif ($type eq 'HTML::Template::DEF') { $_ = $x; # remember default place in stack # find next VAR, there might be an ESCAPE in the way *line = \$parse_stack[++$x]; *line = \$parse_stack[++$x] if ref $line eq 'HTML::Template::ESCAPE' or ref $line eq 'HTML::Template::JSESCAPE' or ref $line eq 'HTML::Template::URLESCAPE'; # either output the default or go back if (defined $$line) { $x = $_; } else { $result .= ${$parse_stack[$_]}; } next; } elsif ($type eq 'HTML::Template::ESCAPE') { *line = \$parse_stack[++$x]; if (defined($$line)) { my $tmp_val; if (ref($$line) eq 'CODE') { $tmp_val = $$line->($self); if ($options->{force_untaint} > 1 && tainted($_)) { croak("HTML::Template->output() : 'force_untaint' option but coderef returns tainted value"); } $$line = $tmp_val if $options->{cache_lazy_vars}; } else { $tmp_val = $$line; if ($options->{force_untaint} > 1 && tainted($_)) { croak("HTML::Template->output() : tainted value with 'force_untaint' option"); } } # straight from the CGI.pm bible. $tmp_val =~ s/&/&/g; $tmp_val =~ s/\"/"/g; $tmp_val =~ s/>/>/g; $tmp_val =~ s/($self); if ($options->{force_untaint} > 1 && tainted($_)) { croak("HTML::Template->output() : 'force_untaint' option but coderef returns tainted value"); } $$line = $tmp_val if $options->{cache_lazy_vars}; } else { $tmp_val = $$line; if ($options->{force_untaint} > 1 && tainted($_)) { croak("HTML::Template->output() : tainted value with 'force_untaint' option"); } } $tmp_val =~ s/\\/\\\\/g; $tmp_val =~ s/'/\\'/g; $tmp_val =~ s/"/\\"/g; $tmp_val =~ s/[\n\x{2028}]/\\n/g; $tmp_val =~ s/\x{2029}/\\n\\n/g; $tmp_val =~ s/\r/\\r/g; $result .= $tmp_val; } } elsif ($type eq 'HTML::Template::URLESCAPE') { $x++; *line = \$parse_stack[$x]; if (defined($$line)) { my $tmp_val; if (ref($$line) eq 'CODE') { $tmp_val = $$line->($self); if ($options->{force_untaint} > 1 && tainted($_)) { croak("HTML::Template->output() : 'force_untaint' option but coderef returns tainted value"); } $$line = $tmp_val if $options->{cache_lazy_vars}; } else { $tmp_val = $$line; if ($options->{force_untaint} > 1 && tainted($_)) { croak("HTML::Template->output() : tainted value with 'force_untaint' option"); } } # Build a char->hex map if one isn't already available unless (exists($URLESCAPE_MAP{chr(1)})) { for (0 .. 255) { $URLESCAPE_MAP{chr($_)} = sprintf('%%%02X', $_); } } # do the translation (RFC 2396 ^uric) $tmp_val =~ s!([^a-zA-Z0-9_.\-])!$URLESCAPE_MAP{$1}!g; $result .= $tmp_val; } } else { confess("HTML::Template::output() : Unknown item in parse_stack : " . $type); } } # undo the globalization circular refs $self->_unglobalize_vars() if ($options->{global_vars}); print STDERR "### HTML::Template Memory Debug ### END OUTPUT ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; return undef if defined $args{print_to}; return $result; } =head2 query This method allow you to get information about the template structure. It can be called in a number of ways. The simplest usage of query is simply to check whether a parameter name exists in the template, using the C option: if ($template->query(name => 'foo')) { # do something if a variable of any type named FOO is in the template } This same usage returns the type of the parameter. The type is the same as the tag minus the leading 'TMPL_'. So, for example, a C parameter returns 'VAR' from C. if ($template->query(name => 'foo') eq 'VAR') { # do something if FOO exists and is a TMPL_VAR } Note that the variables associated with Cs and Cs will be identified as 'VAR' unless they are also used in a C, in which case they will return 'LOOP'. C also allows you to get a list of parameters inside a loop (and inside loops inside loops). Example loop: And some query calls: # returns 'LOOP' $type = $template->query(name => 'EXAMPLE_LOOP'); # returns ('bop', 'bee', 'example_inner_loop') @param_names = $template->query(loop => 'EXAMPLE_LOOP'); # both return 'VAR' $type = $template->query(name => ['EXAMPLE_LOOP', 'BEE']); $type = $template->query(name => ['EXAMPLE_LOOP', 'BOP']); # and this one returns 'LOOP' $type = $template->query(name => ['EXAMPLE_LOOP', 'EXAMPLE_INNER_LOOP']); # and finally, this returns ('inner_bee', 'inner_bop') @inner_param_names = $template->query(loop => ['EXAMPLE_LOOP', 'EXAMPLE_INNER_LOOP']); # for non existent parameter names you get undef this returns undef. $type = $template->query(name => 'DWEAZLE_ZAPPA'); # calling loop on a non-loop parameter name will cause an error. This dies: $type = $template->query(loop => 'DWEAZLE_ZAPPA'); As you can see above the C option returns a list of parameter names and both C and C take array refs in order to refer to parameters inside loops. It is an error to use C with a parameter that is not a loop. Note that all the names are returned in lowercase and the types are uppercase. Just like C, C with no arguments returns all the parameter names in the template at the top level. =cut sub query { my $self = shift; $self->{options}{debug} and print STDERR "### HTML::Template Debug ### query(", join(', ', @_), ")\n"; # the no-parameter case - return $self->param() return $self->param() unless scalar(@_); croak("HTML::Template::query() : Odd number of parameters passed to query!") if (scalar(@_) % 2); croak("HTML::Template::query() : Wrong number of parameters passed to query - should be 2.") if (scalar(@_) != 2); my ($opt, $path) = (lc shift, shift); croak("HTML::Template::query() : invalid parameter ($opt)") unless ($opt eq 'name' or $opt eq 'loop'); # make path an array unless it already is $path = [$path] unless (ref $path); # find the param in question. my @objs = $self->_find_param(@$path); return undef unless scalar(@objs); my ($obj, $type); # do what the user asked with the object if ($opt eq 'name') { # we only look at the first one. new() should make sure they're # all the same. ($obj, $type) = (shift(@objs), shift(@objs)); return undef unless defined $obj; return 'VAR' if $type eq 'HTML::Template::VAR'; return 'LOOP' if $type eq 'HTML::Template::LOOP'; croak("HTML::Template::query() : unknown object ($type) in param_map!"); } elsif ($opt eq 'loop') { my %results; while (@objs) { ($obj, $type) = (shift(@objs), shift(@objs)); croak( "HTML::Template::query() : Search path [", join(', ', @$path), "] doesn't end in a TMPL_LOOP - it is an error to use the 'loop' option on a non-loop parameter. To avoid this problem you can use the 'name' option to query() to check the type first." ) unless ((defined $obj) and ($type eq 'HTML::Template::LOOP')); # SHAZAM! This bit extracts all the parameter names from all the # loop objects for this name. map { $results{$_} = 1 } map { keys(%{$_->{'param_map'}}) } values(%{$obj->[HTML::Template::LOOP::TEMPLATE_HASH]}); } # this is our loop list, return it. return keys(%results); } } # a function that returns the object(s) corresponding to a given path and # its (their) ref()(s). Used by query() in the obvious way. sub _find_param { my $self = shift; my $spot = $self->{options}{case_sensitive} ? shift : lc shift; # get the obj and type for this spot my $obj = $self->{'param_map'}{$spot}; return unless defined $obj; my $type = ref $obj; # return if we're here or if we're not but this isn't a loop return ($obj, $type) unless @_; return unless ($type eq 'HTML::Template::LOOP'); # recurse. this is a depth first search on the template tree, for # the algorithm geeks in the audience. return map { $_->_find_param(@_) } values(%{$obj->[HTML::Template::LOOP::TEMPLATE_HASH]}); } # HTML::Template::VAR, LOOP, etc are *light* objects - their internal # spec is used above. No encapsulation or information hiding is to be # assumed. package HTML::Template::VAR; sub new { my $value; return bless(\$value, $_[0]); } package HTML::Template::DEF; sub new { my $value = $_[1]; return bless(\$value, $_[0]); } package HTML::Template::LOOP; sub new { return bless([], $_[0]); } sub output { my $self = shift; my $index = shift; my $loop_context_vars = shift; my $template = $self->[TEMPLATE_HASH]{$index}; my $value_sets_array = $self->[PARAM_SET]; return unless defined($value_sets_array); my $result = ''; my $count = 0; my $odd = 0; # execute the code to get the values if it's a code reference if( ref $value_sets_array eq 'CODE' ) { $value_sets_array = $value_sets_array->($template); croak("HTML::Template->output: TMPL_LOOP code reference did not return an ARRAY reference!") unless ref $value_sets_array && ref $value_sets_array eq 'ARRAY'; $self->[PARAM_SET] = $value_sets_array if $template->{options}->{cache_lazy_loops}; } foreach my $value_set (@$value_sets_array) { if ($loop_context_vars) { if ($count == 0) { @{$value_set}{qw(__first__ __inner__ __outer__ __last__)} = (1, 0, 1, $#{$value_sets_array} == 0); } elsif ($count == $#{$value_sets_array}) { @{$value_set}{qw(__first__ __inner__ __outer__ __last__)} = (0, 0, 1, 1); } else { @{$value_set}{qw(__first__ __inner__ __outer__ __last__)} = (0, 1, 0, 0); } $odd = $value_set->{__odd__} = !$odd; $value_set->{__even__} = !$odd; $value_set->{__counter__} = $count + 1; $value_set->{__index__} = $count; } $template->param($value_set); $result .= $template->output; $template->clear_params; @{$value_set}{qw(__first__ __last__ __inner__ __outer__ __odd__ __even__ __counter__ __index__)} = (0, 0, 0, 0, 0, 0, 0) if ($loop_context_vars); $count++; } return $result; } package HTML::Template::COND; sub new { my $pkg = shift; my $var = shift; my $self = []; $self->[VARIABLE] = $var; bless($self, $pkg); return $self; } package HTML::Template::NOOP; sub new { my $unused; my $self = \$unused; bless($self, $_[0]); return $self; } package HTML::Template::ESCAPE; sub new { my $unused; my $self = \$unused; bless($self, $_[0]); return $self; } package HTML::Template::JSESCAPE; sub new { my $unused; my $self = \$unused; bless($self, $_[0]); return $self; } package HTML::Template::URLESCAPE; sub new { my $unused; my $self = \$unused; bless($self, $_[0]); return $self; } # scalar-tying package for output(print_to => *HANDLE) implementation package HTML::Template::PRINTSCALAR; use strict; sub TIESCALAR { bless \$_[1], $_[0]; } sub FETCH { } sub STORE { my $self = shift; local *FH = $$self; print FH @_; } 1; __END__ =head1 LAZY VALUES As mentioned above, both C and C values can be code references. These code references are only executed if the variable or loop is used in the template. This is extremely useful if you want to make a variable available to template designers but it can be expensive to calculate, so you only want to do so if you have to. Maybe an example will help to illustrate. Let's say you have a template like this: If C is expensive to calculate we can wrap it's calculation in a code reference and HTML::Template will only execute that code if C is also true. $tmpl->param(life_universe_and_everything => sub { calculate_42() }); Your code reference will be given a single argument, the HTML::Template object in use. In the above example, if we wanted C to have this object we'd do something like this: $tmpl->param(life_universe_and_everything => sub { calculate_42(shift) }); This same approach can be used for Cs too: Found ! And in your Perl code: $tmpl->param(needles_in_haystack => sub { find_needles() }); The only difference in the C case is that the subroutine needs to return a reference to an ARRAY, not just a scalar value. =head2 Multiple Calls It's important to recognize that while this feature is designed to save processing time when things aren't needed, if you're not careful it can actually increase the number of times you perform your calculation. HTML::Template calls your code reference each time it seems your loop in the template, this includes the times that you might use the loop in a conditional (C or C). For instance: Found ! No needles found! This will actually call C twice which will be even worse than you had before. One way to work around this is to cache the return value yourself: my $needles; $tmpl->param(needles_in_haystack => sub { defined $needles ? $needles : $needles = find_needles() }); =head1 BUGS I am aware of no bugs - if you find one, join the mailing list and tell us about it. You can join the HTML::Template mailing-list by visiting: http://lists.sourceforge.net/lists/listinfo/html-template-users Of course, you can still email me directly (C) with bugs, but I reserve the right to forward bug reports to the mailing list. When submitting bug reports, be sure to include full details, including the VERSION of the module, a test script and a test template demonstrating the problem! If you're feeling really adventurous, HTML::Template has a publically available Git repository. See below for more information in the PUBLIC GIT REPOSITORY section. =head1 CREDITS This module was the brain child of my boss, Jesse Erlbaum (C) at Vanguard Media (http://vm.com) . The most original idea in this module - the C<< >> - was entirely his. Fixes, Bug Reports, Optimizations and Ideas have been generously provided by: =over =item * Richard Chen =item * Mike Blazer =item * Adriano Nagelschmidt Rodrigues =item * Andrej Mikus =item * Ilya Obshadko =item * Kevin Puetz =item * Steve Reppucci =item * Richard Dice =item * Tom Hukins =item * Eric Zylberstejn =item * David Glasser =item * Peter Marelas =item * James William Carlson =item * Frank D. Cringle =item * Winfried Koenig =item * Matthew Wickline =item * Doug Steinwand =item * Drew Taylor =item * Tobias Brox =item * Michael Lloyd =item * Simran Gambhir =item * Chris Houser =item * Larry Moore =item * Todd Larason =item * Jody Biggs =item * T.J. Mather =item * Martin Schroth =item * Dave Wolfe =item * uchum =item * Kawai Takanori =item * Peter Guelich =item * Chris Nokleberg =item * Ralph Corderoy =item * William Ward =item * Ade Olonoh =item * Mark Stosberg =item * Lance Thomas =item * Roland Giersig =item * Jere Julian =item * Peter Leonard =item * Kenny Smith =item * Sean P. Scanlon =item * Martin Pfeffer =item * David Ferrance =item * Gyepi Sam =item * Darren Chamberlain =item * Paul Baker =item * Gabor Szabo =item * Craig Manley =item * Richard Fein =item * The Phalanx Project =item * Sven Neuhaus =item * Michael Peters =item * Jan Dubois =item * Moritz Lenz =back Thanks! =head1 WEBSITE You can find information about HTML::Template and other related modules at: http://html-template.sourceforge.net =head1 PUBLIC GIT REPOSITORY HTML::Template now has a publicly accessible Git repository provided by GitHub (github.com). You can access it by going to https://github.com/mpeters/html-template. Give it a try! =head1 AUTHOR Sam Tregar, C =head1 CO-MAINTAINER Michael Peters, C =head1 LICENSE HTML::Template : A module for using HTML Templates with Perl Copyright (C) 2000-2011 Sam Tregar (sam@tregar.com) This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself, which means using either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" which comes with this module. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details. You should have received a copy of the Artistic License with this module. If not, I'll be glad to provide one. You should have received a copy of the GNU General Public License along with this program. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =cut HTML-Template-2.97/lib/HTML/Template/0000775000175000017500000000000013107402001015165 5ustar samsamHTML-Template-2.97/lib/HTML/Template/FAQ.pm0000644000175000017500000001264613107402001016141 0ustar samsamuse strict; use warnings; package HTML::Template::FAQ; # ABSTRACT: Frequently Asked Questions about HTML::Template use Carp (); Carp::confess "you're not meant to use the FAQ, just read it!"; 1; __END__ =pod =head1 NAME HTML::Template::FAQ - Frequently Asked Questions about HTML::Template =head1 SYNOPSIS In the interest of greater understanding I've started a FAQ section of the perldocs. Please look in here before you send me email. =head1 FREQUENTLY ASKED QUESTIONS =head2 Is there a place to go to discuss HTML::Template and/or get help? There's a mailing-list for discussing L at html-template-users@lists.sourceforge.net. Join at: http://lists.sourceforge.net/lists/listinfo/html-template-users If you just want to get email when new releases are available you can join the announcements mailing-list here: http://lists.sourceforge.net/lists/listinfo/html-template-announce =head2 Is there a searchable archive for the mailing-list? Yes, you can find an archive of the SourceForge list here: http://dir.gmane.org/gmane.comp.lang.perl.modules.html-template =head2 I want support for ! How about it? Maybe. I definitely encourage people to discuss their ideas for L on the mailing list. Please be ready to explain to me how the new tag fits in with HTML::Template's mission to provide a fast, lightweight system for using HTML templates. NOTE: Offering to program said addition and provide it in the form of a patch to the most recent version of L will definitely have a softening effect on potential opponents! =head2 I found a bug, can you fix it? That depends. Did you send me the VERSION of L, a test script and a test template? If so, then almost certainly. If you're feeling really adventurous, L is publicly available on GitHub (https://github.com/mpeters/html-template). Please feel free to fork it and send me a pull request with any changes you have. =head2 s from the main template aren't working inside a ! Why? This is the intended behavior. C<< >> introduces a separate scope for C<< s >> much like a subroutine call in Perl introduces a separate scope for C variables. If you want your C<< >>s to be global you can set the C option when you call C. See above for documentation of the C C option. =head2 How can I pre-load my templates using cache-mode and mod_perl? Add something like this to your startup.pl: use HTML::Template; use File::Find; print STDERR "Pre-loading HTML Templates...\n"; find( sub { return unless /\.tmpl$/; HTML::Template->new( filename => "$File::Find::dir/$_", cache => 1, ); }, '/path/to/templates', '/another/path/to/templates/' ); Note that you'll need to modify the C line to specify the extension you use for your template files - I use F<.tmpl>, as you can see. You'll also need to specify the path to your template files. One potential problem: the F must be B the same path you use when you call C<< HTML::Template->new() >>. Otherwise the cache won't know they're the same file and will load a new copy - instead getting a speed increase, you'll double your memory usage. To find out if this is happening set C 1> in your application code and look for "CACHE MISS" messages in the logs. =head2 What characters are allowed in TMPL_* names? Numbers, letters, '.', '/', '+', '-' and '_'. =head2 How can I execute a program from inside my template? Short answer: you can't. Longer answer: you shouldn't since this violates the fundamental concept behind L - that design and code should be separate. But, inevitably some people still want to do it. If that describes you then you should take a look at L. Using L it should be easy to write a C function. Then you can do awful stuff like: Just, please, don't tell me about it. I'm feeling guilty enough just for writing L in the first place. =head2 What's the best way to create a >> element entirely inside the template. What you end up with is a rat's nest of loops and conditionals. Alternately you can give up a certain amount of flexibility in return for vastly simplifying your templates. I generally choose the latter. Another option is to investigate L which some have reported success using to solve this problem. HTML-Template-2.97/bench/0000775000175000017500000000000013107402001013157 5ustar samsamHTML-Template-2.97/bench/profile_small.pl0000755000175000017500000000041513107402001016345 0ustar samsam#!/usr/bin/env perl use strict; use warnings; use lib '../lib'; use HTML::Template; my $tmpl = HTML::Template->new(filename => 'templates/default.tmpl'); $tmpl->param( a => 'foo', cl => 'bar', start => 'baz', sh => 'blah', ); $tmpl->output; HTML-Template-2.97/bench/profile_var.pl0000755000175000017500000002426713107402001016040 0ustar samsam#!/usr/bin/env perl use strict; use warnings; use lib '../lib'; use Benchmark 'timethese'; use HTML::Template; timethese( 1_000, { small_template => sub { my $tmpl = HTML::Template->new(filename => 'templates/default.tmpl'); $tmpl->param( a => 'foo', cl => 'bar', start => 'baz', sh => 'blah', ); $tmpl->output; }, medium_template => sub { my $tmpl = HTML::Template->new(filename => 'templates/medium.tmpl'); $tmpl->param( 'alert' => 'I am alert.', 'company_name' => "MY NAME IS", 'company_id' => "10001", 'office_id' => "10103214", 'name' => 'SAM I AM', 'address' => '101011 North Something Something', 'city' => 'NEW York', 'state' => 'NEw York', 'zip' => '10014', 'phone' => '212-929-4315', 'phone2' => '', 'subcategories' => 'kfldjaldsf', 'description' => "dsa;kljkldasfjkldsajflkjdsfklfjdsgkfld\nalskdjklajsdlkajfdlkjsfd\n\talksjdklajsfdkljdsf\ndsa;klfjdskfj", 'website' => 'http://www.assforyou.com/', 'intranet_url' => 'http://www.something.com', 'remove_button' => "", 'company_admin_area' => "Manage Office Administrators", 'casestudies_list' => "adsfkljdskldszfgfdfdsgdsfgfdshghdmfldkgjfhdskjfhdskjhfkhdsakgagsfjhbvdsaj hsgbf jhfg sajfjdsag ffasfj hfkjhsdkjhdsakjfhkj kjhdsfkjhdskfjhdskjfkjsda kjjsafdkjhds kjds fkj skjh fdskjhfkj kj kjhf kjh sfkjhadsfkj hadskjfhkjhs ajhdsfkj akj fkj kj kj kkjdsfhk skjhadskfj haskjh fkjsahfkjhsfk ksjfhdkjh sfkjhdskjfhakj shiou weryheuwnjcinuc 3289u4234k 5 i 43iundsinfinafiunai saiufhiudsaf afiuhahfwefna uwhf u auiu uh weiuhfiuh iau huwehiucnaiuncianweciuninc iuaciun iucniunciunweiucniuwnciwe", 'number_of_contacts' => "aksfjdkldsajfkljds", 'country_selector' => "klajslkjdsafkljds", 'logo_link' => "dsfpkjdsfkgljdsfkglj", 'photo_link' => "lsadfjlkfjdsgkljhfgklhasgh", ); $tmpl->output; }, large_template => sub { my $tmpl = HTML::Template->new(filename => 'templates/long_loops.tmpl'); $tmpl->param( propname => 'foo', javascript => '', hotel_key => 'bar&>?/', alert => 'Danger!&!', new_comment_button => 'Click Me!', comments => [ { color => 'black', posted_by => 'me & you', posted_on => '', stars => '10', comment => 'Super & duper cool stuff!', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'blue', posted_by => 'you & I', posted_on => '2 days ', stars => '5', comment => 'It is ok ', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'yellow', posted_by => 'someone & someone else', posted_on => '4 days ', stars => '4', comment => 'It would not kill me to go back & spend more time there', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'blue', posted_by => 'someone else!&!', posted_on => '<4 days ago>', stars => '6', comment => 'I enjoyed the ', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'red', posted_by => 'someone else <&>', stars => '6', approval_button => 'No, Click Me!', }, {}, ], comment_editor => [ { color => 'black', posted_by => 'me', posted_on => 'yesterday', stars => '10', comment => 'Super duper cool stuff!', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'blue', posted_by => 'you', posted_on => '2 days ago', stars => '5', comment => 'It is ok', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'yellow', posted_by => 'someone', posted_on => '4 days ago', stars => '4', comment => 'It would not kill me to go back', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'blue', posted_by => 'someone else', posted_on => '4 days ago', stars => '6', comment => 'I enjoyed the bed', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'red', posted_by => 'someone else', stars => '6', cancel_button => 'No you are not.', }, {}, ], comment_created => [ {posted_by => 'Fred'}, {posted_by => 'George'}, {posted_by => 'Thomas'}, {posted_by => 'Dan'}, {posted_by => 'Henry'}, {posted_by => 'Michael'}, {posted_by => 'Nelson'}, {posted_by => 'Brad'}, {posted_by => 'Rodney'}, {posted_by => 'Jose'}, {posted_by => 'Marie'}, {posted_by => 'Eric'}, {posted_by => 'Isaac'}, {posted_by => 'Rusty'}, {posted_by => 'Jacob'}, {posted_by => 'Alice'}, {posted_by => 'Kelly'}, {posted_by => 'Juan'}, {posted_by => 'Lewis'}, {posted_by => 'Fredrick'}, {posted_by => 'Manny'}, {posted_by => 'Dee'}, {posted_by => 'Nort'}, {posted_by => 'Jeanne'}, {posted_by => 'Oscar'}, {posted_by => 'Peter'}, {posted_by => 'Russel'}, {posted_by => 'Steve'}, {posted_by => 'Timmy'}, {posted_by => 'Vance'}, {}, ], ); }, } ); HTML-Template-2.97/bench/vars.pl0000755000175000017500000002426713107402001014503 0ustar samsam#!/usr/bin/env perl use strict; use warnings; use Benchmark 'timethese'; use lib '../lib'; use HTML::Template; timethese( 1_000, { small_template => sub { my $tmpl = HTML::Template->new(filename => 'templates/default.tmpl'); $tmpl->param( a => 'foo', cl => 'bar', start => 'baz', sh => 'blah', ); $tmpl->output; }, medium_template => sub { my $tmpl = HTML::Template->new(filename => 'templates/medium.tmpl'); $tmpl->param( 'alert' => 'I am alert.', 'company_name' => "MY NAME IS", 'company_id' => "10001", 'office_id' => "10103214", 'name' => 'SAM I AM', 'address' => '101011 North Something Something', 'city' => 'NEW York', 'state' => 'NEw York', 'zip' => '10014', 'phone' => '212-929-4315', 'phone2' => '', 'subcategories' => 'kfldjaldsf', 'description' => "dsa;kljkldasfjkldsajflkjdsfklfjdsgkfld\nalskdjklajsdlkajfdlkjsfd\n\talksjdklajsfdkljdsf\ndsa;klfjdskfj", 'website' => 'http://www.assforyou.com/', 'intranet_url' => 'http://www.something.com', 'remove_button' => "", 'company_admin_area' => "Manage Office Administrators", 'casestudies_list' => "adsfkljdskldszfgfdfdsgdsfgfdshghdmfldkgjfhdskjfhdskjhfkhdsakgagsfjhbvdsaj hsgbf jhfg sajfjdsag ffasfj hfkjhsdkjhdsakjfhkj kjhdsfkjhdskfjhdskjfkjsda kjjsafdkjhds kjds fkj skjh fdskjhfkj kj kjhf kjh sfkjhadsfkj hadskjfhkjhs ajhdsfkj akj fkj kj kj kkjdsfhk skjhadskfj haskjh fkjsahfkjhsfk ksjfhdkjh sfkjhdskjfhakj shiou weryheuwnjcinuc 3289u4234k 5 i 43iundsinfinafiunai saiufhiudsaf afiuhahfwefna uwhf u auiu uh weiuhfiuh iau huwehiucnaiuncianweciuninc iuaciun iucniunciunweiucniuwnciwe", 'number_of_contacts' => "aksfjdkldsajfkljds", 'country_selector' => "klajslkjdsafkljds", 'logo_link' => "dsfpkjdsfkgljdsfkglj", 'photo_link' => "lsadfjlkfjdsgkljhfgklhasgh", ); $tmpl->output; }, large_template => sub { my $tmpl = HTML::Template->new(filename => 'templates/long_loops.tmpl'); $tmpl->param( propname => 'foo', javascript => '', hotel_key => 'bar&>?/', alert => 'Danger!&!', new_comment_button => 'Click Me!', comments => [ { color => 'black', posted_by => 'me & you', posted_on => '', stars => '10', comment => 'Super & duper cool stuff!', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'blue', posted_by => 'you & I', posted_on => '2 days ', stars => '5', comment => 'It is ok ', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'yellow', posted_by => 'someone & someone else', posted_on => '4 days ', stars => '4', comment => 'It would not kill me to go back & spend more time there', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'blue', posted_by => 'someone else!&!', posted_on => '<4 days ago>', stars => '6', comment => 'I enjoyed the ', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'red', posted_by => 'someone else <&>', stars => '6', approval_button => 'No, Click Me!', }, {}, ], comment_editor => [ { color => 'black', posted_by => 'me', posted_on => 'yesterday', stars => '10', comment => 'Super duper cool stuff!', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'blue', posted_by => 'you', posted_on => '2 days ago', stars => '5', comment => 'It is ok', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'yellow', posted_by => 'someone', posted_on => '4 days ago', stars => '4', comment => 'It would not kill me to go back', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'blue', posted_by => 'someone else', posted_on => '4 days ago', stars => '6', comment => 'I enjoyed the bed', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'red', posted_by => 'someone else', stars => '6', cancel_button => 'No you are not.', }, {}, ], comment_created => [ {posted_by => 'Fred'}, {posted_by => 'George'}, {posted_by => 'Thomas'}, {posted_by => 'Dan'}, {posted_by => 'Henry'}, {posted_by => 'Michael'}, {posted_by => 'Nelson'}, {posted_by => 'Brad'}, {posted_by => 'Rodney'}, {posted_by => 'Jose'}, {posted_by => 'Marie'}, {posted_by => 'Eric'}, {posted_by => 'Isaac'}, {posted_by => 'Rusty'}, {posted_by => 'Jacob'}, {posted_by => 'Alice'}, {posted_by => 'Kelly'}, {posted_by => 'Juan'}, {posted_by => 'Lewis'}, {posted_by => 'Fredrick'}, {posted_by => 'Manny'}, {posted_by => 'Dee'}, {posted_by => 'Nort'}, {posted_by => 'Jeanne'}, {posted_by => 'Oscar'}, {posted_by => 'Peter'}, {posted_by => 'Russel'}, {posted_by => 'Steve'}, {posted_by => 'Timmy'}, {posted_by => 'Vance'}, {}, ], ); }, } ); HTML-Template-2.97/bench/profile_medium.pl0000755000175000017500000000341713107402001016522 0ustar samsam#!/usr/bin/env perl use strict; use warnings; use lib '../lib'; use HTML::Template; my $tmpl = HTML::Template->new(filename => 'templates/medium.tmpl'); $tmpl->param( 'alert' => 'I am alert.', 'company_name' => "MY NAME IS", 'company_id' => "10001", 'office_id' => "10103214", 'name' => 'SAM I AM', 'address' => '101011 North Something Something', 'city' => 'NEW York', 'state' => 'NEw York', 'zip' => '10014', 'phone' => '212-929-4315', 'phone2' => '', 'subcategories' => 'kfldjaldsf', 'description' => "dsa;kljkldasfjkldsajflkjdsfklfjdsgkfld\nalskdjklajsdlkajfdlkjsfd\n\talksjdklajsfdkljdsf\ndsa;klfjdskfj", 'website' => 'http://www.assforyou.com/', 'intranet_url' => 'http://www.something.com', 'remove_button' => "", 'company_admin_area' => "Manage Office Administrators", 'casestudies_list' => "adsfkljdskldszfgfdfdsgdsfgfdshghdmfldkgjfhdskjfhdskjhfkhdsakgagsfjhbvdsaj hsgbf jhfg sajfjdsag ffasfj hfkjhsdkjhdsakjfhkj kjhdsfkjhdskfjhdskjfkjsda kjjsafdkjhds kjds fkj skjh fdskjhfkj kj kjhf kjh sfkjhadsfkj hadskjfhkjhs ajhdsfkj akj fkj kj kj kkjdsfhk skjhadskfj haskjh fkjsahfkjhsfk ksjfhdkjh sfkjhdskjfhakj shiou weryheuwnjcinuc 3289u4234k 5 i 43iundsinfinafiunai saiufhiudsaf afiuhahfwefna uwhf u auiu uh weiuhfiuh iau huwehiucnaiuncianweciuninc iuaciun iucniunciunweiucniuwnciwe", 'number_of_contacts' => "aksfjdkldsajfkljds", 'country_selector' => "klajslkjdsafkljds", 'logo_link' => "dsfpkjdsfkgljdsfkglj", 'photo_link' => "lsadfjlkfjdsgkljhfgklhasgh", ); $tmpl->output; HTML-Template-2.97/bench/new.pl0000755000175000017500000000052213107402001014305 0ustar samsam#!/usr/bin/env perl use strict; use warnings; use Benchmark 'timethese'; use lib '../lib'; use HTML::Template; timethese( 1_000, { small_template => sub { HTML::Template->new(filename => 'templates/default.tmpl') }, big_template => sub { HTML::Template->new(filename => 'templates/long_loops.tmpl') } } ); HTML-Template-2.97/bench/profile_large.pl0000755000175000017500000001355413107402001016337 0ustar samsam#!/usr/bin/env perl use strict; use warnings; use lib '../lib'; use HTML::Template; my $tmpl = HTML::Template->new(filename => 'templates/long_loops.tmpl'); $tmpl->param( propname => 'foo', javascript => '', hotel_key => 'bar&>?/', alert => 'Danger!&!', new_comment_button => 'Click Me!', comments => [ { color => 'black', posted_by => 'me & you', posted_on => '', stars => '10', comment => 'Super & duper cool stuff!', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'blue', posted_by => 'you & I', posted_on => '2 days ', stars => '5', comment => 'It is ok ', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'yellow', posted_by => 'someone & someone else', posted_on => '4 days ', stars => '4', comment => 'It would not kill me to go back & spend more time there', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'blue', posted_by => 'someone else!&!', posted_on => '<4 days ago>', stars => '6', comment => 'I enjoyed the ', approval_button => 'No, Click Me!', edit_button => 'Hey, what about me!', delete_button => 'Why am I always last?', }, { color => 'red', posted_by => 'someone else <&>', stars => '6', approval_button => 'No, Click Me!', }, {}, ], comment_editor => [ { color => 'black', posted_by => 'me', posted_on => 'yesterday', stars => '10', comment => 'Super duper cool stuff!', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'blue', posted_by => 'you', posted_on => '2 days ago', stars => '5', comment => 'It is ok', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'yellow', posted_by => 'someone', posted_on => '4 days ago', stars => '4', comment => 'It would not kill me to go back', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'blue', posted_by => 'someone else', posted_on => '4 days ago', stars => '6', comment => 'I enjoyed the bed', ok_button => 'I am totally fine with that.', cancel_button => 'No you are not.', }, { color => 'red', posted_by => 'someone else', stars => '6', cancel_button => 'No you are not.', }, {}, ], comment_created => [ {posted_by => 'Fred'}, {posted_by => 'George'}, {posted_by => 'Thomas'}, {posted_by => 'Dan'}, {posted_by => 'Henry'}, {posted_by => 'Michael'}, {posted_by => 'Nelson'}, {posted_by => 'Brad'}, {posted_by => 'Rodney'}, {posted_by => 'Jose'}, {posted_by => 'Marie'}, {posted_by => 'Eric'}, {posted_by => 'Isaac'}, {posted_by => 'Rusty'}, {posted_by => 'Jacob'}, {posted_by => 'Alice'}, {posted_by => 'Kelly'}, {posted_by => 'Juan'}, {posted_by => 'Lewis'}, {posted_by => 'Fredrick'}, {posted_by => 'Manny'}, {posted_by => 'Dee'}, {posted_by => 'Nort'}, {posted_by => 'Jeanne'}, {posted_by => 'Oscar'}, {posted_by => 'Peter'}, {posted_by => 'Russel'}, {posted_by => 'Steve'}, {posted_by => 'Timmy'}, {posted_by => 'Vance'}, {}, ], ); HTML-Template-2.97/README0000644000175000017500000000060313107402001012755 0ustar samsam This archive contains the distribution HTML-Template, version 2.97: Perl module to use HTML-like templating language This software is copyright (c) 2012 by Michael Peters. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. This README file was generated by Dist::Zilla::Plugin::Readme v5.043. HTML-Template-2.97/scripts/0000775000175000017500000000000013107402001013567 5ustar samsamHTML-Template-2.97/scripts/clean_shm.pl0000755000175000017500000000100413107402001016051 0ustar samsam#!/usr/bin/env perl use strict; use warnings; # this script deletes all shared memory segments accessible by the # running user. Probably only works on Linux systems. open(IPCS, 'ipcs |') or die "Probs opening icps : $!"; my $mode = 0; while () { if (/(Shared)|(Semaphore)|(Message)/) { $mode++; next; } next unless /^0x[0-9a-f]+\s(\d+)\s.*$/; system("ipcrm shm $1") if ($mode == 1); system("ipcrm sem $1") if ($mode == 2); system("ipcrm msg $1") if ($mode == 3); } HTML-Template-2.97/scripts/time_trial.pl0000755000175000017500000000716613107402001016270 0ustar samsam#!/usr/bin/env perl use strict; use warnings; use lib '../lib'; use HTML::Template; # this is a little script I use to test the timing behavior of various # options in HTML::Template;; # an array of template files to test against and params to fill in my %templates = ( simple => ['templates/simple.tmpl', {}], include => ['templates/include.tmpl'], medium => [ 'templates/medium.tmpl', { 'ALERT' => 'I am alert.', 'COMPANY_NAME' => "MY NAME IS", 'COMPANY_ID' => "10001", 'OFFICE_ID' => "10103214", 'NAME' => 'SAM I AM', 'ADDRESS' => '101011 North Something Something', 'CITY' => 'NEW York', 'STATE' => 'NEw York', 'ZIP' => '10014', 'PHONE' => '212-929-4315', 'PHONE2' => '', 'SUBCATEGORIES' => 'kfldjaldsf', 'DESCRIPTION' => "dsa;kljkldasfjkldsajflkjdsfklfjdsgkfld\nalskdjklajsdlkajfdlkjsfd\n\talksjdklajsfdkljdsf\ndsa;klfjdskfj", 'WEBSITE' => 'http://www.assforyou.com/', 'INTRANET_URL' => 'http://www.something.com', 'REMOVE_BUTTON' => "", 'COMPANY_ADMIN_AREA' => "Manage Office Administrators", 'CASESTUDIES_LIST' => "adsfkljdskldszfgfdfdsgdsfgfdshghdmfldkgjfhdskjfhdskjhfkhdsakgagsfjhbvdsaj hsgbf jhfg sajfjdsag ffasfj hfkjhsdkjhdsakjfhkj kjhdsfkjhdskfjhdskjfkjsda kjjsafdkjhds kjds fkj skjh fdskjhfkj kj kjhf kjh sfkjhadsfkj hadskjfhkjhs ajhdsfkj akj fkj kj kj kkjdsfhk skjhadskfj haskjh fkjsahfkjhsfk ksjfhdkjh sfkjhdskjfhakj shiou weryheuwnjcinuc 3289u4234k 5 i 43iundsinfinafiunai saiufhiudsaf afiuhahfwefna uwhf u auiu uh weiuhfiuh iau huwehiucnaiuncianweciuninc iuaciun iucniunciunweiucniuwnciwe", 'NUMBER_OF_CONTACTS' => "aksfjdkldsajfkljds", 'COUNTRY_SELECTOR' => "klajslkjdsafkljds", 'LOGO_LINK' => "dsfpkjdsfkgljdsfkglj", 'PHOTO_LINK' => "lsadfjlkfjdsgkljhfgklhasgh", } ], long_loop => ['templates/long_loops.tmpl', {}], loop_if => ['templates/loop-if.tmpl', {LOOP_ONE => [{VAR => 'foo'}]}] ); # a hash of option hashes to test my %options = ( 'no cache' => {}, #'simple cache' => { cache => 1 }, # 'shared cache' => { shared_cache => 1, cache => 1 }, 'file cache' => { file_cache => 1, file_cache_dir => './file_cache' }, # 'simple cache, no_includes' => { cache => 1, no_includes => 1}, # 'blind cache' => { blind_cache => 1}, ); # number of times over each template my $n = 100; #open(OUT, ">test.out"); foreach my $template (keys %templates) { print "\nTESTING : $template : $n iterations\n\n"; foreach my $option (keys %options) { my $start_time = (times)[0]; for (my $x = 0 ; $x < $n ; $x++) { my $template = HTML::Template->new( filename => $templates{$template}->[0], %{$options{$option}} ); foreach my $name (keys %{$templates{$template}->[1]}) { $template->param($name => $templates{$template}->[1]->{$name}); } my $result = $template->output; #print OUT $result; #$template->output(print_to => *OUT); } my $end_time = (times)[0]; print "$option : average iteration in " . (($end_time - $start_time) / $n) . " seconds\n"; } } HTML-Template-2.97/MANIFEST0000644000175000017500000000452713107402001013237 0ustar samsam# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.043. Changes LICENSE MANIFEST META.yml Makefile.PL README bench/new.pl bench/profile_large.pl bench/profile_medium.pl bench/profile_small.pl bench/profile_var.pl bench/vars.pl dist.ini lib/HTML/Template.pm lib/HTML/Template/FAQ.pm scripts/clean_shm.pl scripts/time_trial.pl t/01-bad-args.t t/01-coderefs.t t/02-parse.t t/02-random.t t/03-associate.t t/03-else_else_bug.t t/04-default-escape.t t/04-default_with_escape.t t/04-escape.t t/04-no_taintmode.t t/04-type-source.t t/05-blind-cache.t t/05-force_untaint.t t/05-nested_global.t t/06-file-cache-dir.t t/07-double-file-cache.t t/08-cache-debug.t t/09-caching-precluded.t t/10-param.t t/11-non-file-templates.t t/12-open_mode.t t/12-query.t t/12-utf8.t t/13-loop-boolean.t t/13-loop-context.t t/13-loop-repeated.t t/14-includes.t t/15-comment.t t/16-config.t t/99-old-test-pl.t t/author-pod-syntax.t t/testlib/IO/Capture.pm t/testlib/IO/Capture/ErrorMessages.pm t/testlib/IO/Capture/Stderr.pm t/testlib/IO/Capture/Stdout.pm t/testlib/IO/Capture/Tie_STDx.pm t/testlib/_Auxiliary.pm templates/case_loop.tmpl templates/context.tmpl templates/counter.tmpl templates/default.tmpl templates/default_escape.tmpl templates/default_escape_off.tmpl templates/double_loop.tmpl templates/escapes.tmpl templates/global-loops.tmpl templates/globals.tmpl templates/html-escape.tmpl templates/if.tmpl templates/ifelse.tmpl templates/include.tmpl templates/include_path/a.tmpl templates/include_path/b.tmpl templates/include_path/inner.tmpl templates/include_path/one.tmpl templates/include_path2/inner.tmpl templates/included.tmpl templates/included2.tmpl templates/included3.tmpl templates/js.tmpl templates/long_loops.tmpl templates/loop-context.tmpl templates/loop-if.tmpl templates/loop.tmpl templates/medium.tmpl templates/multiline_tags.tmpl templates/newline_test1.tmpl templates/newline_test2.tmpl templates/other-loop.tmpl templates/outer.tmpl templates/query-test.tmpl templates/query-test2.tmpl templates/recursive.tmpl templates/searchpath/included.tmpl templates/searchpath/three.tmpl templates/searchpath/two.tmpl templates/simple-loop-nonames.tmpl templates/simple-loop.tmpl templates/simple.tmpl templates/simplemod.tmpl templates/unless.tmpl templates/urlescape.tmpl templates/utf8-test.tmpl templates/vanguard1.tmpl templates/vanguard2.tmpl templates/var.tmpl HTML-Template-2.97/templates/0000775000175000017500000000000013107402001014076 5ustar samsamHTML-Template-2.97/templates/case_loop.tmpl0000644000175000017500000000010313107402001016730 0ustar samsam HTML-Template-2.97/templates/include_path2/0000775000175000017500000000000013107402001016617 5ustar samsamHTML-Template-2.97/templates/include_path2/inner.tmpl0000644000175000017500000000001513107402001020622 0ustar samsamI AM INNER 2 HTML-Template-2.97/templates/ifelse.tmpl0000644000175000017500000000013313107402001016236 0ustar samsamThis is a line outside the if. INSIDE IF INSIDE ELSE HTML-Template-2.97/templates/searchpath/0000775000175000017500000000000013107402001016220 5ustar samsamHTML-Template-2.97/templates/searchpath/included.tmpl0000644000175000017500000000005313107402001020701 0ustar samsam9 9 9 HTML-Template-2.97/templates/searchpath/three.tmpl0000644000175000017500000000000613107402001020217 0ustar samsamTHREE HTML-Template-2.97/templates/searchpath/two.tmpl0000644000175000017500000000003613107402001017724 0ustar samsamTWO HTML-Template-2.97/templates/double_loop.tmpl0000644000175000017500000000020413107402001017271 0ustar samsam One of David's numbers is . VAR TIME: HTML-Template-2.97/templates/js.tmpl0000644000175000017500000000003513107402001015404 0ustar samsamHTML-Template-2.97/templates/escapes.tmpl0000644000175000017500000000020013107402001016405 0ustar samsam HTML-Template-2.97/templates/simple-loop-nonames.tmpl0000644000175000017500000000024513107402001020671 0ustar samsam Simple Template I am a simple loop template. HTML-Template-2.97/templates/simple.tmpl0000644000175000017500000000017513107402001016266 0ustar samsam Simple Template IIII am a simple template. HTML-Template-2.97/templates/include_path/0000775000175000017500000000000013107402001016535 5ustar samsamHTML-Template-2.97/templates/include_path/a.tmpl0000644000175000017500000000003413107402001017646 0ustar samsamFoo HTML-Template-2.97/templates/include_path/one.tmpl0000644000175000017500000000005213107402001020207 0ustar samsamONE HTML-Template-2.97/templates/include_path/inner.tmpl0000644000175000017500000000001513107402001020540 0ustar samsamI AM INNER 1 HTML-Template-2.97/templates/include_path/b.tmpl0000644000175000017500000000000413107402001017644 0ustar samsamBar HTML-Template-2.97/templates/included3.tmpl0000644000175000017500000000000613107402001016640 0ustar samsam6 6 6 HTML-Template-2.97/templates/context.tmpl0000644000175000017500000000031713107402001016457 0ustar samsamand , . pingpong HTML-Template-2.97/templates/default_escape.tmpl0000644000175000017500000000014213107402001017733 0ustar samsam be HTML-Template-2.97/templates/loop-context.tmpl0000644000175000017500000000026713107402001017432 0ustar samsam:FIRST:INNER:LAST:ODD HTML-Template-2.97/templates/vanguard2.tmpl0000644000175000017500000000002413107402001016657 0ustar samsam%baz% sdfsdgsdhsgf HTML-Template-2.97/templates/included.tmpl0000644000175000017500000000005313107402001016557 0ustar samsam4 4 4 HTML-Template-2.97/templates/html-escape.tmpl0000644000175000017500000000024413107402001017174 0ustar samsamThis should be a bunch of HTML-escaped stuff: HTML-Template-2.97/templates/default.tmpl0000644000175000017500000000036113107402001016416 0ustar samsamcause it's hard to , and are ing to HTML-Template-2.97/templates/loop.tmpl0000644000175000017500000000006413107402001015743 0ustar samsam HTML-Template-2.97/templates/multiline_tags.tmpl0000644000175000017500000000011213107402001020004 0ustar samsam HTML-Template-2.97/templates/utf8-test.tmpl0000644000175000017500000000000313107402001016626 0ustar samsamรค HTML-Template-2.97/templates/recursive.tmpl0000644000175000017500000000006413107402001017001 0ustar samsamI am infinity. HTML-Template-2.97/templates/var.tmpl0000644000175000017500000000001713107402001015560 0ustar samsam HTML-Template-2.97/templates/loop-if.tmpl0000644000175000017500000000023713107402001016341 0ustar samsam Loop not filled in! HTML-Template-2.97/templates/included2.tmpl0000644000175000017500000000000613107402001016637 0ustar samsam5 5 5 HTML-Template-2.97/templates/urlescape.tmpl0000644000175000017500000000006613107402001016757 0ustar samsamSome URL escaped stuff: HTML-Template-2.97/templates/medium.tmpl0000644000175000017500000001505513107402001016260 0ustar samsam Global Navigator Administration : Office Editor
Office Editor
Office Data
> >
Company Name >
Office Name
Address
City
State
Country
Postal Code
Phone Number
Secondary Phone Number
Email
Website
Intranet URL
Logo Upload New Logo:
Photo Upload New Photo:
Subcategories
Description
> >
Case Study
Client Brands Account Manager
> Add a Case Study
Contacts
> This office has Contacts.
HTML-Template-2.97/templates/simple-loop.tmpl0000644000175000017500000000025313107402001017232 0ustar samsam Simple Template I am a simple loop template. HTML-Template-2.97/templates/if.tmpl0000644000175000017500000000016013107402001015365 0ustar samsamThis is a line outside the if. INSIDE the if unless HTML-Template-2.97/templates/counter.tmpl0000644000175000017500000000026113107402001016450 0ustar samsam HTML-Template-2.97/templates/newline_test1.tmpl0000644000175000017500000000005213107402001017550 0ustar samsamSTARTEND HTML-Template-2.97/templates/query-test.tmpl0000644000175000017500000000064613107402001017122 0ustar samsam HTML-Template-2.97/templates/globals.tmpl0000644000175000017500000000036713107402001016423 0ustar samsam Some global var: Some Loop. Some local data Something global, but hidden Hidden! HTML-Template-2.97/templates/long_loops.tmpl0000644000175000017500000002760213107402001017154 0ustar samsam WPP Hotel Directory Vistor Comments: <TMPL_VAR PROPNAME>

Inside WPPNew searchReturn to hotel list WPP Hotel Directory
WPP Hotel DirectoryWPP Hotel Directory
General InfoRates and ChargesFacilities and AmenitiesPoliciesAlso in the areaComments
>
Back to the topVistor Comments

 
> Posted by: > Rating:
COLSPAN=2> Comment



 
> Posted by: > Rating:
COLSPAN=2> Comment



 
Thank you for you comment !
The moderators have been notified of your new comment - they will review it as soon as possible.


 


HTML-Template-2.97/templates/simplemod.tmpl0000644000175000017500000000015213107402001016761 0ustar samsam Simple Template IIII am not such a simple template. HTML-Template-2.97/templates/default_escape_off.tmpl0000644000175000017500000000015313107402001020567 0ustar samsam be HTML-Template-2.97/templates/global-loops.tmpl0000644000175000017500000000037713107402001017373 0ustar samsamglobal: outer loop foo: inner loop bar: inner loop foo: inner loop global: HTML-Template-2.97/templates/unless.tmpl0000644000175000017500000000011613107402001016301 0ustar samsam INSIDE UNLESS INSIDE ELSE HTML-Template-2.97/templates/query-test2.tmpl0000644000175000017500000000050213107402001017173 0ustar samsam HTML-Template-2.97/templates/outer.tmpl0000644000175000017500000000006013107402001016124 0ustar samsamI AM OUTER I AM OUTER HTML-Template-2.97/templates/newline_test2.tmpl0000644000175000017500000000000713107402001017551 0ustar samsamincludeHTML-Template-2.97/templates/other-loop.tmpl0000644000175000017500000000012713107402001017062 0ustar samsamOUTSIDE INSIDE HTML-Template-2.97/templates/include.tmpl0000644000175000017500000000007513107402001016417 0ustar samsam1 1 1 2 2 2 3 3 3 6 6 6 HTML-Template-2.97/templates/vanguard1.tmpl0000644000175000017500000000004413107402001016660 0ustar samsam%foo% HTML-Template-2.97/Changes0000644000175000017500000003751313107402001013402 0ustar samsam2.97 Thu May 18 2017 - Change internal module name HTML::Template::DEFAULT to HTML::Template::DEF to avoid conflict with HTML::Template::Default. [Sam Tregar] 2.96 Thu May 18 2017 - Fixed typos in documentation [David Steinbrunner, Steve Kemp] - Added CGI.pm as a dependency, needed now that it's no longer in core. [Martin McGrath, Steve Bertrand] 2.95 Mon Oct 21 2013 - Added support for "none" for default_escape [Mark Stosberg] - Escape unicode new-line characters in JS escape [Michael Peters] 2.94 Thu Jan 17 2013 - Fixed bug where options were bleeding over into subsequent calls to new() [Michael Peters] 2.93 Wed Jan 16 2013 - Feature: Added config() method to make setting global defaults easy so that each call to new() has less boiler plate. [Michael Peters] - Bug Fix: t/05-force_untaint.t now passes when run with prove [Michael Peters] - Bug Fix: die_on_bad_params now controls whether we die if tmpl_vars reuse names from tmpl_loops (which can be useful in some situations) [Michael Peters] 2.91 Fri Mar 30 2012 - Feature: RT #18901 - Added new utf8 option to make it really simple to use UTF-8 encoded templates [Michael Peters] - Feature: RT #30586 - Added new open_mode option to allow for Perl IO layers to interact when using open() on the template files [moritz@faui2k3.org and Michael Peters] - Feature: RT #38189 - Allow clean XML style tags "" to be used as well. [allard@byte.nl] - Feature: RT #46285 - Added support for lazily-evaluated coderefs for TMPL_LOOPs. [Justin DeVuyst and Michael Peters] - Feature: RT #64797 - Added new option die_on_missing_include (defaults to true) that allows users to turn off the behavior of dieing when an include can't be found [Zdenek Styblik and Michael Peters] - Feature: Add new cache_lazy_vars option so that the values from coderefs used for TMPL_VARs can be cached and the coderef not run multiple times [Michael Peters] - Feature: Add new cache_lazy_loops option so that the values from coderefs used for TMPL_LOOPs can be cached and the coderef not run multiple times [Michael Peters] - Feature: Added __even__, __outer__ and __index__ loop context vars. [Michael Peters] - Bug Fix: RT #26456 - force_untaint can't work in Perl < 5.8.0 [admin@photoresearchers.com] - Bug Fix: RT #67663 - remove warning under Perl > 5.14.0 about using tied with a file handle without "*" [RENEEB, TODDR and Michael Peters] - Bug Fix: RT #35534 - Using the same loop multiple times with different vars will no longer cause an error if die_on_bad_params is set. [Ron Savage & Michael Peters] - Bug Fix: RT #38325 - Give a better error message if param() is set with a reference to a reference. [Mark Stosberg & Michael Peters] - Test Fix: RT #26103 - t/05-blind-cache.t no longer modifies the distribution during the tests but instead uses temp files [Jan Dubois and Michael Peters] - Test Fix: Tests that create and modify files now use temp files and file_cache_dir is always a temp directory [Michael Peters] - Doc Fix: Using more POD formatting [Michael Peters] - Doc Fix: RT #46244 - fix broken link to tutorial [Michael Peters] - Doc Fix: RT #60282 - fix various mispellings [Florian Ernst] - Doc Fix: RT #60283 - fix broken HTML example [Florian Ernst] - Doc Fix: RT #60284 - fix broken POD [Florian Ernst and Michael Peters] - Development: Moved development to GitHub (https://github.com/mpeters/html-template) - Development: Switched to using Dist::Zilla internally for release management - Development: Added Michael Peters as co-maintainer 2.9 Mon Jan 29 15:54:03 EST 2007 - New Feature: the new force_untaint option makes sure you do not pass tainted values to param(). [Sven Neuhaus] - New Feature: Added ESCAPE=NONE as a synonym for ESCAPE=0. Fixed both to work with default_escape. [cpan@punch.net] - Bug Fix: DEFAULT didn't work with URL and JS escaping. - Bug Fix: Long-standing bug where variables set in a loop weren't available inside inner loops under global_vars if the variable wasn't actually used in the outer loop. (Thanks to Richard Fein for help debugging the fix.) - Doc Fix: Changed references to CVS in the docs to Subversion now that the switch is complete. - Test Fix: At long last, the work from the Phalanx project has been merged! The tests are now more complete and easier to work on. Thanks Phalanx guys! 2.8 Wed Dec 21 18:37:39 EST 2005 - New Feature: the new default_escape option allows you to apply escaping to all variables in a template. [Alex Kapranoff] - Bug Fix: ESCAPE wasn't working on variables containing code-refs. - Bug Fix: Changed HTML::Template to help sub-classes by called _new_from_loop() via ref($self) rather than hard-coding the package name. [Mark Stosberg] - Bug Fix: Including more than one tag in or now dies with an error message, instead of silently ignoring one of the clauses. [Mitar and Mark Stosberg] - Bug Fix: Fixed HTML::Template to re-evaluate conditions to handle . This bug could cause HTML::Template to take both branches of a conditional if a code-ref parameter returned a different value when called a second time. [Emanuele Zeppieri] 2.7 Thu Jun 24 12:00:00 2004 - New Feature: Added javascript escaping with ESCAPE=JS. (Craig Manley) - Bug Fix: Improved cache keying to be sensitive to options which alter the compilation of templates (path, search_path, loop_context_vars and global_vars). Calls to new() with different settings for any of these options will no longer pull incorrect cached objects. - Bug Fix: Added code to detect broken Perl 5.8.0 installs during installation (i.e. Redhat 8 and 9). - Bug Fix: Fixed parsing of ESCAPE='URL' (Paul Baker) - Bug Fix: Added check for empty filename passed to new(). - Test Fix: Migrated tests to Test::More. This will allow the easier introduction of new tests and the use of Devel::Cover. (Gabor Szabo) 2.6 Thu Aug 29 12:00:00 2002 - New Feature: HTML::Template will combine HTML_TEMPLATE_ROOT environment variable and path option if both are available. (Jesse Erlbaum) - New Feature: __counter__ variable now available when loop_context_vars is set (Simran Gambhir) - New Feature: The default attribute allows you to specify defaults for tags. - Bug Fix: fixed parser to reject s with no names. (crazyinsomniac) - Doc Fix: fixed documentation to correctly describe the interaction of case_sensitive and loop_context_vars. (Peter Claus Lamprecht) - Doc Fix: updated mailing-list information to reflect move from vm.com to sourceforge.net 2.5 Fri Feb 01 12:00:00 2002 - Bug Fix: global_vars fixed for loops within loops - Bug Fix: include paths were broken under Windows (David Ferrance) - Bug Fix: nested include path handling was wrong (Gyepi Sam) - Bug Fix: MD5 signatures for file cache corrected (Martin Schroth) - Bug Fix: print_to was broken for tied filehandles (Darren Chamberlain) - Doc Fix: added mailing-list archive URL to FAQ, added link to tutorial, fixed typos and formatting - Doc Fix: added reference to new HTML::Template website at http://html-template.sourceforge.net/ 2.4 Mon August 27 12:00:00 2001 - Bug Fix: case_sensitive option broke loops (Peter Leonard) - Bug Fix: code-ref params now work with IF and UNLESS 2.3 Thu June 28 12:00:00 2001 - New Feature: template tags can now span lines. (Roland Giersig) - New Feature: new() option 'filehandle'. (Roland Giersig) - Bug Fix: includes were broken in some cases using scalarref templates. (Lance Thomas) - Bug Fix: recursive include detection was broken for scalarref templates. (Mark Stosberg) - Bug Fix: cleaned up more 5.004 warnings. (Jere Julian) 2.2 Sat December 23 12:00:00 2000 - Bug Fix: fixed memory leak in global_vars implementation (Ade Olonoh) - Bug Fix: fixed file_cache not reloading templates on changes (T.J. Mather) - Bug Fix: fixed broken error checking in param() (Mark Stosberg) 2.1 Sun December 18 12:00:00 2000 - New Feature: new 'file_cache' and 'double_file_cache' options provide a file based caching method (T.J. Mather) - New Feature: new 'print_to' option for output() allows output() to print to a filehandle as it runs. (Chris Nokleberg) - New Feature: new 'case_sensitive' option to allow template variable names to be case sensitive. (Matthew Wickline) - New Feature: new 'filter' option allows pre-parse filtering of template files. - Bug Fix: added single-quote escaping to HTML escaping code (Ralph Corderoy) - Bug Fix: fixed a noisy bug in param() when used with 'associate' (William Ward) - Doc Fix: broke out FAQ into separate file. 2.0 Sun September 16 12:00:00 2000 - New Feature: new 'search_path_on_include' option (Jody Biggs) - New Feature: much requested variable __ODD__ added to set of loop_context_vars. - New Feature: new 'no_includes' option (Scott Guelich) - Doc Addition: Added link to Japanese translation (Kawai Takanori) - Bug Fix: loop_context_vars was mostly broken (T.J. Mather, Martin Schroth and Dave Wolfe) - Bug Fix: vanguard_compatibility_mode was broken on first line of included files. (uchum) 1.8 Sun June 25 12:00:00 2000 - New Feature: global_vars option makes outer variables visible inside loops. - Bug Fix: Use File::Spec to construct pathnames. This means that HTML::Template should now work on VMS and MacOS. (Larry Moore) - Bug Fix: loop_context_vars were broken in an unusual case (Todd Larason) - Bug Fix: ESCAPE was broken in some cases. - New License: switched to GPL/Artistic hybrid normally used with Perl modules. 1.7 Fri March 24 12:00:00 2000 - New Feature: new method query() enables introspection into loops (Chris Houser) - New Feature: Better error handling with Carp - Bug Fix: URLESCAPE was skipping some important escapes (Simran Gambhir) - New FAQ: How can I execute a program from inside my template? 1.6 Sun March 05 12:00:00 2000 - New Feature: double_cache combines shared memory and local memory caching for twice the speedup! - New feature: ESCAPE=URL (added by Tobias Brox) - Bug Fix: allow for blessed objects in calls to param() (thanks to Michael Lloyd and David Glasser) - Bug Fix: _mtime was broken in 1.5, fixed a typo. 1.5.1 Wed February 23 12:00:00 2000 - Bug Fix: 1.5 broke caching in some cases - thanks to Drew Taylor for help solving this one. 1.5 Mon February 17 12:00:00 2000 - Shared cache now uses IPC::SharedCache and is much more stable. - Fixed problem with mixed case associated CGI.pm parameters - param() now accepts subroutine refs for TMPL_VARs. 1.4 Sat January 8 12:00:00 2000 - New feature: new() option 'shared_cache' enables experimental IPC shared memory caching! - TMPL_IF now works on TMPL_LOOP variables. - Public CVS server available at www.sourceforge.net. - Bug Fix from Doug Steinwand: loop_context_vars not working on one-item loops. 1.3 Fri December 17 12:00:00 1999 - Omnibus regex patch from Matthew Wickline: a faster and more robust parse(). - New tag: TMPL_UNLESS, the opposite of TMPL_IF. - Numerous bug fixes: mixed-case filenames in includes, recursive TMPL_INCLUDEs, reporting filename and line number inside included files, better syntax-error detection. - Optional loop context variables - __FIRST__, __LAST__ and __INNER__. 1.2.1 Wed November 17 12:00:01 1999 - tiny bug fix 1.2 Wed November 17 12:00:00 1999 - Added multi-parameter and hash-ref syntax for param() calls. - Added DTD-compliant syntax patch from Matthew Wickline - Thanks! - vanguard_compatibility_mode = 1 implies die_on_bad_params = 0 1.1 Fri November 05 12:00:00 1999 - Lifted requirement that s be alone on a line - Added "path" option to new() to manipulate search path for templates. - bug fixes 1.0 Fri October 28 12:00:00 1999 - An HTML::Template mailing-list! Send a blank message to htmltmpl-subscribe@lists.vm.com to join. - bug fixes - improved docs 0.96 October 14th 1999 15:49 - Added "ESCAPE=1" option to to HTML-escape variable values. (Peter Marelas, thanks!) - more bug fixes (David Glasses, James William Carlson - thanks) - even *more* code cleanup! - new FAQ concerning pre-loading templates and mod_perl. 0.95 October 8th 1999 12:28 - bug fix: some lines were getting chomped (Eric Zylberstejn) - *NUMEROUS* bug fixes (David Glasser - Thanks a lot!) - new FAQ section in documentation - code cleanup and improved comments 0.91 September 29th 1999 17:59 - bug fix: possible loss of text after a (Thanks to Tom Huskins for alerting me to this one!) 0.9 September 28th 1999 17:46 - and - near total rewrite - faster, smaller, more "compiler-esque" code. - *MASSIVE* speedups in all modes - up to 10x faster!1 - bug fix : param() wasn't returning names of LOOPs - This really is version 0.9 so 1.0 is coming up. Get those bug reports in! 0.06 September 19th 1999 23:09 - added associate parameter to new() and obsoleted associate_CGI() (still supported for now) - added support for HTML_TEMPLATE_ROOT environment variable - small performance improvements using typeglobs - added a performance testing script: time_trial.pl 0.051 September 10th 1999 17:30 - small problem with make test fixed. 0.05 September 10th 1999 17:18 - Added functionality! - Added associate_CGI() method - donated by Richard Dice - Cleaned up internal access to new() options. - more bug fixes from such notables as Kevin Puetz, and Steve Reppucci. 0.04 Fri June 18 12:00:00 1999 - fixed cacheing - under certain conditions it was totally broken! - changed {param} to {param_values} - some older perls complained. - die_on_bad_params => 0 now also applied to loop body. - added copious comments about how bad m//i is to avoid future bug reports about [tT][hH][iI][sS]! - added numerous bug fixes and optimizations submitted by Mike Blazer, Adriano Nagelschmidt Rodrigues, Andrej Mikus and Ilya Obshadko. Thanks! 0.03 Fri June 11 17:37:00 1999 - fixed a few irritating "undefined variable" errors in -w - big speedup on large TMPL_LOOPs. They are at least one order of magnitude faster now! - die_on_bad_params => 0 never really worked! It does now. 0.02 Mon May 31 12:47:00 1999 - die on multiple source parameters in new() - tries to preserve newlines in loop body - copies in array contents from array refs on param call i.e. allows for reuse of scratch arrays on calling side - Added a CREDITS section to the docs, inaugurated it with Richard Chen for his many fixes. - Added type => 'sometype', source => 'source' new() syntax. - made "NAME=" in tags optional. Added a test.pl to check for this. 0.01 Mon May 17 15:17:00 1999 - added cacheing to module and perldoc - moved .tmpl files used by 'make test' to /templates - first release! 0.00 Fri May 14 14:59:06 1999 - original version; created by h2xs 1.18