[Templates-cvs] cvs commit: TT3/examples compiler.pl custom.pl htmlt.pl scanner.pl tt3.pl html2.pl
cvs@template-toolkit.org
cvs@template-toolkit.org
Sat, 11 Dec 2004 13:56:54 +0000
cvs 04/12/11 13:56:54
Modified: examples compiler.pl custom.pl htmlt.pl scanner.pl tt3.pl
Removed: examples html2.pl
Log:
* updated examples
Revision Changes Path
1.2 +49 -16 TT3/examples/compiler.pl
Index: compiler.pl
===================================================================
RCS file: /template-toolkit/TT3/examples/compiler.pl,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- compiler.pl 2004/01/30 09:32:52 1.1
+++ compiler.pl 2004/12/11 13:56:54 1.2
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w # -*- perl -*-
#
-# Perl script written by Andy Wardley. This is free software.
+# This example shows the Perl code generated by the compiler.
#
use strict;
@@ -9,15 +9,13 @@
use Template::TT3::Compiler;
my $compiler = Template::TT3::Compiler->new({
- grammar => 'Template::TT3::Grammar::TT3',
- tagset => 'Template::TT3::Tagset::TT3',
- generator => 'Template::TT3::Generator::Debug',
interpolate => 1,
+ pretty => 1,
}) || die Template::TT3::Compiler->error();
local $/ = undef;
my $input = <DATA>;
-my $output = $compiler->compile($input)
+my $output = $compiler->compile($input, name => 'compiler example')
|| die $compiler->error();
print "-- input --\n",
@@ -26,14 +24,49 @@
$output, "\n";
__DATA__
-Hello World
-[% foo %] and $bar and ${baz} but not \$bam
-[% foo('hello world').bar('nice to see you' ) %]
-you can now have spaces in embedded variables
-like $foo('hello world').bar('and it works') as expected
-and also you can do $foo(bar + baz)
-[% INCLUDE header
- title = 'Hello World'
- author = page.author or site.author
-%]
-The end
+[% META title = 'Compiler Example' %]
+
+Hello World!
+
+Here are some variables:
+ [% foo %] and $bar and ${baz} but not \$bam
+ [% foo('hello world').bar('nice to see you') %]
+
+INTERPOLATE is currently set ON, but we can turn it off like so:
+[% INTERPOLATE off %] and then the embedded variables below are not
+interpolated:
+
+ [% foo %] but neither $bar nor ${baz}
+
+There's a new MY variable type. Here's an example:
+
+ [% MY x = 'private bar variable' %]
+ [% y = 'regular foo variable' %]
+
+The 'x' variable is declared as MY, so it is created in the underlying
+Perl code as a "my $var_x" variable, making it fast to access, and
+totally private to the current lexical template scope. The 'y'
+variable is a regular TT variable that is stored in the current
+context variables.
+
+ [% x %]
+ [% y %]
+
+The parser and scanner are now smart enough to Do The Right Thing when
+the tag start or end tokens are embedded in a quote string.
+
+ [% start_tag = '[%' # no problem
+ end_tag = '%]'
+ %]
+
+You can now also included spaces in embedded variables, for
+example in argument lists: [% INTERPOLATE on %]
+
+ $foo('hello world').bar(10, 20, 30)
+
+You can also put full expressions in argument lists:
+
+ [% foo(x * 20) %]
+ [% bar(y && z ? x * 10 : x * 20) %]
+
+And much, much more...
1.4 +2 -4 TT3/examples/custom.pl
Index: custom.pl
===================================================================
RCS file: /template-toolkit/TT3/examples/custom.pl,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- custom.pl 2004/01/30 14:35:46 1.3
+++ custom.pl 2004/12/11 13:56:54 1.4
@@ -7,15 +7,13 @@
use warnings;
use lib qw( ../lib ./lib );
use Template::TT3::Compiler;
+use Template::Generator::Debug;
my $compiler = Template::TT3::Compiler->new({
- grammar => 'Template::TT3::Grammar::TT3',
- tagset => 'Template::TT3::Tagset::TT3',
- generator => 'Template::TT3::Generator::Debug',
+ generator => 'Template::Generator::Debug',
interpolate => 1,
directives => {
hello => {
- rule => 'expression' ,
},
},
generators => {
1.4 +160 -84 TT3/examples/htmlt.pl
Index: htmlt.pl
===================================================================
RCS file: /template-toolkit/TT3/examples/htmlt.pl,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- htmlt.pl 2004/11/26 12:50:54 1.3
+++ htmlt.pl 2004/12/11 13:56:54 1.4
@@ -1,130 +1,206 @@
#!/usr/bin/perl -w # -*- perl -*-
#
-# Example simulating HTML::Template
+# This example is a quick proof-of-concept hack to show how you
+# can write a custom tag to parse your own language (e.g. HTML::Template)
+# and feed structured expression events (currently a little clumsy) into
+# the Template::Handler back-end, and leave TT to handle the rest. Templates
+# are compiled into Perl code, just as for regular TT templates with which
+# they are fully interoperable.
#
-# Perl script written by Andy Wardley. This is free software.
+# Andy Wardley. 11th December 2004.
#
-# <TMPL_VAR>
-# <TMP_INCLUDE>
-# <TMPL_IF> ... <TMPL_ELSE> ... </TMPL_IF>
-# <TMPL_UNLESS> ... <TMPL_ELSE> ... </TMPL_UNLESS>
-# <TMPL_LOOP> ... </TMPL_LOOP>
+# Directives implemented:
+# <TMPL_VAR>
+# <TMP_INCLUDE>
+# <TMPL_IF> ... <TMPL_ELSE> ... </TMPL_IF>
+# <TMPL_UNLESS> ... <TMPL_ELSE> ... </TMPL_UNLESS>
+#
+# Not yet implemented:
+# <TMPL_LOOP> ... </TMPL_LOOP> # not implemented in generator
+#
use strict;
use warnings;
use lib qw( ../lib ./lib );
-use Template::TT3::Compiler;
-use Template::TT3::Tag::Closed;
-
-package Template::TT3::Tag::HTMLTemplate;
-use base qw( Template::TT3::Tag::Closed );
-use vars qw( $TAG );
+use Template;
+use Template::Compiler;
+use Template::Parser;
+use Template::Tag::Closed;
+use Template::Generator::Debug;
+use Template::Directive::Include;
+
+# run with '-d' option to enable debugging
+my $DEBUG =
+#$Template::Parser::DEBUG =
+grep(/^--?d(ebug)?/, @ARGV);
+
+#------------------------------------------------------------------------
+# define a custom Tag object for parsing HTML::Template-like tags.
+#------------------------------------------------------------------------
+
+package Template::Tag::HTMLTemplate;
+use Template::Parser;
+use base qw( Template::Tag::Closed );
-$TAG = {
- name => 'htmltemplate',
+our $TAG = {
start => qr[</?TMPL_\w+]i,
end => qr[/?>],
};
+our $PARSER = Template::Parser->new( tag_end => $TAG->{ end } );
+
+
sub parse {
my ($self, $textref, $handler, $match) = @_;
my $start = $match->{ start };
-
+ my $name;
+
+ $handler->line($match->{ line });
+
# remove leading '<' and TMPL
$start =~ s/^<//;
$start =~ s/TMPL_//i;
- # copy all arguments into hash
- my $args = { };
- while ($$textref =~ /^\s*(\w+)="([^"]*)"/g) {
- $args->{ lc $1 } = $2;
+ # many directives start with NAME="something", so we'll look
+ # for that
+ if ($$textref =~ s/ \s* NAME = "([^"]*)" //x) {
+ $name = $1;
}
-
- my $dir;
+
if ($start eq 'INCLUDE') {
+
+ #----------------------------------------------------------------
+ # <TMPL_INCLUDE NAME="header" arg1="value" arg="value2">
+ #----------------------------------------------------------------
+
return $self->error("no NAME provided for TMPL_INCLUDE directive")
- unless $args->{ name };
- return $handler->directive( include => $args->{ name } )
+ unless $name;
+
+ my $paths = $PARSER->parse_paths(\$name)
+ || return $self->error("invalid NAME in TMPL_INCLUDE directive");
+
+ my $params = $PARSER->parse_params($textref);
+
+ return $handler->expr( include => $paths, $params )
|| $self->error($handler->error());
}
elsif ($start eq 'VAR') {
+
+ #----------------------------------------------------------------
+ # <TMPL_VAR NAME="foobar">
+ #----------------------------------------------------------------
+
return $self->error("no NAME provided for TMPL_VAR directive")
- unless $args->{ name };
- return $handler->directive( get => $args->{ name } )
+ unless $name;
+
+ my $expr = $PARSER->parse_variable(\$name)
+ || return $self->error($PARSER->error());
+
+ return $handler->expr( get => $expr )
|| $self->error($handler->error());
}
- elsif ($start eq 'LOOP') {
- return $self->error("no NAME provided for TMPL_LOOP directive")
- unless $args->{ name };
- return $handler->start_block( loop => $args->{ name } )
- ? $handler : $self->error($handler->error());
- }
- elsif ($start eq '/LOOP') {
- return $handler->end_block('loop')
- ? $handler : $self->error($handler->error());
- }
elsif ($start eq 'IF') {
+
+ #----------------------------------------------------------------
+ # <TMPL_IF NAME="foobar"> ... </IF>
+ #----------------------------------------------------------------
+
return $self->error("no NAME provided for TMPL_IF directive")
- unless $args->{ name };
- # tmp hack
- return $handler->start_block( if => $args->{ name } )
- ? $handler : $self->error($handler->error());
+ unless $name;
+
+ my $expr = $PARSER->parse_expression(\$name)
+ || return $self->error($PARSER->error());
+
+ return $handler->start_expr( [ if => $expr ],
+ { keyword => $start,
+ line => $match->{ line },
+ } )
+ || $self->error($handler->error());
}
elsif ($start eq 'UNLESS') {
+
+ #----------------------------------------------------------------
+ # <TMPL_UNLESS NAME="foobar"> ... </UNLESS>
+ #----------------------------------------------------------------
+
return $self->error("no NAME provided for TMPL_UNLESS directive")
- unless $args->{ name };
- return $handler->start_block( unless => $args->{ name } )
- ? $handler : $self->error($handler->error());
+ unless $name;
+
+ my $expr = $PARSER->parse_expression(\$name)
+ || return $self->error($PARSER->error());
+
+ return $handler->start_expr( [ unless => $expr ],
+ { keyword => $start,
+ line => $match->{ line },
+ } )
+ || $self->error($handler->error());
}
elsif ($start eq 'ELSE') {
- return $handler->next_block('else')
- ? $handler : $self->error($handler->error());
+ return $handler->next_expr({ keyword => 'ELSE',
+ line => $match->{ line }
+ })
+ || $self->error($handler->error());
}
elsif ($start eq '/IF') {
- # tmp hack
- return $handler->end_block()
- ? $handler : $self->error($handler->error());
+ return $handler->end_expr()
+ || $self->error($handler->error());
}
+ elsif ($start eq 'LOOP') {
+ die "LOOP not yet implemented\n";
+ }
+ elsif ($start eq '/LOOP') {
+ die "/LOOP not yet implemented\n";
+ }
else {
return $self->error("unknown directive: $start");
}
}
+
+#------------------------------------------------------------------------
+# create a custom compiler with this tag, and only this tag defined.
+# (we could subclass from Template::TT3::Compiler to get all the regular
+# TT tags in addition to our custom HTML::Template tag).
+#------------------------------------------------------------------------
+
package main;
+
+my $compiler = Template::Compiler->new({
+ tags => [ htmlt => Template::Tag::HTMLTemplate->new() ],
+}) || die Template::Compiler->error();
+
+
+#------------------------------------------------------------------------
+# create a Template object with the custom compiler enabled by default,
+# and have it process our example template.
+#------------------------------------------------------------------------
+
+my $tt3 = Template->new({
+ template_path => 'templates',
+ compilers => {
+ default => $compiler,
+ },
+}) || die Template->error();
+
+if ($DEBUG) {
+ my $template = $tt3->context->template('htmltemplate')
+ || die $tt3->error();
+ print "template code: ", $template->source->code(), "\n";
+}
+
+$tt3->process('htmltemplate', {
+ message => 'Hello World',
+ interesting => 'very',
+ myhash => {
+ x => 100,
+ y => {
+ z => 200,
+ },
+ },
+ mycode => sub {
+ return "called subref(" . join(', ', @_) . ")";
+ },
+}) || die $tt3->error();
+
+
-my $compiler = Template::TT3::Compiler->new({
- tags => [ Template::TT3::Tag::HTMLTemplate->new() ],
- generator => 'Template::TT3::Generator::Debug',
-}) || die Template::TT3::Compiler->error();
-
-local $/ = undef;
-my $input = <DATA>;
-my $output = $compiler->compile($input)
- || die $compiler->error();
-
-print "-- input --\n",
- $input, "\n",
- "-- output --\n",
- $output, "\n";
-
-__DATA__
-<html>
- <head>
- <title>Template Toolkit / HTML::Template Test</title>
- </head>
- <body>
- <TMPL_INCLUDE NAME="header">
-
- <p>
- my name is <TMPL_VAR NAME="myname">.
- </p>
- <TMPL_IF NAME="interesting">
- I am very interesting.
- <TMPL_LOOP NAME="interest">
- I like <TMPL_VAR NAME="interest"/>
- </TMPL_LOOP>
- <TMPL_ELSE>
- I am very boring.
- </TMPL_IF>
- </body>
-</html>
1.2 +49 -35 TT3/examples/scanner.pl
Index: scanner.pl
===================================================================
RCS file: /template-toolkit/TT3/examples/scanner.pl,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- scanner.pl 2004/02/02 10:03:52 1.1
+++ scanner.pl 2004/12/11 13:56:54 1.2
@@ -1,30 +1,46 @@
#!/usr/bin/perl -w # -*- perl -*-
#
-# Perl script written by Andy Wardley. This is free software.
+# This example shows how the scanner can be customised to detect
+# different kinds of embedded tags. We create a Template::Compiler
+# and define a set of tags for the Template::Scanner to detect.
+# We provide custom scanning subroutines to parse the contents
+# of the tag and generate parse events against the handler.
+# These are later converted into a text representation of the
+# parse tree for debugging purposes, thanks to the efforts of
+# Template::Generator::Debug. We additionally define two generator
+# subroutines to help the generator turn our compiled directives
+# into real-world code. This would normally be Perl, but it's
+# just some debugging output in this example.
#
+# Andy Wardley. 11th December 2004.
+#
+
use strict;
use warnings;
use lib qw( ../lib ./lib );
-use Template::TT3::Handler;
-use Template::TT3::Scanner;
-use Template::TT3::Generator::Debug;
-use Template::TT3::Tag;
+use Template::Compiler;
+use Template::Generator::Debug;
+use Template::Tag::Closed;
-# define scanner
-my $scanner = Template::TT3::Scanner->new({
+my $compiler = Template::Compiler->new({
tags => [
- Template::TT3::Tag->new({ # TODO: should be able to pass hash refs
- start => '<$', # and have the scanner auto-vivify
- end => '$>', # Tag objects for you
+ dollar => Template::Tag::Closed->new({
+ start => '<$',
+ end => '$>',
parse => \&dollar_tag,
}),
- Template::TT3::Tag->new({
+ question => Template::Tag::Closed->new({
start => '<?',
end => '?>',
parse => \&question_tag,
}),
- ]
+ ],
+ generator => Template::Generator::Debug->new(),
+ generators => {
+ question => \&generate_question,
+ dollar => \&generate_dollar,
+ },
});
# subroutine for parsing <$ ... $> tags
@@ -38,7 +54,7 @@
my $locn = $self->location();
# notify the handler of some new content
- return $handler->directive( dollar => "at $locn: [$$textref]" )
+ return $handler->expr( dollar => "at $locn: [$$textref]" )
|| $self->error($handler->error());
}
@@ -51,29 +67,28 @@
my $locn = $self->location();
# first argument denotes the content type, any other args can follow
- return $handler->directive( question => "at $locn: [$$textref]" )
+ return $handler->expr( question => "at $locn: [$$textref]" )
|| $self->error($handler->error());
}
+# subroutine for generating code for question tag
+sub generate_question {
+ my ($self, $text) = @_;
+ return "QUESTION $text";
+}
+
+# subroutine for generating code for dollar tag
+sub generate_dollar {
+ my ($self, $text) = @_;
+ return "DOLLAR $text";
+}
+
# read input from __DATA__
local $/ = undef;
my $input = <DATA>;
-# define a handler to construct document content
-my $handler = Template::TT3::Handler->new();
+my $output = $compiler->compile($input) || die $compiler->error();
-# scan document
-$handler->start();
-$scanner->scan($input, $handler) || die $scanner->error();
-my $result = $handler->end() || die $handler->error();
-
-# create a generator to display document
-my $generator = Template::TT3::Generator::Debug->new({});
-# generators );
-
-my $output = $generator->generate($result)
- || die $generator->error();
-
print "-- input --\n",
$input, "\n",
"-- output --\n",
@@ -89,11 +104,10 @@
lines
and ?> the scanner takes
care of counting
-<$
-
- line
- numbers
-
-$> for you
-
+all the
+<$
+ line
+ numbers
+$>
+for you
1.2 +10 -31 TT3/examples/tt3.pl
Index: tt3.pl
===================================================================
RCS file: /template-toolkit/TT3/examples/tt3.pl,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- tt3.pl 2004/11/26 12:51:49 1.1
+++ tt3.pl 2004/12/11 13:56:54 1.2
@@ -1,40 +1,19 @@
#!/usr/bin/perl -w # -*- perl -*-
#
-# Perl script written by Andy Wardley. This is free software.
+# example/tt3.pl
#
+# The first TT3 script ever to process a complete template
+# This is free software. May a thousand flowers blossom.
+#
+# Andy Wardley. 11th December 2004
+#
use strict;
use warnings;
use lib qw( ../lib ./lib );
-use Template::TT3::Compiler::TT3;
-
-my $compiler = Template::TT3::Compiler::TT3->new({
- generator => 'Template::TT3::Generator::Debug',
- interpolate => 1,
- directives => {
- hello => {
- rule => 'expression' ,
- },
- },
- generators => {
- hello => sub {
- my ($self, $expr) = @_;
- $expr = $self->generate($expr) || return;
- $expr =~ s/\n/\n /g;
- return "<hello:\n $expr\n>";
- },
- },
-}) || die Template::TT3::Compiler->error();
-
-local $/ = undef;
-my $input = <DATA>;
-my $output = $compiler->compile($input)
- || die $compiler->error();
+use Template;
-print "-- input --\n",
- $input, "\n",
- "-- output --\n",
- $output, "\n";
+my $tt3 = Template->new( template_path => 'templates' );
-__DATA__
-[% HELLO world + his.wife %]
+$tt3->process("example.html", { message => 'Hello World' })
+ || die $tt3->error();