You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Thomas Klausner <do...@zsi.at> on 2002/11/15 23:42:22 UTC
RFC: Template::YetAnother
Hi!
Yes, this is a RFC for Yet Another Templating System. I know that
there are a lot of those around. But this own might be
different/interesting (at least I think/hope so...)
I also posted this on perlmonks:
http://www.perlmonks.org/index.pl?node_id=213300
So, here it is, in POD format:
=pod
=head1 NAME
Template::YetAnother
=head1 INTRODUCTION
=head2 Why another templating system?
There are a lot of templating modules on CPAN. Some are obvious, some
are hidden in very strange namespaces (eg HTML::Processor). Some are
used a lot, some not. I read a lot of manpages, but definitly not all
and none completly. If there is a module doing what I am proposing,
please inform me!
Before we continue, read Perrin Harkins' "Choosing a Templating
System", available here:
http://perl.apache.org/docs/tutorials/tmpl/comparison/comparison.html
There are different types of Templating Systems available. Some are
complete Application Frameworks, including stuff like Session
Management, Form Handling etc. Examples include Mason, AxKit and
Embperl. They are nice. They work. But that's not what I'm looking
for.
I want Just Templates.
Why?
Because IMO, the main reason for using templates is to seperate code
from markup. The code produces some data. The markup displays the
data. Those Application Frameworks don't seem to be too good at
seperating code and markup (I have to admit though, that I know next
to nothing about them, only that they are too big/powerfull). After
all, they B<embed> code in markup.
So I am looking for a "pipeline"-type, Just-Template System, which
reduces the number of available modules somewhat.
The best-known contestors here are TemplateToolkit
resp. Apache::Template and HTML::Template. But if you look at there
manpages, you'll quickly find references to stuff like C<TPL_LOOP>
(HTML::Template). TT2 even has it's own mini-language. So, once again,
code (even rather trivial) mixed with the markup.
There is one module, CGI::FastTemplate, that does seperate code from
markup completly. But the way different templates are strung together
seems rather comlicated to me.
But why is there no Templating System with a clean seperation of code
and markup?
There are two types of code (at least) that pollute nearly all
Templating Systems:
=over
=item * Loops
Loops are one of the things computers do best (for very good reasons,
mainly lazyness of humans). So, a template should be able to handle
large amounts of similar data using ... a template. Obvious. So a
Templating System must handle Loops. Most (all?) do it by adding some
sort of LOOP or FOREACH Syntax, thereby introducing code into the
markup. But there is another way to loop over data: Recursion.
=item * If-Blocks
As the template is rather general, you want it to handle slightly
different kinds of data differently. One very obvious example would be
to print something like "No Data" instead of C<undef>. Or to highlight
the current item in a list.
Often IF-Blocks are also used to present different kinds of data
differently, which can lead to long series of IF-ELSIF-ELSE
blocks. Which is a clear pointer that one should use Object
Orientation instead.
Another way would be to add something like attributes to the data. But as far as I know, attributes aren't included that thightly into Perl as OO.
=back
So I am looking for a Templating System that does Just Templating, no
code in the markup, maybe by using recursion and OO.
I didn't find anything.
So I am proposing this:
=head2 Template::YetAnother
The name is just a placeholder right now, other ideas are:
=over
=item * Template::Dumper
=item * Template::Stringify
=item * Template::OO
=item * Template::OO_Dumper
=item * any other ideas?
=back
Template::YetAnother is yet another Templating module, using a
slightly different approach than most of the other Templating modules.
The templates are completly dumb. There is B<absolutly no> piece of
code in a template - neither Perl nor "mini language". A template
consists of arbitrary text (e.g. HTML) and Template Tags, e.g.
[% title %]
Your application builds up a data structure. The data structure
consists of various Perl Data Types (Strings, Arrays, Hashes) and
Template::YetAnother Objects (or Data Structures marked with some
other kind of metainformation, e.g. with attributes)
The data structure gets passed to Template::YetAnother, which
magically find the right template for each object and replaces all
Template Tags (recursivly) with the dumped/stringified data structure.
Template::YetAnother is like Data::Dumper on steroids. It's the big
Stringifyer.
Template::YetAnother doesn't use one monolithic template, but a lot of
small template fragments, each one correlating to a data type
generated by the application.
Template::YetAnother is just an idea right now. I am trying the "write
documentation, write tests, write code" way of development... There is
only a small prove-of-concept type bit of code (I can send it/post it
if somebody cares..). I'll really appreciate feedback on this.
I hope that this descripction is clear enought. If not, let me know and I'll post some clarification / examples.
=head1 SYNOPSIS
# generate a new template handler
my $th=Template::YetAnother->new
({
namespace=>'acme',
template_dir=>'/projects/acme/templates/',
});
# build up a data structure
$data={
title=>$th->title('this is the title'),
breadcrumb=>[
$th->link({url=>'/index.html',text=>'Home'}),
$th->separator_breadcrumb,
$th->link({url=>'/acme/index.html',text=>'Acme'}),
$th->separator_breadcrumb,
$th->link({url=>'/acme/bleach.html',text=>'Bleach'}),
],
content=>[
$th->element({heading=>'SYNOPSIS',value=>'blabla'}),
$th->element({heading=>'DESCRIPTION',value=>'foo bar'}),
],
lastmod=>scalar localtime,
};
# fill template & print
print $th->fill({data=>$data});
##################################################
# for this to work, we need the following files in
# /projects/acme/templates
# file: main.tpl
<html><head><title>[% title %]</title></head>
<body>
<center>[% breadcrumb %]</center>
<h1>[% title %]</h1>
[% content %]
<hr>
[% lastmod %]
# file: link.tpl
<a href='[% url %]'>[% text %]</a>
# file: seperator.tpl
/
# file: element.tpl
<h3>[% heading %]</h3>
<p>[% value %]</p>
##################################################
# the finished template should look like this:
<html><head><title>this is the title</title></head>
<body>
<center>
<a href='/index.html'>Home</a> /
<a href='/acme/index.html'>Acme</a> /
<a href='/acme/bleach.html'>Bleach</a>
</center>
<h1>this is the title</h1>
<h3>SYNOPSIS</h3>
<p>blabla</p>
<h3>DESCRIPTION</h3>
<p>foo bar</p>
<hr>
Thu Nov 7 21:51:05 200
=head1 DESCRIPTION
=head2 new
my $th=Template::YetAnother->new({
template_dir=>'/path/to/templates/',
# namespace=>'projectname',
# start_tag=>'<--',
# end_tag=> '-->',
});
Generates a new Template::YetAnother Handler Object.
=head2 fill
$th->fill($data);
Fill the template with the data in the data structure.
=head2 _gen
my $fragment=$th->_gen('type',$data)
Generates a new Template Fragment
You usually do not have to call this. You just say
$th->type($data)
and AUTOLOAD passes it to C<_gen>
=head1 EXPORT
Nothing.
=head1 SEE ALSO
Search for C<template> on http://search.cpan.org, if you dare.
=head1 AUTHOR
Thomas Klausner, domm@zsi.at, http://domm.zsi.at
=head1 COPYRIGHT
This module is Copyright (c) 2002 Thomas Klausner, ZSI.
All rights reserved.
You may use and distribute this module according to the same terms
that Perl is distributed under.
=cut
--
#!/usr/bin/perl http://domm.zsi.at
for(ref(bless[],just'another'perl'hacker)){s-:+-$"-g&&print$_.$/}
Re: RFC: Template::YetAnother
Posted by Robert Landrum <rl...@aol.net>.
I've said it before... :)
http://mathforum.org/epigone/modperl/zhixswahar/v04210105b76eecf6c2be@%5b192.168.1.3%5d
Rob
On Sat, Nov 16, 2002 at 10:33:44PM +0100, Thomas Klausner wrote:
> Hi!
>
> On Sat, Nov 16, 2002 at 03:31:39PM -0500, Perrin Harkins wrote:
> > >I also posted this on perlmonks:
> > >http://www.perlmonks.org/index.pl?node_id=213300
> >
> > Ovid on Perlmonks already said some of the things I would have said
> > about needing a presentation language. For a templating system to be
> > useful, it has to be able to deal with loops and conditionals. Your
> > system pushes those into the Perl code, splitting the presentation
> > control into multiple places. This fails one of my major goals: the
> > template coders should be able to change the presentation without help
> > from a Perl coder. What if they decide they don't want to loop through
> > the links, but rather just print a message saying there are some? What
> > if they only want to show the first two? What if they want to display a
> > list with commas between the elements where they didn't use a separator
> > before? A mature templating system can handle all of these issues
> > without changing the main Perl module code.
>
> That's a very good point I didn't really think about. I was thinking
> of templates as DUMB frontends that should just display
> data. Period.
>
> Thinking of them as tools that handle presentation logic (as Ovid
> pointed out) seems to make more sense.
>
> It does pay of to write RFCs before starting to code...
>
> > >Because IMO, the main reason for using templates is to seperate code
> > >from markup.
> >
> > It sounds to me like you want one of the HTML attribute ones, like Petal
> > or HTML::Seamstress. What was wrong with those?
>
> One problem I see with HTML::Seamstress is that it uses the HTML
> attributes 'class' and 'id' for templating info. But those attributes
> are used by CSS and JavaScript and might conflict somehow. I do not
> know if you can change the behaviour of HTML::Seamstress to use other
> attributes, though. But this stopped my from looking further.
>
> And I didn't look at Petal. For now.
>
> > >There is one module, CGI::FastTemplate, that does seperate code from
> > >markup completly. But the way different templates are strung together
> > >seems rather comlicated to me.
> >
> > It's not complicated, but it is somewhat confusing the first time you
> > look at it. I don't find your approach much easier though.
>
> Well, I found mine easier :-)
> (But I guess this is the reason for the Template Flood on CPAN -
> everbody finds his own solution easier...)
>
> > Isn't your fill method just doing a sort of multi-level join here? All
> > of the data is passed in already, so there is no reason to delay
> > evaluation of the templates.
>
> The main reason for doing this was to simplify testing. I planned to
> just test the plain data structures, that should be free of HTML at
> this time (before the fill). This (testing) was in fact the reason I
> started thinking about this proposal in the first place.
>
> > More importantly, your use of AUTOLOAD to treat method calls as file
> > names looks neat, but is not a good approach. It's limiting (all
> > templates in one directory!) and has potential security issues with
> > namespace clashes. These are all just the same method call with a
> > single argument changed, so why not write them that way?
>
> I planned to handle those namespace and filename issues.
>
> > ..
> > force you to use them. They are flexible modules. I think you should
> > look at them more closely before you go off on your own.
>
> That's what I'll do. Thanks for the excellent feedback.
>
> --
> #!/usr/bin/perl http://domm.zsi.at
> for(ref(bless[],just'another'perl'hacker)){s-:+-$"-g&&print$_.$/}
Re: RFC: Template::YetAnother
Posted by Thomas Klausner <do...@zsi.at>.
Hi!
On Sat, Nov 16, 2002 at 03:31:39PM -0500, Perrin Harkins wrote:
> >I also posted this on perlmonks:
> >http://www.perlmonks.org/index.pl?node_id=213300
>
> Ovid on Perlmonks already said some of the things I would have said
> about needing a presentation language. For a templating system to be
> useful, it has to be able to deal with loops and conditionals. Your
> system pushes those into the Perl code, splitting the presentation
> control into multiple places. This fails one of my major goals: the
> template coders should be able to change the presentation without help
> from a Perl coder. What if they decide they don't want to loop through
> the links, but rather just print a message saying there are some? What
> if they only want to show the first two? What if they want to display a
> list with commas between the elements where they didn't use a separator
> before? A mature templating system can handle all of these issues
> without changing the main Perl module code.
That's a very good point I didn't really think about. I was thinking
of templates as DUMB frontends that should just display
data. Period.
Thinking of them as tools that handle presentation logic (as Ovid
pointed out) seems to make more sense.
It does pay of to write RFCs before starting to code...
> >Because IMO, the main reason for using templates is to seperate code
> >from markup.
>
> It sounds to me like you want one of the HTML attribute ones, like Petal
> or HTML::Seamstress. What was wrong with those?
One problem I see with HTML::Seamstress is that it uses the HTML
attributes 'class' and 'id' for templating info. But those attributes
are used by CSS and JavaScript and might conflict somehow. I do not
know if you can change the behaviour of HTML::Seamstress to use other
attributes, though. But this stopped my from looking further.
And I didn't look at Petal. For now.
> >There is one module, CGI::FastTemplate, that does seperate code from
> >markup completly. But the way different templates are strung together
> >seems rather comlicated to me.
>
> It's not complicated, but it is somewhat confusing the first time you
> look at it. I don't find your approach much easier though.
Well, I found mine easier :-)
(But I guess this is the reason for the Template Flood on CPAN -
everbody finds his own solution easier...)
> Isn't your fill method just doing a sort of multi-level join here? All
> of the data is passed in already, so there is no reason to delay
> evaluation of the templates.
The main reason for doing this was to simplify testing. I planned to
just test the plain data structures, that should be free of HTML at
this time (before the fill). This (testing) was in fact the reason I
started thinking about this proposal in the first place.
> More importantly, your use of AUTOLOAD to treat method calls as file
> names looks neat, but is not a good approach. It's limiting (all
> templates in one directory!) and has potential security issues with
> namespace clashes. These are all just the same method call with a
> single argument changed, so why not write them that way?
I planned to handle those namespace and filename issues.
> ..
> force you to use them. They are flexible modules. I think you should
> look at them more closely before you go off on your own.
That's what I'll do. Thanks for the excellent feedback.
--
#!/usr/bin/perl http://domm.zsi.at
for(ref(bless[],just'another'perl'hacker)){s-:+-$"-g&&print$_.$/}
Re: RFC: Template::YetAnother
Posted by Perrin Harkins <pe...@elem.com>.
Thomas Klausner wrote:
> Yes, this is a RFC for Yet Another Templating System. I know that
> there are a lot of those around. But this own might be
> different/interesting (at least I think/hope so...)
>
> I also posted this on perlmonks:
> http://www.perlmonks.org/index.pl?node_id=213300
Ovid on Perlmonks already said some of the things I would have said
about needing a presentation language. For a templating system to be
useful, it has to be able to deal with loops and conditionals. Your
system pushes those into the Perl code, splitting the presentation
control into multiple places. This fails one of my major goals: the
template coders should be able to change the presentation without help
from a Perl coder. What if they decide they don't want to loop through
the links, but rather just print a message saying there are some? What
if they only want to show the first two? What if they want to display a
list with commas between the elements where they didn't use a separator
before? A mature templating system can handle all of these issues
without changing the main Perl module code.
> Because IMO, the main reason for using templates is to seperate code
> from markup.
It sounds to me like you want one of the HTML attribute ones, like Petal
or HTML::Seamstress. What was wrong with those?
> There is one module, CGI::FastTemplate, that does seperate code from
> markup completly. But the way different templates are strung together
> seems rather comlicated to me.
It's not complicated, but it is somewhat confusing the first time you
look at it. I don't find your approach much easier though.
> # generate a new template handler
> my $th=Template::YetAnother->new
> ({
> namespace=>'acme',
> template_dir=>'/projects/acme/templates/',
> });
>
> # build up a data structure
> $data={
> title=>$th->title('this is the title'),
> breadcrumb=>[
> $th->link({url=>'/index.html',text=>'Home'}),
> $th->separator_breadcrumb,
> $th->link({url=>'/acme/index.html',text=>'Acme'}),
> $th->separator_breadcrumb,
> $th->link({url=>'/acme/bleach.html',text=>'Bleach'}),
> ],
> content=>[
> $th->element({heading=>'SYNOPSIS',value=>'blabla'}),
> $th->element({heading=>'DESCRIPTION',value=>'foo bar'}),
> ],
> lastmod=>scalar localtime,
>
> };
>
> # fill template & print
> print $th->fill({data=>$data});
Isn't your fill method just doing a sort of multi-level join here? All
of the data is passed in already, so there is no reason to delay
evaluation of the templates.
More importantly, your use of AUTOLOAD to treat method calls as file
names looks neat, but is not a good approach. It's limiting (all
templates in one directory!) and has potential security issues with
namespace clashes. These are all just the same method call with a
single argument changed, so why not write them that way?
Here's the same thing written with Template Toolkit. You could use
HTML::Template, CGI::FastTemplate, Text::Template, etc. here with minor
changes:
my $th = Template->new({INCLUDE_PATH => '/projects/acme/templates/');
$th->process->('title.tmpl', {title => 'this is the title'});
$th->process->('link.tmpl', {url => '/index.html', text => 'Home'});
$th->process->('separator.tmpl');
$th->process->('link.tmpl', {url => '/index.html', text => 'Home'});
$th->process->('separator.tmpl');
$th->process->('link.tmpl', {url => '/acme/index.html', text => 'Acme'});
$th->process->('separator.tmpl');
... And so on.
Text::Template allows Perl code to be put in the template, and
HTML::Template/TT allow loops and conditionals, but no one is going to
force you to use them. They are flexible modules. I think you should
look at them more closely before you go off on your own.
- Perrin
Re: RFC: Template::YetAnother
Posted by Thomas Klausner <do...@zsi.at>.
Hi!
On Fri, Nov 15, 2002 at 07:05:49PM -0800, Josh Chamas wrote:
> Don't do it. If you want a stripped down version of
> ..
> evolution of these things. The perl template user community is
> already fractured enough,
I expected that canonical answer to all Template Proposals :-)
> better to hop onto a project, hack it to your
> satisfaction ( with the blessing of the maintainers ) to get
> the configs/subclasses you need for your requirements.
I will take a closer look if my ideas could be implemented by
subclassing/extending Template Toolkit or CGI::FastTemplate.
But do you think that the concept sounds reasonable in the first
place?
--
#!/usr/bin/perl http://domm.zsi.at
for(ref(bless[],just'another'perl'hacker)){s-:+-$"-g&&print$_.$/}
Re: RFC: Template::YetAnother
Posted by Josh Chamas <jo...@chamas.com>.
Thomas Klausner wrote:
> Hi!
>
> Yes, this is a RFC for Yet Another Templating System. I know that
> there are a lot of those around. But this own might be
> different/interesting (at least I think/hope so...)
>
> I also posted this on perlmonks:
> http://www.perlmonks.org/index.pl?node_id=213300
>
> So, here it is, in POD format:
>
Don't do it. If you want a stripped down version of
an existing templatting language, then that's great.
Work with the authors of exising frameworks like Template Toolkit
or HTML::Template that *were designed* as pure template frameworks
( as opposed to the app frameworks like Embperl, ASP, AxKit, Mason)
I'm sure you can get the authors to accept patches to disable features
that you don't want, you might even be able to create a subclass
of such a template module that sets these for the end user,
so if they just "use Template:JustVarsPlease", and Template::JustVarsPlease
is a subclass of Template or HTML::Template, then you have
your solution.
Those template solutions that are too much for you got that way
because their users wanted & needed more. That is the natural
evolution of these things. The perl template user community is
already fractured enough, better to hop onto a project, hack it to your
satisfaction ( with the blessing of the maintainers ) to get
the configs/subclasses you need for your requirements.
That's what I would do anyway. :)
Regards,
Josh
________________________________________________________________
Josh Chamas, Founder phone:925-552-0128
Chamas Enterprises Inc. http://www.chamas.com
NodeWorks Link Checking http://www.nodeworks.com
Re: RFC: Template::YetAnother
Posted by Perrin Harkins <pe...@elem.com>.
Thomas Klausner wrote:
> Hi!
>
> On Sat, Nov 16, 2002 at 10:43:44AM +0100, Marcin Kasperski wrote:
>
>
>>One note: while talking about templating systems for generating HTML,
>>it can be inspiring to take a look at the Zope Page Templates (yes, I
>>know, this is the python/zope world, not perl...). They found the nice
>>idea of injecting loops/ifs etc into HTML in the way which does not
>>spoil HTML markup.
>
>
> There is a simmilar Perl implementation of this called HTML_Tree
> http://homepage.mac.com/pauljlucas/software/html_tree/
>
> A module based on HTML_Tree is on CPAN under the name of
> HTML-Seamstress:
> http://search.cpan.org/author/TBONE/HTML-Seamstress-1.17/Seamstress.pm
There is also an implementation that copies the Zope style pretty
closely called Petal:
http://search.cpan.org/author/JHIVER/Petal-0.77/lib/Petal.pm
- Perrin
Re: RFC: Template::YetAnother
Posted by Thomas Klausner <do...@zsi.at>.
Hi!
On Sat, Nov 16, 2002 at 10:43:44AM +0100, Marcin Kasperski wrote:
> One note: while talking about templating systems for generating HTML,
> it can be inspiring to take a look at the Zope Page Templates (yes, I
> know, this is the python/zope world, not perl...). They found the nice
> idea of injecting loops/ifs etc into HTML in the way which does not
> spoil HTML markup.
There is a simmilar Perl implementation of this called HTML_Tree
http://homepage.mac.com/pauljlucas/software/html_tree/
A module based on HTML_Tree is on CPAN under the name of
HTML-Seamstress:
http://search.cpan.org/author/TBONE/HTML-Seamstress-1.17/Seamstress.pm
--
#!/usr/bin/perl http://domm.zsi.at
for(ref(bless[],just'another'perl'hacker)){s-:+-$"-g&&print$_.$/}
Re: RFC: Template::YetAnother
Posted by Marcin Kasperski <Ma...@acn.waw.pl>.
Thomas Klausner <do...@zsi.at> writes:
> Yes, this is a RFC for Yet Another Templating System. I know that
> there are a lot of those around. But this own might be
> different/interesting (at least I think/hope so...)
> (...)
One note: while talking about templating systems for generating HTML,
it can be inspiring to take a look at the Zope Page Templates (yes, I
know, this is the python/zope world, not perl...). They found the nice
idea of injecting loops/ifs etc into HTML in the way which does not
spoil HTML markup.
Their introduction is on
http://www.zope.org/Documentation/Articles/ZPT1
and reference is in
http://www.zope.org/Documentation/Books/ZopeBook/current/AppendixC.stx
Here are some examples (copied from the introduction)
<title tal:content="here/title">Page Title</title>
The URL is <span tal:replace="request/URL">URL</span>.
<table border="1" width="100%">
<tr>
<th>#</th><th>Id</th><th>Meta-Type</th><th>Title</th>
</tr>
<tr tal:repeat="item container/objectValues">
<td tal:content="repeat/item/number">#</td>
<td tal:content="item/id">Id</td>
<td tal:content="item/meta_type">Meta-Type</td>
<td tal:content="item/title">Title</td>
</tr>
</table>
--
( Marcin Kasperski | Osoba jest omegalizacją ewolucji uniwersalnej na )
( http://www.mk.w.pl | określonym odcinku etapowym (Teilhard de Chardin) )
(----------------------------------------------------------------------------)
( Wygeneruj dokumentację: http://www.mk.w.pl/narzedzia/narzedzia_gendoc )