Click here to get back home

Recall::Template - new module proposal

 HomeNewsGroups | Search | About
 comp.lang.perl.modules    Post an article   get this group's latest topics as an RSS feed add this group's latest topics to your My MSN content add this group's latest topics to your My Yahoo content
Subject Author Date
Recall::Template - new module proposal arbingersys@gmail.com 03-14-2007
Posted by arbingersys@gmail.com on March 14, 2007, 3:21 pm
Please log in for more thread options


Hi, I've created a module template system that works, from what I can
tell, in a novel manner. I'd love to hear any comments you might have.

Recall::Template works using what I call a "reverse callback''
approach. A "callback'' template system (i.e. Mason, Apache::ASP)
generally includes template markup and code in the same file. The
template "calls'' out to the code where needed. Recall::Template works
in reverse. Rather than inserting code inside the template, the
template remains separate, but broken into sections. The sections are
then called from within the code at the appropriate times.

A template section is merely a file on disk (or a "marked'' section in
a single file). For instance, a section called 'prodrow' would
actually be 'prodrow.html' in a template directory, and might look
like

<tr>
<td>TEMPLATE_var_product</td>
<td>TEMPLATE_var_description</td>
<td>TEMPLATE_var_price</td>
</tr>

If called in every iteration of a loop, you could build a set of
product data in HTML dynamically.

The Recall::Template::render() method is used to "call'' out to the
template sections. You create a hash of name/value pairs that
represent the template tags you wish to replace, and pass it along
with the template section, i.e.

$h = 'bunny slippers';
$rt->render('prodrow', %h);

render() returns the template with the template tags replaced by the
key/value pairs in %h.

For more details, you can go to

http://www.arbingersys.com/boot/recall-template/article.html

You can download a demo from there that contains the module code, if
you'd like to take a closer look.

Thanks, James


Posted by Uri Guttman on March 14, 2007, 3:50 pm
Please log in for more thread options



ac> Recall::Template works using what I call a "reverse callback''
ac> approach. A "callback'' template system (i.e. Mason, Apache::ASP)
ac> generally includes template markup and code in the same file. The
ac> template "calls'' out to the code where needed. Recall::Template works
ac> in reverse. Rather than inserting code inside the template, the
ac> template remains separate, but broken into sections. The sections are
ac> then called from within the code at the appropriate times.

ac> A template section is merely a file on disk (or a "marked'' section in
ac> a single file). For instance, a section called 'prodrow' would
ac> actually be 'prodrow.html' in a template directory, and might look
ac> like

ac> <tr>
ac> <td>TEMPLATE_var_product</td>
ac> <td>TEMPLATE_var_description</td>
ac> <td>TEMPLATE_var_price</td>
ac> </tr>

ac> If called in every iteration of a loop, you could build a set of
ac> product data in HTML dynamically.

ac> The Recall::Template::render() method is used to "call'' out to the
ac> template sections. You create a hash of name/value pairs that
ac> represent the template tags you wish to replace, and pass it along
ac> with the template section, i.e.

this sounds very similar to Template::Simple which is up on cpan. it
only has 4 markups and can do all the things you want in your module.

and you don't even need any code to handle loops as that is driven by
the data. so it is even simpler to use than your module for that.


ac> $h = 'bunny slippers';
ac> $rt->render('prodrow', %h);

it even has the same basic api.

ac> render() returns the template with the template tags replaced by the
ac> key/value pairs in %h.

ac> For more details, you can go to

ac> http://www.arbingersys.com/boot/recall-template/article.html

i don't see nested sections, include files and various options such as
markup delimiters. again, check out Template::Simple and you may find it
is all you need and you don't need to add another templater to cpan. :)

uri

--
Uri Guttman ------ uri@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org

Posted by arbingersys@gmail.com on March 14, 2007, 5:29 pm
Please log in for more thread options


> this sounds very similar to Template::Simple which is up on cpan. it
> only has 4 markups and can do all the things you want in your module.

Well, at least the render() methods seem similar.

How about conditionals? For instance, because logic only exists in the
code file with Recall::Template, if during the loop you wanted to hide
the price of items over a certain amount (say $1000) with a "Please
call" message, it's quite simple:

for (@prods) {
my @pa = split(/,/, $_);
if ($pa[0] > 1000) {
$h = 'Please call';
}
else
$h = $pa[0];

...
$rt->render('prodrow', %h);
}

I realize that with Template::Simple would have to do this when you
construct the data, but that seems to imply generating the data in a
loop to handle the conditional, then passing this to the
Template::Simple::render() method, which would ultimately iterate over
it again against the template. Perhaps I'm wrong.


> and you don't even need any code to handle loops as that is driven by
> the data. so it is even simpler to use than your module for that.

Well, I guess that all depends on whether you consider creating a loop
a more difficult programming task than nesting hashes and arrays (and
arrays of hashes). :)

Since you brought it up, however, there is no reason that
Recall::Template, being an object, couldn't be extended to be passed a
complex data structure and iterate over it automatically.

