I'll be honest. I've never really been a big fan of the template systems available to Perl (although I can't think of another language that comes even close to providing the options and maturity that Perl offers). Mason reminds me too much of my days writing ASP, with HTML and code strewn together, and it's always bothered me that TT2 and HTML::Template, although much cleaner, contain logic.

So I decided there really was More Than One Way To Do Things, and wrote a module called Template::Recall (available on CPAN). My idea was that you could get truer SOC if you kept the templates physically separate from the code and broke them into "callable" sections, because all you'd ever have to do to process a template was substitution.

For example, if you had the following three sections (header,row,footer),

[=== header ===] <table> [=== row ===] <tr><td>['product']</td><td>['quantity']</td><td>$['price']</td></tr> [=== footer ===] </table>
a Template::Recall object ($tr) would render the row, on each iteration, something like
print $tr->render( 'row', { product=>$prod, quantity=>$quant, price=>$price } );

Consider that with HTML::Template you would render the product data to an array containing hashes, and then pass it to a <TMPL_LOOP> "logic" construct in the template. (To be iterated over again for output, I might add.)

A more detailed introduction to Template::Recall is at the following link, and the nuances may be made more apparent there.

http://blog.arbingersys.com/articles/TemplateRecall/article.html

Recently, I came across this interesting post by Fred Moyer, called "Down with templating languages".

http://use.perl.org/~Phred/journal/33451

He makes the following statement:

So here I present to you Moyer's Eleventh Rule of Templating Languages. "Any sufficiently complicated templating language contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Perl"

This is referring to how logic creeps in (Mason) or is built-in (TT2, HTML::Template) to the templates, making them a "language" all their own.

After considering, I think that Template::Recall is, by design, "11th law"-proof, because it only allows substitution. Perhaps it just seems that way because it is not (yet) a "sufficiently complicated" template language. I suspect this is not the case, but I'd like to hear the Monks' perspectives.

I consciously wanted all logic (presentation or otherwise) to be forced into the code. If you need to provide nested output, it would be done like

for (@groups) { # ... manipulate data ... $tr->render('group', \%group_data); for(@details) { # ... manipulate ... $tr->render('details', \%detail_data); } }

Includes would be done using multiple Template::Recall objects, e.g.

if ($department eq 'Technology') { print $tr->render( 'include_header', { header => $tr2->render('tech_dept') } ); } else { print $tr->render( 'include_header', { header => $tr2->render('default') } ); }

And as you can see, conditionals are also where, I feel, all logic should be: in the code.

So that's my perspective. I'm interested in hearing what the Monks have to say about it.

P.S. I don't think you can really know how an idea will be in implementation, until, well, you implement it. I've used Template::Recall with CGI::Application to build Sylbi, a true MVC application, and the templates have worked out pretty much how I expected. To me (naturally) the code feels very "clean".

http://sylbi.arbingersys.com

The msite/Sylbi/*.pm files in the Sylbi code can be perused for a taste of Template::Recall in use rendering not only HTML output, but also Perl code for eval.

Replies are listed 'Best First'.
Re: Template modules, logic, and SOC
by Joost (Canon) on Jan 23, 2008 at 19:21 UTC
    So here I present to you Moyer's Eleventh Rule of Templating Languages. "Any sufficiently complicated templating language contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Perl"
    Very true. Which is why I prefer to put plain perl/ruby/whatever code in the templates ala PHP/JSP over, well, any template system I've used.

    That's not to say that template systems are the best way to create dynamic apps. I've been messing with Common Lisp + cl-who which works more or less like CGI's HTML generation modules, but with Lisp's syntax. So far it's a joy to use: you can get as detailed as possible and the code is a both smaller and easier to read than the equivalent HTML and you get all of Lisp's power (including macros) in the bargain.

    In the end, I'm pretty sure the "separate code from presentation" guys have it all wrong. Just take a look at the enormous amount of code that gets generated when you want to use JSP's taglibs, for instance.

    You may want to separate the view from the lower level / model code, but there's no good reason I can see to even try to "keep the code out of the view".

      ...there's no good reason I can see to even try to "keep the code out of the view".

      I think the usual reason is, "so they can be worked on separately." This is especially nice if you have dedicated designers doing HTML and CSS distinct from the people who work on Perl and SQL and JavaScript (oh my), but it's also nice for an individual who wants to be able to mutate things independently.

        Well, if you have an Object-Relational system like DBIx::Class, you should/will usually put all (or at least most) of the SQL needed in the model classes anyway. I very much prefer to make the model easy enough to use so that I can use it directly in the view.

        I have had doubts about the separation between front-end and back-end programmers for a long time. Especially for applications. JSP/PHP like templating works OK for things like CMS templates (provided you the model API is stable enough over updates) but they get seriously annoying when you're writing reusable widgets or heavily interactive applications.

        Anyway trying to keep a template system flexible enough to actually work, and still rigid enough that you can get any inexperienced HTML guy mess with it without potential consequences is futile. There will never be such a system. In the end the programmers will take your straight-forward page-by-page design and cut it up and break it apart anyway, just to get consistency.

      I should mention how I came up with the name Template::Recall for the module. Perrin Harkins dubbed Mason (PHP/JSP fit this bill) styled template systems as "callback" and TT2, HTML::Template systems as "pipeline".

      Template::Recall really works like the "callback" model, except in reverse. Perl isn't inserted between sections of the code and "called back" to by the template; instead, the template is (effectively) inserted between blocks of Perl code, and it is "called back" to. This is why it only requires substitution, and no logic.

        Sorry, this is just another pipeline module in my opinion. Callback means that the template is in charge of the program flow. In your case, the perl code calls the template and passes in data, thus pipeline.

        Frankly, there's nothing new under the sun with templating. What you've done is pretty much identical to several modules that have been on CPAN for years, like CGI::FastTemplate. In fact, there's no reason you can't use HTML::Template, Text::Template, TT2, etc. in the way you're showing here.

        I think you'll find that substitutions are really not enough. You at least need conditionals, because some things are too small to make a whole separate template and put the conditional in the perl code. And loops make for much more readable HTML code, which is one of the major reasons to use a template. And whitespace control is important. And formatting all of your numbers and dates in perl before you call the template gets ugly when you start needing the same data in multiple formats. And putting all this into your perl code means any significant HTML change has to be done by a perl programmer, which is fine for some dev teams and not for others.

        My advice is to get over your idea that the view shouldn't contain logic. It's supposed to contain logic -- logic about how to display the data. It may sometimes be convenient to write the view logic in perl, and sometimes in a view-specific shorthand like TT2.

        Don't get me wrong, I kind of like the system you described, for a templating system :-).

        One of the problems I can see, though, is that for some kinds of output you'll either end up writing "one-off" callbacks, which means you'll now have highly integrated code and template fragments that you'll need to keep in sync spread over multiple files.

        In those cases, you may be better off either writing a function that just returns the complete HTML fragment, or putting the formatting details in code in the template directly, just to make it clear what's going on.