HTML-Template-Pluggable-0.17/ 0000755 0001750 0001750 00000000000 10676575531 014663 5 ustar rhesa rhesa HTML-Template-Pluggable-0.17/Changes 0000644 0001750 0001750 00000005366 10623056531 016152 0 ustar rhesa rhesa Revision history for HTML-Template-Pluggable
0.17 2007-05-15 Rhesa Rozendaal
- ::Dot now handles exceptions on method calls differently:
* if the option die_on_bad_params is on, it will rethrow the exception
* if die_on_bad_params is off, it will emit a warning and produce no
output for that param
0.16 2007-03-28 Rhesa Rozendaal
- removed test dependency on CGI::Application
0.15 2006-03-28 Rhesa Rozendaal
- argh! removed dependency on CAP::AutoRunmode from test suite
0.14 2006-03-27 Rhesa Rozendaal
- bugfixes in ::Dot:
- switched to using blessed() instead of UNIVERSAL::can as a function.
this breaks with using a CGI object for versions older than 3.06,
since CGI didn't have a working can() method.
- made nested calls to the same object work, so you can now do:
Both issues were reported by Dan Horne.
0.13 2005-10-04 Rhesa Rozendaal
- bug fixes in ::Dot:
- using obj.loop in a or now returns the
number of elements; this is a slight incompatibility with
H::T, but makes the if's work
- single char method names in nested calls work properly now
- added pod tests to improve kwalitee...
0.12 2005-08-26 Rhesa Rozendaal
- added before_output hook
0.08 Wed Aug 17 02:30:37 CEST 2005 Rhesa Rozendaal
- fixed bug with global_vars => 1
- made sure all original HTML::Template tests pass with ::Pluggable
and ::Dot
0.07 Tue Aug 16 16:19:50 CEST 2005 Rhesa Rozendaal
- bug fix in tmpl_loop stuff. Only get array on final method call
0.06 Mon Aug 15 19:56:24 CEST 2005 Rhesa Rozendaal
- implemented tmpl_loops in ::Dot!
0.05 Sun Aug 14 23:36:55 CEST 2005 Rhesa Rozendaal
- Added tests against side effects (where avoidable). Extended the docs
for ::Dot
- renamed 'pre_param' trigger location to 'middle_param'
0.04 Sat Aug 13 03:09:54 CEST 2005 Rhesa Rozendaal
- Thanks to Michael Graham, it's now possible to reference plain old
tmpl_vars in argument lists
0.03 Fri Aug 12 16:16:29 CEST 2005 Rhesa Rozendaal
- Added more docs to ::Dot, and more tests
0.02 Thu Aug 11 01:09:21 CEST 2005 Mark Stosberg
- minor doc formatting tweaks
0.01 Wed Aug 10 16:21:03 CEST 2005 Rhesa Rozendaal
- Initial release on CPAN
HTML-Template-Pluggable-0.17/t/ 0000755 0001750 0001750 00000000000 10676575531 015126 5 ustar rhesa rhesa HTML-Template-Pluggable-0.17/t/dot_notation.t 0000644 0001750 0001750 00000002320 10412001154 017756 0 ustar rhesa rhesa use strict;
use Test::More tests => 8;
use Test::MockObject;
use strict;
use_ok('HTML::Template::Pluggable');
use_ok('HTML::Template::Plugin::Dot');
use_ok('Test::MockObject');
my $mock = Test::MockObject->new();
$mock->mock( 'some', sub { $mock } );
$mock->mock( 'method', sub { "chained methods work" } );
my ($output, $template, $result);
# test a simple template
my $t = HTML::Template::Pluggable->new( scalarref =>
\ qq{
tmpl_ifs work
\n},
debug => 0
);
$t->param('wants.to_be.literal', "Literals tokens with dots work");
$t->param('desires', { to_be => { hashref => "nested hashrefs work" } });
$t->param('should_be',$mock);
$output = $t->output;
like($output ,qr/Literals tokens with dots work/);
like($output ,qr/nested hashrefs work/);
like($output ,qr/chained methods work/);
like($output ,qr/chained methods work.*chained methods work/, "using a dot var more than once works" );
like($output ,qr/tmpl_ifs work/);
# vi: filetype=perl
__END__
HTML-Template-Pluggable-0.17/t/side_effects.t 0000644 0001750 0001750 00000005177 10676575473 017755 0 ustar rhesa rhesa use Test::More;
use Test::MockObject;
use strict;
plan tests => 3 # use_ok
+ 12 # hash keys, dying methods
;
use_ok 'HTML::Template::Pluggable';
use_ok 'HTML::Template::Plugin::Dot';
use_ok 'Test::MockObject';
my $mock = Test::MockObject->new();
$mock->mock( 'method_that_dies' => sub { die "horribly..." } );
$mock->mock( 'nested' => sub { $_[0] } );
# methods that die
{
my $ex = get_output(
'',
$mock,
{ die_on_bad_params => 1 },
);
like $@, qr/horribly... at /, "method calls die loudly with die_on_bad_params off";
unlike $ex, qr/0x/, "exception doesn't leave a stringified object behind";
}
{
my $ex = get_output(
'',
$mock,
{ die_on_bad_params => 1 },
);
like $@, qr/horribly... at /, "nested method calls die loudly with die_on_bad_params off";
unlike $ex, qr/0x/, "exception doesn't leave a stringified object behind";
}
{
my $warning;
local $SIG{__WARN__} = sub { $warning = shift; };
my $ex = get_output(
'',
$mock,
{ die_on_bad_params => 0 },
);
is $@, '', "method calls fail silently with die_on_bad_params off";
is $ex, '', "exception doesn't leave a stringified object behind";
like $warning, qr/horribly/, 'but emits a warning';
$ex = get_output(
'',
$mock,
{ die_on_bad_params => 0 },
);
is $@, '', "nested method calls fail silently with die_on_bad_params off";
is $ex, '', "exception doesn't leave a stringified object behind";
like $warning, qr/horribly/, 'but emits a warning';
}
# accessing non-existent hash keys
my %in = ( a => 1, b => 2 );
get_output(
'',
\%in,
);
is_deeply(\%in, { a=>1, b=>2 }, 'No side effects on hashes');
# accessing non-existent object properties
$mock->{old_key} = 'old value';
get_output(
'',
$mock,
);
ok(!exists($mock->{new_key}), 'No side effects on object properties');
sub get_output {
my ($tag, $data, $params) = @_;
my $output = '';
my $t = HTML::Template::Pluggable->new(
scalarref => \$tag,
debug => 0,
%$params,
);
eval {
$t->param( object => $data );
$output = $t->output;
};
# diag("template tag is $tag");
# diag("output is $output");
# diag("exception is $@") if $@;
return $output;
}
# vi: filetype=perl
__END__
HTML-Template-Pluggable-0.17/t/dot_notation_mixnmatch.t 0000644 0001750 0001750 00000005045 10276461501 022053 0 ustar rhesa rhesa use Test::More;
use Test::MockObject;
use strict;
### Tests mixing method calls and hashkey access.
###
### The objective is to be able to say:
### object.method.hashkey
### or
### hashref.object.method
###
### Wilder patterns should work too.
# setup tags to test.
# the template var name is $key,
# the expected outcome is the $value.
my %pats = map { split /\s+=>\s+/ } split $/, < plain hash ref chain
hash.obj => Test::MockObject
hash.obj.property => direct object property
hash.obj.accessor => default accessor value
hash.obj.accessor('public') => public object property
hash.key.obj.accessor('hash').key.deep => deep hash ref via obj accessor via hash ref
obj.property => direct object property
obj.accessor => default accessor value
obj.accessor('public') => public object property
obj.accessor('hash').key.objaccess => hash ref via obj accessor
obj._private => private method
PATS
plan tests => 3 # use_ok
+ scalar(keys %pats) # method patterns
;
use_ok('HTML::Template::Pluggable');
use_ok('HTML::Template::Plugin::Dot');
use_ok('Test::MockObject');
## setup data structures
my $obj = Test::MockObject->new();
my $hash = {};
### fill them with something useful
$hash->{key} = {};
$hash->{obj} = $obj;
$hash->{key}->{string} = 'plain hash ref chain';
$hash->{key}->{objaccess} = 'hash ref via obj accessor';
$hash->{key}->{deep} = 'deep hash ref via obj accessor via hash ref';
$hash->{key}->{obj} = $obj;
$obj->{ 'property' } = 'direct object property';
$obj->{ 'public' } = 'public object property';
$obj->{ 'hash' } = $hash;
$obj->mock('accessor', sub {
my ($self, $attr) = @_;
return "default accessor value" unless $attr;
return $self->{property} if $attr eq 'property';
return $self->{public} if $attr eq 'public';
return $self->{hash} if $attr eq 'hash';
}
);
$obj->mock('_private', sub { "private method" });
# dump structures
# use Data::Dumper;
# diag("hash looks like ", Dumper($hash));
# diag("obj looks like ", Dumper($obj));
my ( $output, $template, $result );
foreach my $pat(sort keys %pats) {
my $out = $pats{$pat};
my $tag = qq{ };
# diag("template tag is $tag");
my $t = HTML::Template::Pluggable->new(
scalarref => \$tag,
debug => 0
);
$t->param( obj => $obj ) if $pat =~ /^obj/;
$t->param( hash => $hash ) if $pat =~ /^hash/;
$output = $t->output;
# diag("output is $output");
like( $output, qr/\Q$out/, $pat);
}
# vi: filetype=perl
__END__
HTML-Template-Pluggable-0.17/t/dot_loop.t 0000644 0001750 0001750 00000002101 10632767655 017126 0 ustar rhesa rhesa use Test::More qw(no_plan);
use strict;
use_ok('HTML::Template::Pluggable');
use_ok('HTML::Template::Plugin::Dot');
use_ok('Test::MockObject');
my $mock = Test::MockObject->new();
$mock->mock( 'some', sub { $mock } );
$mock->mock( 'method', sub { "chained methods work inside tmpl_loop" } );
my $mock2 = Test::MockObject->new();
$mock2->mock( 'some', sub { $mock2 } );
$mock2->mock( 'method', sub { "chained methods work inside a loop twice" } );
my ($output, $template, $result);
$template = qq{};
# test a simple template
my $t = HTML::Template::Pluggable->new(
scalarref => \$template,
debug => 0
);
eval {
$t->param('deloop',[ {should_be => $mock, num => 1}, {should_be => $mock2, num => 2} ]);
$output = $t->output;
};
SKIP: {
skip "HTML::Template subclassing bug for tmpl_loop support. See: http://rt.cpan.org/NoAuth/Bug.html?id=14037", 2 if $@;
like($output ,qr/chained methods work inside tmpl_loop/);
like($output ,qr/chained methods work inside a loop twice/);
}
__END__
HTML-Template-Pluggable-0.17/t/dot_for_loops.t 0000644 0001750 0001750 00000012026 10676575254 020166 0 ustar rhesa rhesa use Test::More;
use Test::MockObject;
use Data::Dumper;
use lib 'lib';
use strict;
my $tests = 14;
plan tests => 3 # use_ok
+ $tests # my tests
;
use_ok('HTML::Template::Pluggable');
use_ok('HTML::Template::Plugin::Dot');
use_ok('Test::MockObject');
my $mock = Test::MockObject->new();
$mock->mock( 'name', sub { 'mock' } );
$mock->mock( 'that_returns_loopdata', sub {
my ($self, $count) = @_;
$count ||= 5;
return $self->ar($count);
} );
$mock->mock( 'ar', sub {
my ($self, $count) = @_;
my @ret = ();
for( 1.. $count) {
push @ret, {
a => $_,
b => $_*10,
};
}
return @ret;
} );
$mock->mock( 'arrayref', sub {
my ($self, $count) = @_;
$count ||= 5;
return [ $self->ar($count) ];
} );
$mock->mock( empty_Loop => sub { return [] } );
$mock->mock( 'nested', sub {
my ($self, $count) = @_;
$count ||= 2;
my @ret;
for (1..$count) {
push @ret, {
a => $_,
b => [ map { { c=>$_*3 } } (1..$_) ],
};
}
return @ret;
} );
my $hashref = { loop => $mock->arrayref };
my ($tag, $out);
$tag = q{ : , . };
$out = get_output($tag, $mock);
SKIP: {
skip "HTML::Template subclassing bug for tmpl_loop support. See: http://rt.cpan.org/NoAuth/Bug.html?id=14037", $tests if $@;
like($out, qr/1, 10/, 'Wrapped loops work with implicit "this" mapping');
$tag = q{ , . };
$out = get_output($tag, $mock);
like($out, qr/1, 10/, 'Wrapped loops work with explicit "that" mapping');
$tag = q{ , . };
$out = get_output($tag, $mock);
like($out, qr/1, 10/, 'Wrapped loops work with arrayrefs');
$tag = q{ no , . data };
$out = get_output($tag, $mock);
like($out, qr/no\s+data/, 'Wrapped loops work with no data');
$tag = q{ no , . data };
$out = get_output($tag, $mock, 'non_object.empty_loop' => []);
like($out, qr/no\s+data/, 'Wrapped loops work with no object and no data');
$tag = q{ , (). };
$out = get_output($tag, $mock);
like($out, qr/\Q3, (3)(6)(9)./, 'Wrapped nested loops work with arrayrefs');
$tag = q{ , (). };
$out = get_output($tag, $mock);
like($out, qr/\Q3, (3)(6)(9)./, 'Wrapped nested loops work with arrayrefs and explicit "inner" mapping');
$tag = q{ , (). };
$out = get_output($tag, $mock);
like($out, qr/\Q1, (3)./, 'Wrapped nested loops work with arrayrefs and implicit mapping everywhere (single return value)');
$tag = q{ , (). };
$out = get_output($tag, $mock);
like($out, qr/\Q3, (3)(6)(9)./, 'Wrapped nested loops work with arrayrefs and implicit mapping everywhere');
$tag = q{ , . };
$out = get_output($tag, $hashref);
like($out, qr/\Q3, 30./, 'simple hashref with an arrayref');
$tag = q{ , . };
$out = get_output($tag, $hashref);
like($out, qr/\Q3, 30./, 'simple hashref with an arrayref, which is tested in a tmpl_if');
$tag = q{ :: , . };
$out = get_output($tag, $hashref);
like($out, qr/\Q3, 30./, 'simple hashref with an arrayref, which is used as a var');
$hashref={loop=>[]};
$tag = q{ , . };
$out = get_output($tag, $hashref);
like($out, qr/^ $/, 'simple hashref with an emtpy arrayref');
$hashref={loop=>[]};
$tag = q{ , . };
$out = get_output($tag, $hashref);
like($out, qr/^ $/, 'simple hashref with an emtpy arrayref, used in a tmpl_if');
}
sub get_output {
my ($tag, @data) = @_;
my ( $output );
# diag("");
my $t = HTML::Template::Pluggable->new(
scalarref => \$tag,
global_vars => 0,
debug => 0,
die_on_bad_params => 1,
);
eval {
$t->param( object => @data );
$output = $t->output;
};
#diag("template tag is $tag");
#diag("output is $output");
#diag("exception is $@") if $@;
return $output;
}
# vi: filetype=perl
__END__
HTML-Template-Pluggable-0.17/t/dot_notation_recursive.t 0000644 0001750 0001750 00000003316 10411776237 022077 0 ustar rhesa rhesa use Test::More;
use Test::MockObject;
use strict;
my @tests = (
[q/Formatter.sprintf('%.2f', mock.value)/, q/ 3.20 / ],
[q/Formatter.sprintf('%.2f', mock.nested(3.1459).key)/, q/ 3.15 / ],
[q/Formatter.sprintf('%20s', mock.nested(bareword, 'literal1', non.bareword).key)/, q/ bare value := / ],
[q/Formatter.sprintf('%20s %4s %7s', bareword, 'literal1', non.bareword)/, q/ bare value := / ],
# [q/mock.nested(Formatter.sprintf('%.3f', 3.14159)).key/, q/ 3.142 / ], ### eeewww. other way around obviously doesn't work, as it needs the param setting reversed.
);
plan tests => 3 # use_ok
+ scalar(@tests) # recursion tests
;
use_ok('HTML::Template::Pluggable');
use_ok('HTML::Template::Plugin::Dot');
use_ok('Test::MockObject');
my $formatter = Test::MockObject->new();
$formatter->mock( 'sprintf' , sub { shift; sprintf(shift(), @_) } );
my $mock = Test::MockObject->new();
$mock->mock( 'name', sub { 'Mock' } );
$mock->mock( 'value', sub { '3.196002' } );
$mock->mock( 'nested', sub { $mock->{key} = $_[1]; $mock } );
foreach my $test(@tests) {
my ($pat, $out) = @$test;
my ( $output, $template, $result );
my $tag = qq{ := }; #
my $t = HTML::Template::Pluggable->new(
scalarref => \$tag,
debug => 0
);
# diag("template tag is $tag");
$t->param( bareword => 'bare value' );
$t->param('non.bareword' => 'non bare value' );
$t->param( mock => $mock );
$t->param( Formatter => $formatter );
$output = $t->output;
like( $output, qr/$out/, $pat);
# diag("output is $output");
# diag("mock is ", $t->param('mock'));
}
# vi: filetype=perl
__END__
HTML-Template-Pluggable-0.17/t/dot_notation_methods_with_args.t 0000644 0001750 0001750 00000005035 10277734264 023606 0 ustar rhesa rhesa use Test::More;
use Test::MockObject;
use strict;
# setup tags to test.
# the tag name is "should_be.some.method" . $key,
# the expected outcome is the value.
# this list should pass
my @passing = (
[ q/should_be.some.method/, q/args/, ],
[ q/should_be.some.method()/, q/args/, ],
[ q/should_be.some.method('with_param')/, q/>with_param, ],
[ q/should_be.some.method(1, 2, 3)/, q/>1< >2< >3, ],
[ q/should_be.some.method(-1.3E+09, 12345, +13, -1)/, q/>-1.3E+09, ],
[ q/should_be.some.method('with.parens()')/, q/>with.parens(), ],
[ q/should_be.some.method('with `quotes`')/, q/>with `quotes`/, ],
[ q/should_be.some.method('with `quotes` and ( parens ) and {braces} ')/,q/braces} /, ],
[ q/should_be.some.method('something with brackets[1,2,3]')/, q/>something with brackets[1,2,3], ],
);
# this list should fail
my @failing = (
[ q/should_be.some.method('quotes', and, bare, args)/, q/Attempt to reference nonexisting parameter/, ],
[ q/should_be.some.method(arrays_are_not_possible[1,2,3])/, q/Attempt to reference nonexisting parameter/, ],
[ q/should_be.some.method$$$/, q/Trailing characters/, ],
[ q/should_be(object.method)/, q/Attempt to set nonexistent parameter/,],
);
plan tests => 3 # use_ok
+ scalar(@passing) # tests that should pass
+ scalar(@failing) # tests that should fail
;
use_ok('HTML::Template::Pluggable');
use_ok('HTML::Template::Plugin::Dot');
use_ok('Test::MockObject');
my $mock = Test::MockObject->new();
$mock->mock( 'some', sub { $mock } );
$mock->mock(
'method',
sub {
shift; # skip object
join " ", "args =", map { ">$_<" } @_;
}
);
foreach my $test ( @passing) {
my ($pat, $out) = @$test;
my $tag = qq{ };
my ( $output, $template, $result );
my $t = HTML::Template::Pluggable->new(
scalarref => \$tag,
debug => 0
);
$t->param( should_be => $mock );
$output = $t->output;
# diag("template tag is $tag");
# diag("output is $output");
like( $output, qr/\Q$out/i, $pat);
}
foreach my $test ( @failing) {
my ($pat, $out) = @$test;
my $tag = qq{ };
my ( $output, $template, $result );
my $t = HTML::Template::Pluggable->new(
scalarref => \$tag,
debug => 0
);
eval {
$t->param( should_be => $mock );
$output = $t->output;
};
# diag("template tag is $tag");
# diag("output is $output");
# diag("exception is $@") if $@;
like( $@, qr/\Q$out/, $pat);
}
# vi: filetype=perl
__END__
HTML-Template-Pluggable-0.17/t/before_output.t 0000644 0001750 0001750 00000001212 10602350533 020147 0 ustar rhesa rhesa use Test::More;
use Data::Dumper;
use strict;
plan tests => 1 # use_ok
+ 2 # my tests
;
use_ok('HTML::Template::Pluggable');
{
my $t = HTML::Template::Pluggable->new(
scalarref => \q{nothing},
debug => 0,
);
$t->add_trigger('before_output', sub { diag("trigger called with @_") if $_[0]->{options}->{debug} } );
ok($t->output eq 'nothing');
}
{
my $t = HTML::Template::Pluggable->new(
scalarref => \q{},
debug => 0,
);
$t->add_trigger('before_output', sub { my $self = shift; $self->param('before_output' => 'before output'); } );
ok($t->output eq 'before output');
}
__END__
HTML-Template-Pluggable-0.17/t/dot_nested.t 0000644 0001750 0001750 00000001476 10616674325 017446 0 ustar rhesa rhesa # use Carp qw(verbose);
use Test::More qw/ no_plan /;
{
# submitted by Dan Horne
package T1;
use strict;
sub name {
my $self = shift;
$self->{name} ||= shift;
return $self->{name};
}
sub greeting {
my $self = shift;
my $name = shift;
return "hello $name";
}
sub new {
my $class = shift;
bless {}, $class;
}
1;
}
use HTML::Template::Pluggable;
use HTML::Template::Plugin::Dot;
my $text = '';
my $test = T1->new();
$test->name('bob');
is "hello bob", $test->greeting('bob');
eval {
my $template = HTML::Template::Pluggable->new(scalarref => \$text);
$template->param('t' => $test);
my $out = $template->output;
is($out, T1->greeting("bob"));
} or warn $@;
__END__
HTML-Template-Pluggable-0.17/t/dot_can.t 0000644 0001750 0001750 00000002563 10602350036 016704 0 ustar rhesa rhesa # use Carp qw(verbose);
use Test::More qw/ no_plan /;
SKIP:
{
# tests the new object test supplied by Dan Horne (RT #18129)
# specifically with CGI.
# Note that CGI.pm prior to version 3.06 does not have a sane
# can() method, so we skip this test if your version is older.
require CGI;
skip "Your CGI.pm ($CGI::VERSION) does not have a sane can() method. Upgrade to at least 3.06 if you want to run this test." if $CGI::VERSION lt '3.06';
BEGIN {
$ENV{QUERY_STRING} = 'foo=bar';
$ENV{HTTP_HOST} = 'hiero';
$ENV{CGI_APP_RETURN_ONLY} = 1;
}
my $t = T2->new;
$t->start_mode('foo');
my $out = $t->run;
like ($out, qr/Start Mode: foo/);
package T2;
use warnings;
use HTML::Template::Pluggable;
use HTML::Template::Plugin::Dot;
sub new { bless {}, +shift; }
sub run { my $self = shift; my $m = $self->{start_mode}; $self->$m(); }
sub start_mode { my $self = shift; $self->{start_mode} = shift if @_; $self->{start_mode} }
sub query { my $self = shift; $self->{cgi} ||= CGI->new; $self->{cgi}; }
sub foo {
my $self = shift;
my $t = HTML::Template::Pluggable->new(scalarref => \q{
Start Mode:
});
$t->param(c => $self);
return $t->output;
}
}
__END__
HTML-Template-Pluggable-0.17/t/pod-coverage.t 0000644 0001750 0001750 00000000254 10320545661 017652 0 ustar rhesa rhesa #!perl -T
use Test::More;
eval "use Test::Pod::Coverage 1.04";
plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@;
all_pod_coverage_ok();
HTML-Template-Pluggable-0.17/t/pod.t 0000644 0001750 0001750 00000000214 10320545661 016055 0 ustar rhesa rhesa #!perl -T
use Test::More;
eval "use Test::Pod 1.14";
plan skip_all => "Test::Pod 1.14 required for testing POD" if $@;
all_pod_files_ok();
HTML-Template-Pluggable-0.17/MANIFEST 0000644 0001750 0001750 00000000605 10602351675 016003 0 ustar rhesa rhesa ARTISTIC
Build.PL
Changes
GPL
lib/HTML/Template/Pluggable.pm
lib/HTML/Template/Plugin/Dot.pm
Makefile.PL
MANIFEST This list of files
MANIFEST.SKIP
META.yml
README
t/before_output.t
t/dot_can.t
t/dot_for_loops.t
t/dot_loop.t
t/dot_nested.t
t/dot_notation.t
t/dot_notation_methods_with_args.t
t/dot_notation_mixnmatch.t
t/dot_notation_recursive.t
t/pod-coverage.t
t/pod.t
t/side_effects.t
HTML-Template-Pluggable-0.17/MANIFEST.SKIP 0000644 0001750 0001750 00000000566 10602351714 016550 0 ustar rhesa rhesa # This is a list of regular expressions of files to skip when rebuilding
# the MANIFEST file. See the documention for the ExtUtils::Manifest module for more detail. -mls
\bCVS\b
^MANIFEST\.bak$
^Makefile$
~$
\.old$
\.bak$
^blib/
^pm_to_blib$
^MakeMaker-\d
.tar.gz$
^notes
^releases
\.tgz$
\.tmp$
\.swp$
\.swm$
\.swn$
\.swo$
\.patch$
\.orig$
\.diff$
_darcs
_build
^Build$
HTML-Template-Pluggable-0.17/lib/ 0000755 0001750 0001750 00000000000 10676575531 015431 5 ustar rhesa rhesa HTML-Template-Pluggable-0.17/lib/HTML/ 0000755 0001750 0001750 00000000000 10676575531 016175 5 ustar rhesa rhesa HTML-Template-Pluggable-0.17/lib/HTML/Template/ 0000755 0001750 0001750 00000000000 10676575531 017750 5 ustar rhesa rhesa HTML-Template-Pluggable-0.17/lib/HTML/Template/Plugin/ 0000755 0001750 0001750 00000000000 10676575531 021206 5 ustar rhesa rhesa HTML-Template-Pluggable-0.17/lib/HTML/Template/Plugin/Dot.pm 0000644 0001750 0001750 00000043102 10623061320 022244 0 ustar rhesa rhesa package HTML::Template::Plugin::Dot;
use vars qw/$VERSION/;
$VERSION = '1.00';
use strict;
use Scalar::Util qw/blessed/;
use Carp;
use Data::Dumper;
use Regexp::Common qw/balanced delimited number/;
use Scalar::Util qw/reftype/;
use base 'Exporter';
sub import {
# my $caller = scalar(caller);
HTML::Template::Pluggable->add_trigger('middle_param', \&_dot_notation);
goto &Exporter::import;
}
sub _dot_notation {
my $self = shift;
my $options = $self->{options};
my $param_map = $self->{param_map};
# carp("dot_notation called for $_[0]");
# carp("param map: ", Dumper($param_map));
# @_ has already been setup for us by the time we're called.
for (my $x = 0; $x <= $#_; $x += 2) {
my $param = $options->{case_sensitive} ? $_[$x] : lc $_[$x];
my $value = $_[($x + 1)];
# necessary to cooperate with plugin system
next if ($self->{param_map_done}{$param} and not $self->{num_vars_left_in_loop});
my ($exists,@dot_matches) = _exists_in_tmpl($param_map, $param);
# We don't have to worry about "die on bad params", because that will be handled
# by HTML::Template's param().
next unless $exists;
my $value_type = ref($value);
if (@dot_matches) {
for (@dot_matches) {
# carp("calling _param_to_tmpl for $_, $param, $value");
my $value_for_tmpl = _param_to_tmpl($self,$_,$param,$value);
my $dot_value_type = ref($value_for_tmpl);
# carp("_param_to_tmpl returned '$value_for_tmpl' for '$_', '$param', '$value'");
unless (defined($dot_value_type) and length($dot_value_type) and ($dot_value_type eq 'ARRAY'
or (ref($value_for_tmpl) and (ref($value_for_tmpl) !~ /^(CODE)|(HASH)|(SCALAR)$/) and $value_for_tmpl->isa('ARRAY')))) {
(ref($param_map->{$_}) eq 'HTML::Template::VAR') or
croak("HTML::Template::param() : attempt to set parameter '$param' with a scalar - parameter is not a TMPL_VAR!");
${$param_map->{$_}} = $value_for_tmpl;
}
else {
(ref($param_map->{$_}) eq 'HTML::Template::LOOP') or
croak("HTML::Template::param() : attempt to set parameter '$param' with an array ref - parameter is not a TMPL_LOOP!");
$param_map->{$_}[HTML::Template::LOOP::PARAM_SET] = $value_for_tmpl;
}
# Necessary for plugin system compatibility
$self->{num_vars_left_in_loop} -= 1;
$self->{param_map_done}{$param} = $value; # store the object for future reference
}
}
# We still need to care about tmpl_loops that aren't dot matches so we can adjust their loops
elsif (defined($value_type) and length($value_type) and ($value_type eq 'ARRAY'
or ((ref($value) !~ /^(CODE)|(HASH)|(SCALAR)$/) and $value->isa('ARRAY')))) {
(ref($param_map->{$param}) eq 'HTML::Template::LOOP') or
croak("HTML::Template::param() : attempt to set parameter '$param' with an array ref - parameter is not a TMPL_LOOP!");
# TODO: Use constant names instead of "0"
$self->{num_vars_left_in_loop} += keys %{ $param_map->{$param}[HTML::Template::LOOP::TEMPLATE_HASH]{'0'}{'param_map'} } if exists $param_map->{$param}[HTML::Template::LOOP::TEMPLATE_HASH]{'0'};
}
else {
(ref($param_map->{$param}) eq 'HTML::Template::VAR') or
croak("HTML::Template::param() : attempt to set parameter '$param' with a scalar - parameter is not a TMPL_VAR!");
# intetionally /don't/ set the values for non-dot notation params,
# and don't mark them as done, just that they exist.
$self->{num_vars_left_in_loop} -= 1;
}
}
}
# Check to see if a param exists in the template, with support for dot notation
# returns an an array
# - bool for any matches
# - array of keys with dot notation that matched.
sub _exists_in_tmpl {
my ($param_map,$param) = @_;
return 1 if exists $param_map->{$param};
if (my @matching_dot_tokes = grep { /^$param\./ } keys %$param_map) { # (?:\s*[fF][oO][rR]\s+[_a-z]\w*\s+[Ii][nN]\s+)? after the ^ can be used for supporting "for cd in artist.cds" style loops
return (1, @matching_dot_tokes);
}
else {
return undef;
}
}
# =head2 _param_to_tmpl()
#
# my $result = _param_to_tmpl($pluggable,$tmpl_token_name,$param_name,$param_value);
#
# Returns the right thing to put in the template given a token name, a param name
# and a param value. Returns undef if this template token name and param name
# don't match.
#
# The template token name supports the dot notation, which means that method
# calls and nested hashes are expanded.
#
# However, first we check for a literal match, for backwards compatibility with
# HTML::Template.
#
# =cut
sub _param_to_tmpl {
my ($self,$toke_name,$param_name,$param_value) = @_;
# carp("_param_to_tmpl called for '$toke_name', '$param_name', '$param_value'");
# This clause may not be needed because the non-dot-notation
# cases are handled elsewhere.
if ($toke_name eq $param_name) {
# carp("toke equals param: $toke_name == $param_name");
return $param_value;
}
elsif (my ($one, $the_rest) = split /\./, $toke_name, 2) {
# my $loopmap_name = 'this'; # default for mapping array elements for loop vars
# $loopmap_name = $1 if $one =~ s/^\s*[fF][oO][rR]\s+([_a-z]\w*)\s+[Ii][nN]\s+//; the "for x in y" style
if ($one eq $param_name) {
my $loopmap_name = 'this'; # default for mapping array elements for loop vars
$loopmap_name = $1 if $the_rest =~ s/\s*:\s*([_a-z]\w*)\s*$//;
# NOTE: we do the can-can because UNIVSERAL::isa($something, 'UNIVERSAL')
# doesn't appear to work with CGI, returning true for the first call
# and false for all subsequent calls.
# This is exactly what TT does.
# Rhesa (Thu Aug 4 18:33:30 CEST 2005)
# Patch for mixing method calls and attribute access mixing,
# and optional parameter lists!
#
# First we're setting $ref to $param_value
#
# We're going to loop over $the_rest by finding anything that matches
# - a valid identifier $id ( [_a-z]\w* )
# - optionally followed by something resembling an argument list $data
# - optionally followed by a dot or $
# then we're checking if
# - $ref is an object
# - if we can call $id on it
# - in this case we further parse the argument list for strings
# or numbers or references to other h-t params
# - or if it's an attribute
# - or a hashref and we have no $data
# We'll use the result of that operation for $ref as long as there are dots
# followed by an identifier
my $ref = $param_value;
$self->{param_map_done}{$one} ||= $ref;
my $want_loop = ref($self->{param_map}{$toke_name}) eq 'HTML::Template::LOOP';
my(@results); # keeps return values from dot operations
THE_REST:
while( $the_rest =~ s/^
([_a-z]\w*) # an identifier
($RE{balanced})? # optional param list
(?:\.|$) # dot or end of string
//xi ) {
my ($id, $data) = ($1, $2);
if (ref($ref) and blessed($ref)) {
# carp("$ref is an object, and its ref=", ref($ref), Dumper($ref));
if($ref->can($id)) {
my @args = ();
# carp "Calling $id on ", ref($ref), " with $data";
if($data) {
$data =~ s/^\(// and $data =~ s/\)$//;
while( $data ) {
if ($data =~ s/
^\s*
(
$RE{delimited}{-delim=>q{'"`}} # a string
|
$RE{num}{real} # or a number
)
(?:,\s*)?
//xi
) {
my $m = $1;
$m =~ s/^["'`]//; $m =~ s/["'`]$//;
# carp "found string or numeric argument $m";
push @args, $m;
}
elsif( $data =~ s/
^\s*
( # ($1) a sub-expression of the form "object.method(args)"
([_a-z]\w*) # ($2) the object in question
(?:
\.
[_a-z]\w* # method name
$RE{balanced}? # optional argument list
)*
)
(?:,\s*)?
//xi
) {
my ($m, $o) = ($1, $2);
# carp("found subexpression '$m' with '$o'");
# carp Dumper($self->{param_map}), Dumper($self->{param_map_done});
if( exists($self->{param_map}->{$m}) ) {
my $prev = $self->param($m);
# carp("found '$prev' for '$m' in param_map");
push @args, $prev;
}
elsif( exists($self->{param_map_done}{$o}) ) {
my $prev = _param_to_tmpl($self, $m, $o, $self->{param_map_done}{$o});
# carp("found '$prev' for '$o' in param_map_done");
push @args, $prev;
}
else {
croak("Attempt to reference nonexisting parameter '$m' in argument list to '$id' in dot expression '$toke_name': $m is not a TMPL_VAR!");
}
}
else {
# local $,= ', ';
# carp("Parsing is in some weird state. args so far are '@args'. data = '$data'. id='$id'");
last;
}
}
croak("Bare word '$data' not allowed in argument list to '$id' in dot expression '$toke_name'") if $data;
}
# carp("calling '$id' on '$ref' with '@args'");
eval {
if($the_rest or !$want_loop) {
$one .= ".$id";
$ref = $ref->$id(@args);
$self->{param_map_done}{$one} ||= $ref;
} else {
@results = $ref->$id(@args);
}
};
if($@) {
if( $self->{options}{die_on_bad_params} ) {
croak("Error invoking $ref->$id(@args): $@");
} else {
carp("Error invoking $ref->$id(@args): $@");
@results = ();
$ref = $self->{param_map_done}{$one} = '';
$the_rest = '';
last THE_REST;
}
}
}
elsif(reftype($ref) eq'HASH') {
croak("Can't access hash key '$id' with a parameter list! ($data)") if $data;
if($the_rest or !$want_loop) {
$ref = exists( $ref->{$id} ) ? $ref->{$id} : undef;
} else {
@results = exists( $ref->{$id} ) ? $ref->{$id} : ();
}
}
else {
croak("Don't know what to do with reference '$ref', identifier '$id' and data '$data', giving up.");
}
}
elsif(ref($ref) eq 'HASH') {
# carp("accessing key $id on $ref");
if($the_rest or !$want_loop) {
$ref = exists( $ref->{$id} ) ? $ref->{$id} : undef;
} else {
@results = exists( $ref->{$id} ) ? $ref->{$id} : ();
}
}
# carp("setting ref for id=$id, toke=$toke_name, param=$param_name, and param map wants a ", ref($self->{param_map}{$toke_name}), " What we got is ", ref($ref), ", results is ", scalar(@results));
}
if(!$the_rest and $want_loop) {
$ref = ($#results==0 and ref($results[0]) eq 'ARRAY') ? $results[0] : \@results;
}
croak("Trailing characters '$the_rest' in dot expression '$toke_name'") if $the_rest;
# carp("we got $ref. the rest = $the_rest");
if($want_loop) { # fixup the array to a conformant data structure
my @arr = (reftype($ref) eq 'ARRAY') ? @$ref : ($ref);
return [ map { {$loopmap_name => $_} } @arr ];
} else {
$ref = scalar(@$ref) if ref($ref) eq 'ARRAY';
return $ref;
}
}
# no match. give up.
else {
# carp("No match: one=$one, param_name=$param_name, the rest=$the_rest");
return undef;
}
}
# no dots and no literal match: give up
else {
# carp("No dots, no literal match: toke=$toke_name, name=$param_name, value=$param_value");
return undef;
}
}
1;
__END__
=head1 NAME
HTML::Template::Plugin::Dot - Add Magic Dot notation to HTML::Template
=head1 SYNOPSIS
use HTML::Template::Pluggable;
use HTML::Template::Plugin::Dot;
my $t = HTML::Template::Pluggable->new(...);
Now you can use chained accessor calls and nested hashrefs as params, and access
them with a dot notation. You can even pass arguments to the methods.
For example, in your code:
$t->param( my_complex_struct => $struct );
And then in your template you can reference specific values in the structure:
my_complex_struct.key.obj.accessor('hash')
my_complex_struct.other_key
=head1 DESCRIPTION
By adding support for this dot notation to L, the programmers'
job of sending data to the template is easier, and designers have easier access
to more data to display in the template, without learning any more tag syntax.
=head2 EXAMPLES
=head2 Class::DBI integration
L accessors can be used in the template. If the accessor is never
called in the template, that data doesn't have to be loaded.
In the code:
$t->param ( my_row => $class_dbi_obj );
In the template:
my_row.last_name
This extends to related objects or inflated columns (commonly used for date
fields). Here's an example with a date column that's inflated into a DateTime
object:
my_row.my_date.mdy('/')
my_row.my_date.strftime('%D')
Of course, if date formatting strings look scary to the designer, you can keep
them in the application, or even a database layer to insure consistency in all
presentations.
Here's an example with related objects. Suppose you have a Customer object, that
has_a BillingAddress object attached to it. Then you could say something like
this:
...
=head2 More complex uses
The dot notation allows you to pass arguments to method calls (as in the
C example above). In fact, you can pass other objects in the
template as well, and this enables more complex usage.
Imagine we had a (fictional) Formatter object which could perform some basic
string formatting functions. This could be used in e.g. currencies, or dates.
In your code:
$t->param( Formatter => Formatter->new,
order => $order_obj );
In your template:
Amount:
(hint: see L)
This even extends to references to plain tmpl_vars in your template:
$t->param( Formatter => Formatter->new,
plain => 'Jane' );
is
backwards
=head2 TMPL_LOOPs
As of version 0.94, the dot notation is also supported on TMPL_LOOP tags (but
see the L section).
Given an object method (or a hash key) that returns an array or a reference
to an array, we will unwrap that array for use in the loop. Individual array
elements are mapped to a hash C<< { 'this' => $elt } >>, so that you can refer
to them in TMPL_VARs as "this.something".
An example might help. Let's use the canonical Class::DBI example for our data.
Suppose you have an $artist object, which has_many CDs. You can now pass just
the $artist object, and handle the loops in the template:
$t->param( artist => $artist );
The template:
has released these albums:
-
As you can see, each element from the artist.cds() array is called "this" by
default. You can supply your own name by appending ': name' like this:
...
That's not the end of it! You can even nest these loops, displaying the Tracks
for each CD like so:
- ( )
=head2 LIMITATIONS
=over 4
=item * Casing of parameter names
Casing of parameter names follows the option C of
HTML::Template. If you do not use that option, all parameter names are
converted to lower case. I suggest turning this option on to avoid confusion.
=item * Quotes and spaces
Because of the way HTML::Template parses parameter names (which follows the
rules of HTML attributes), you have to be careful when your expressions contain
spaces or quote characters. You can say
C<< >>, but not
C<< >>. You can use single or double quotes
around your entire expression, and then use the other one inside:
C<< >> This is the recommended
way to write your expressions.
(Note: within expressions, the characters in C<< [`'"] >> are recognised as
quote characters. So if you need to pass literal quotes to a method, you could
do it like this: C<< >>. )
=back
=head2 PERFORMANCE
No attempt to even measure performance has been made. For now the focus is on
usability and stability. If you carry out benchmarks, or have suggestions for
performance improvements, be sure to let us know!
=head1 CONTRIBUTING
Patches, questions and feedback are welcome. This project is managed using
the darcs source control system ( http://www.darcs.net/ ). A public darcs archive is here:
http://cgiapp.erlbaum.net/darcs_hive/ht-pluggable/
=head1 AUTHORS
Mark Stosberg, Emark@summersault.comE;
Rhesa Rozendaal, Erhesa@cpan.orgE
=head1 Copyright & License
Parts copyright 2006 Mark Stosberg
Parts copyright 2006 Rhesa Rozendaal
This program is free software; you can redistribute it and/or modify it
under the same terms as perl itself.
=cut
HTML-Template-Pluggable-0.17/lib/HTML/Template/Pluggable.pm 0000644 0001750 0001750 00000016126 10622347363 022205 0 ustar rhesa rhesa package HTML::Template::Pluggable;
use base 'HTML::Template';
use Class::Trigger;
use vars (qw/$VERSION/);
$VERSION = '0.17';
use warnings;
use strict;
use Carp;
=head1 NAME
HTML::Template::Pluggable - Extends HTML::Template with plugin support
=cut
=head1 SYNOPSIS
Just use this module instead of HTML::Template, then use any plugins,
and go on with life.
use HTML::Template::Pluggable;
use HTML::Template::Plugin::Dot;
# Everything works the same, except for functionality that plugins add.
my $t = HTML::Template::Pluggable->new();
=head1 THE GOAL
Ideally we'd like to see this functionality merged into HTML::Template,
and turn this into a null sub-class.
=head1 STATUS
The design of the plugin system is still in progress. Right now we have just
two triggers, in param and output. The name and function of this may change,
and we would like to add triggers in new() and other methods when the need
arises.
All we promise for now is to keep L compatible.
Please get in touch if you have suggestions with feedback on designing the
plugin system if you would like to contribute.
=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
(ref($first) and 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);
$self->call_trigger('middle_param', @_);
# 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)];
# necessary to cooperate with plugin system
next if $self->{param_map_done}{$param};
# 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...
next unless (exists($param_map->{$param}));
# figure out what we've got, taking special care to allow for
# objects that are compatible underneath.
my $value_type = ref($value);
if (defined($value_type) and length($value_type) and ($value_type eq 'ARRAY' or ((ref($value) !~ /^(CODE)|(HASH)|(SCALAR)$/) and $value->isa('ARRAY')))) {
(ref($param_map->{$param}) eq 'HTML::Template::LOOP') or
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}];
} else {
(ref($param_map->{$param}) eq 'HTML::Template::VAR') or
croak("HTML::Template::param() : attempt to set parameter '$param' with a scalar - parameter is not a TMPL_VAR!");
${$param_map->{$param}} = $value;
}
}
}
sub output
{
my $self = shift;
$self->call_trigger('before_output', @_);
$self->SUPER::output(@_);
}
=head1 WRITING PLUGINS
HTML::Template offers a plugin system which allows developers to extend the
functionality in significant ways without creating a creating a sub-class,
which might be impossible to use in combination with another sub-class
extension.
Currently, two triggers have been made available to alter how the values of
TMPL_VARs are set. If more hooks are needed to implement your own plugin idea,
it may be feasible to add them-- check the FAQ then ask about it on the list.
L is used to provide plugins. Basically, you can just:
HTML::Template->add_trigger('middle_param', \&trigger);
A good place to add one is in your plugin's C subroutine:
package HTML::Template::Plugin::MyPlugin;
use base 'Exporter';
sub import {
HTML::Template->add_trigger('middle_param', \&dot_notation);
goto &Exporter::import;
}
=head2 TRIGGER LOCATIONS
=over 4
=item param
We have added one trigger location to this method, named C.
# in a Plugin's import() routine.
HTML::Template->add_trigger('middle_param', \&_set_tmpl_var_with_dot );
This sets a callback which is executed in param() with all of the same
arguments. It is only useful for altering how /setting/ params works.
The logic to read a param is unaffected.
It can set any TMPL_VAR values before the normal param logic kicks in. To do
this, C<$self-E{param_map}> is modified as can be seen from source in
HTML::Template::param(). However, it must obey the following convention of
setting $self->{param_map_done}{$param_name} for each param that is set.
C<$param_name> would be a key from C<$self-E{param_map}>. This notifies the
other plugins and the core param() routine to skip trying to set this value.
$self->{param_map_done} is reset with each call to param(), so that like with a
hash, you have the option to reset a param later with the same name.
=item output
One trigger location here: C.
HTML::Template->add_trigger('before_output', \&_last_chance_params );
This sets a callback which is executed right before output is generated.
=back
=head1 SEE ALSO
=over 4
=item o
L - Add Template Toolkit's magic dot notation to
HTML::Template.
=back
=head1 AUTHOR
Mark Stosberg, C<< >>
=head1 BUGS
Please report any bugs or feature requests to
C, or through the web interface at
L. I will be notified, and then you'll automatically
be notified of progress on your bug as I make changes.
=head1 Copyright & License
Copyright 2006 Mark Stosberg, All Rights Reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
1; # End of HTML::Template::Pluggable
HTML-Template-Pluggable-0.17/GPL 0000644 0001750 0001750 00000043127 10276461477 015236 0 ustar rhesa rhesa GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU 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. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), 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 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 show them these terms so they know 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.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
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 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 derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
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 License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
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.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary 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
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 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 Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing 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 for copying, distributing or modifying
the Program or works based on it.
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.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. 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 this 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
this License, you may choose any version ever published by the Free Software
Foundation.
10. 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
11. 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.
12. 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
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 the public, 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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 is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
HTML-Template-Pluggable-0.17/META.yml 0000644 0001750 0001750 00000001055 10676575531 016135 0 ustar rhesa rhesa # http://module-build.sourceforge.net/META-spec.html
#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
name: HTML-Template-Pluggable
version: 0.17
version_from: lib/HTML/Template/Pluggable.pm
installdirs: site
requires:
Class::Trigger: 0
HTML::Template: 2.7
Regexp::Common: 0
Scalar::Util: 0
Test::MockObject: 1
Test::More: 0
distribution_type: module
generated_by: ExtUtils::MakeMaker version 6.30_01
HTML-Template-Pluggable-0.17/ARTISTIC 0000644 0001750 0001750 00000013737 10276461477 016042 0 ustar rhesa rhesa
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 as specified below.
"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 uunet.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) give non-standard executables non-standard names, and clearly
document 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. You may embed this Package's interpreter within
an executable of yours (by linking); this shall be construed as a mere
form of aggregation, provided that the complete Standard Version of the
interpreter is so embedded.
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 whoever generated
them, and may be sold commercially, and may be aggregated with this
Package. If such scripts or library files are aggregated with this
Package via the so-called "undump" or "unexec" methods of producing a
binary executable image, then distribution of such an image shall
neither be construed as a distribution of this Package nor shall it
fall under the restrictions of Paragraphs 3 and 4, provided that you do
not represent such an executable image as a Standard Version of this
Package.
7. C subroutines (or comparably compiled subroutines in other
languages) supplied by you and linked into this Package in order to
emulate subroutines and variables of the language defined by this
Package shall not be considered part of this Package, but are the
equivalent of input as in Paragraph 6, provided these subroutines do
not change the language in any way that would cause it to fail the
regression tests for the language.
8. Aggregation of this Package with a commercial distribution is always
permitted provided that the use of this Package is embedded; that is,
when no overt attempt is made to make this Package's interfaces visible
to the end user of the commercial distribution. Such use shall not be
construed as a distribution of this Package.
9. The name of the Copyright Holder may not be used to endorse or promote
products derived from this software without specific prior written permission.
10. 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-Pluggable-0.17/Makefile.PL 0000644 0001750 0001750 00000001254 10602352011 016606 0 ustar rhesa rhesa # Note: this file was auto-generated by Module::Build::Compat version 0.03
use ExtUtils::MakeMaker;
WriteMakefile
(
'PL_FILES' => {},
'INSTALLDIRS' => 'site',
'NAME' => 'HTML::Template::Pluggable',
'EXE_FILES' => [],
'VERSION_FROM' => 'lib/HTML/Template/Pluggable.pm',
'PREREQ_PM' => {
'Test::More' => 0,
'Test::MockObject' => 1,
'Scalar::Util' => 0,
'Regexp::Common' => 0,
'Class::Trigger' => 0,
'HTML::Template' => '2.7'
}
)
;
HTML-Template-Pluggable-0.17/Build.PL 0000644 0001750 0001750 00000001352 10276461501 016143 0 ustar rhesa rhesa use strict;
use warnings;
use Module::Build;
my $builder = Module::Build->new(
module_name => 'HTML::Template::Pluggable',
license => 'perl',
dist_author => 'Mark Stosberg ',
dist_version_from => 'lib/HTML/Template/Pluggable.pm',
requires => {
'Test::More' => 0,
# Required because about every test uses it.
'Test::MockObject' => 1,
'HTML::Template' => 2.7,
'Regexp::Common' => 0,
'Scalar::Util' => 0,
'Class::Trigger' => 0,
},
add_to_cleanup => [ 'HTML-Template-Pluggable-*' ],
create_makefile_pl => 'traditional',
create_readme => 1,
);
$builder->create_build_script();
HTML-Template-Pluggable-0.17/README 0000644 0001750 0001750 00000007541 10602352011 015521 0 ustar rhesa rhesa NAME
HTML::Template::Pluggable - Extends HTML::Template with plugin support
SYNOPSIS
Just use this module instead of HTML::Template, then use any plugins,
and go on with life.
use HTML::Template::Pluggable;
use HTML::Template::Plugin::Dot;
# Everything works the same, except for functionality that plugins add.
my $t = HTML::Template::Pluggable->new();
THE GOAL
Ideally we'd like to see this functionality merged into HTML::Template,
and turn this into a null sub-class.
STATUS
The design of the plugin system is still in progress. Right now we have
just two triggers, in param and output. The name and function of this
may change, and we would like to add triggers in new() and other methods
when the need arises.
All we promise for now is to keep HTML::Template::Plugin::Dot
compatible. Please get in touch if you have suggestions with feedback on
designing the plugin system if you would like to contribute.
WRITING PLUGINS
HTML::Template offers a plugin system which allows developers to extend
the functionality in significant ways without creating a creating a
sub-class, which might be impossible to use in combination with another
sub-class extension.
Currently, two triggers have been made available to alter how the values
of TMPL_VARs are set. If more hooks are needed to implement your own
plugin idea, it may be feasible to add them-- check the FAQ then ask
about it on the list.
Class::Trigger is used to provide plugins. Basically, you can just:
HTML::Template->add_trigger('middle_param', \&trigger);
A good place to add one is in your plugin's "import" subroutine:
package HTML::Template::Plugin::MyPlugin;
use base 'Exporter';
sub import {
HTML::Template->add_trigger('middle_param', \&dot_notation);
goto &Exporter::import;
}
TRIGGER LOCATIONS
param
We have added one trigger location to this method, named
"middle_param".
# in a Plugin's import() routine.
HTML::Template->add_trigger('middle_param', \&_set_tmpl_var_with_dot );
This sets a callback which is executed in param() with all of the
same arguments. It is only useful for altering how /setting/ params
works. The logic to read a param is unaffected.
It can set any TMPL_VAR values before the normal param logic kicks
in. To do this, "$self->{param_map}" is modified as can be seen from
source in HTML::Template::param(). However, it must obey the
following convention of setting $self->{param_map_done}{$param_name}
for each param that is set. $param_name would be a key from
"$self->{param_map}". This notifies the other plugins and the core
param() routine to skip trying to set this value.
$self->{param_map_done} is reset with each call to param(), so that
like with a hash, you have the option to reset a param later with
the same name.
output
One trigger location here: "before_output".
HTML::Template->add_trigger('before_output', \&_last_chance_params );
This sets a callback which is executed right before output is
generated.
SEE ALSO
o HTML::Template::Plugin::Dot - Add Template Toolkit's magic dot
notation to HTML::Template.
AUTHOR
Mark Stosberg, ""
BUGS
Please report any bugs or feature requests to
"bug-html-template-pluggable@rt.cpan.org", or through the web interface
at . I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
Copyright & License
Copyright 2006 Mark Stosberg, All Rights Reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.