I also anticipate that someone might even want to store the template
sections in a database, and call them from there. Objects and
extension, it's a good thing they go together so well.


> i don't see nested sections,

I hope I've been clear that the idea here is to keep all logic in the
code. If you have nested sections, i.e.

GROUP 1
DETAIL1 DETAIL2
GROUP 2
DETAIL1 DETAIL2
...
GROUP N
DETAIL1 DETAIL2

this is still done via a programming construct, perhaps as a nested
loop:

for (@groups) {

$rt->render('group', %group_data);

for(@details) {
$rt->render('details', %detail_data);
}
}

> include files and various options such as
> markup delimiters.

I'm not sure what you mean by "markup delimiters", but as far as
include files go, that's really all Recall::Template does -- include
template files at appropriate times in the code. As for including
additional logic (like modules), again, I think this belongs in the
arena of the programming language, rather than anywhere in the
template.

I appreciate your comments. At this point I still think
Recall::Template has enough to offer on its own to be a module, though.


Posted by Uri Guttman on March 14, 2007, 9:29 pm
Please log in for more thread options



>> this sounds very similar to Template::Simple which is up on cpan. it
>> only has 4 markups and can do all the things you want in your module.

ac> Well, at least the render() methods seem similar.

ac> How about conditionals? For instance, because logic only exists in the
ac> code file with Recall::Template, if during the loop you wanted to hide
ac> the price of items over a certain amount (say $1000) with a "Please
ac> call" message, it's quite simple:

ac> for (@prods) {
ac> my @pa = split(/,/, $_);
ac> if ($pa[0] > 1000) {
ac> $h = 'Please call';
ac> }
ac> else
ac> $h = $pa[0];

ac> ...
ac> $rt->render('prodrow', %h);
ac> }

ac> I realize that with Template::Simple would have to do this when you
ac> construct the data, but that seems to imply generating the data in a
ac> loop to handle the conditional, then passing this to the
ac> Template::Simple::render() method, which would ultimately iterate over
ac> it again against the template. Perhaps I'm wrong.

that is the general idea. but you are doing the same loop and
conditional but in a different place. doing it at one time to build a
data tree seems cleaner to me. and you can easily break up the tree
building into subs similarly to how you do it. conditionals are meant to
be in code and we agree on that.

>> and you don't even need any code to handle loops as that is driven by
>> the data. so it is even simpler to use than your module for that.

ac> Well, I guess that all depends on whether you consider creating a loop
ac> a more difficult programming task than nesting hashes and arrays (and
ac> arrays of hashes). :)

well, they have to be created somewhere. most sites have plenty of
nesting of structures. and i recently created CMS::Simple (not published
yet) which uses template::simple and makes it easier to share data and
templates across many pages. it also has content filtering (for links,
markup, escaping, etc.)

ac> Since you brought it up, however, there is no reason that
ac> Recall::Template, being an object, couldn't be extended to be passed a
ac> complex data structure and iterate over it automatically.

sure, steal my ideas! i will sic the riaa on you! :)

ac> I also anticipate that someone might even want to store the template
ac> sections in a database, and call them from there. Objects and
ac> extension, it's a good thing they go together so well.

that can be done with an include mechanism that searches a db or a dir
tree.


>> i don't see nested sections,

ac> I hope I've been clear that the idea here is to keep all logic in the
ac> code. If you have nested sections, i.e.

ac> GROUP 1
ac> DETAIL1 DETAIL2
ac> GROUP 2
ac> DETAIL1 DETAIL2
ac> ...
ac> GROUP N
ac> DETAIL1 DETAIL2

ac> this is still done via a programming construct, perhaps as a nested
ac> loop:

ac> for (@groups) {

ac> $rt->render('group', %group_data);

where is %group_data being set? what is in $_ in the loop? could be just
quickie code and the hash is in the array of hashes.

>> include files and various options such as
>> markup delimiters.

ac> I'm not sure what you mean by "markup delimiters", but as far as
ac> include files go, that's really all Recall::Template does -- include
ac> template files at appropriate times in the code. As for including
ac> additional logic (like modules), again, I think this belongs in the
ac> arena of the programming language, rather than anywhere in the
ac> template.

when you render a value you can't just replace any occurance of the name
token because it might be in the real text. so most/all templaters use a
delimiter to demark which are template tokens and
markup. template::simple does [%NAME%] which is a common style. but the
[% and %] can be changed with options to the constructor.

ac> I appreciate your comments. At this point I still think
ac> Recall::Template has enough to offer on its own to be a module, though.

to each their own. i did mine after years of quickie hacks which grew
into a neat 37 line unpublished module i gave lightning talks about this
past summer at yapc and oscon. someone from england liked it so much he
paid me (very little :) to clean it up for cpan (pod, options, tests,
etc.). the rule is everyone builds a templater in their career. i have
been noodling with them for decades until i came up with the style that
suited my needs and what i see as general templating needs without the
bloat of the large templaters.

uri

--
Uri Guttman ------ uri@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org

Posted by arbingersys@gmail.com on March 15, 2007, 11:45 am
Please log in for more thread options


> that is the general idea. but you are doing the same loop and
> conditional but in a different place. doing it at one time to build a
> data tree seems cleaner to me. and you can easily break up the tree
> building into subs similarly to how you do it. conditionals are meant to
> be in code and we agree on that.

But, doesn't the data get iterated over twice, then? Once when you
build the data tree, and again when it gets rendered against the
template to build the rows between [%START%] and [%END%]? In my loop,
when you call render() the only thing happening is a s/// against the
template, then output. There is no further looping. So there is only
one iteration over the data.


> well, they have to be created somewhere. most sites have plenty of
> nesting of structures. and i recently created CMS::Simple (not published
> yet) which uses template::simple and makes it easier to share data and
> templates across many pages. it also has content filtering (for links,
> markup, escaping, etc.)

Yeah, I suppose that's true. I just know that in my own programming
odyssey, I knew what a loop was long before I understood (or even
wanted to know) what a array of a hash of an array was. I want
Recall::Template to behave as simply, or as complexly as the
programmer is ready for.


> sure, steal my ideas! i will sic the riaa on you! :)

Not planning on any infringement, so you don't have to worry.
Template::Simple does this well enough already.

I think Template::Simple is an interesting module with definite
usefulness. However, I think the motives behind it and
Recall::Template are different. Template::Simple seems driven by
building elegant data structures to be converted into templates with a
single call. Recall::Template is designed to keep everything but the
simplest logic (variables) out of the templates. This is why the
templates are broken into sections. I don't even want the templates to
be able to include other templates, or tell the code where to start
and end iterative output. I want everything to be decided by the code
-- e.g. which templates to include or exclude, in what order, and at
what time, what formatting to use for row output, etc.


> ac> for (@groups) {
>
> ac> $rt->render('group', %group_data);
>
> where is %group_data being set? what is in $_ in the loop? could be just
> quickie code and the hash is in the array of hashes.

Well, I obviously excluded a lot of details. I was just focusing on
the fact that nesting would work as it does normally in code, either
with nested loops, or recursion.

Let's say you query a table in SQL for

select distinct category from products order by category

and you store 'category' in @groups. Then, you will hit the database
(or maybe an in-memory data structure) again for the products in that
group during the loop, e.g.

for (@groups) {
        my %h;
$h = $_;
print $rt->render('groups', %h);
my @details = get_details($_); # Hit DB for products/details in
category
for (@details) {
print $rt->render('details', %);
}
}


If the 'groups' template section looked like

<tr><td colspan="3"><b>[%group%]</b></td></tr>

and the 'details' template section looked like

<tr>
<td>[%product%]</td>
<td>[%inventory%]</td>
<td>[%price%]</td>
</tr>

you've just done simple nested output. You could even add a variable
to tally total product inventory at the end, in a template section
named 'tally', for instance.


> when you render a value you can't just replace any occurance of the name
> token because it might be in the real text. so most/all templaters use a
> delimiter to demark which are template tokens and
> markup. template::simple does [%NAME%] which is a common style. but the
> [% and %] can be changed with options to the constructor.

Gotcha. This is left entirely to the discretion of the programmer. As
you can see in my [reworking of the] example above, you can use
whatever tag pattern you want. Recall::Template doesn't care, and
neither do I.


> to each their own. i did mine after years of quickie hacks which grew
> into a neat 37 line unpublished module i gave lightning talks about this
> past summer at yapc and oscon. someone from england liked it so much he
> paid me (very little :) to clean it up for cpan (pod, options, tests,
> etc.). the rule is everyone builds a templater in their career.

I guess this is mine. :)

>i have been noodling with them for decades until i came up with the style that
> suited my needs and what i see as general templating needs without the
> bloat of the large templaters.

Your comments have been helpful.


Similar ThreadsPosted
Namespace for new module: HTML::Template::HTX? May 13, 2005, 7:17 pm
new module proposal March 29, 2008, 2:02 pm
RFC: Yahoo::DrivingDirections -- new module proposal September 15, 2004, 9:25 am
proposal for new module -- Math::TriangularNumbers February 21, 2005, 10:19 pm
Module Proposal: Calendar::CelticTree January 27, 2007, 9:20 am
[RFC] Apache::Session::Memcached - new module proposal September 14, 2004, 3:54 pm
Scary module base namespace proposal: Metaweb August 16, 2007, 5:51 pm
[RFC] Data::Endian (proposal for module to read/write big-endian floats/doubles) July 3, 2007, 5:26 pm
HTML::Template March 5, 2008, 2:40 pm
HTML::Template and __ODD__ July 22, 2005, 7:48 am

Our other projects:

Art Dolls, Fairies and Mermaids - Sunnyfaces.net

Roy's Linux, Programming and Search Engines messages

1-Script XML SitemapXML Sitemap