http://www.perlmonks.org?node_id=156772

Ovid has asked for the wisdom of the Perl Monks concerning the following question:

I am putting together some fairly complicated HTML templates with Template Toolkit, but the many-to-many database relationships do not map well to one-to-many directory structures. As a result, if our designer needs to work on one of the templates, he or she could be hard-pressed to find it. The cleanest solution that occurs to me is to allow the designers to "view source", and see each template delimited by start and end HTML comments that identify the template path:

<!-- START: [% component.name %] --> <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor +="222222"> <tr> <td width="10"><img src="/images/1xshim.gif" width="10" height="1" +></td> <td valign="middle" class="textSubheader" width="100%">Some text</ +td> </tr> </table> <!-- END: [% component.name %] -->

The problem, though, is that I have to hardcode those comments into each template (component.name is a built-in that lists the path and template). I could write a utility script that goes through and automatically inserts those into templates, if they are not found, but it would be cleaner to simply have Template Toolkit just insert that into the HTML for me. Designers might accidentally remove those comments, or forget to add them to new templates, etc.

My first thought was to use pre and post process configuration options.

my $template = Template->new({ PRE_PROCESS => 'start_tag.tmpl', POST_PROCESS => 'end_tag.tmpl', };

This did not work because I have templates that I INCLUDE into the main template. A careful reading of the docs makes it clear that this is not a feasible solution.

These values may be set to contain the name(s) of template files (relative to INCLUDE_PATH) which should be processed immediately before and/or after each template. These do not get added to templates processed into a document via directives such as INCLUDE, PROCESS, WRAPPER etc.

I've been reading through the docs and can't seem to find anything that seems suitable. My only other thought was to find the appropriate module to subclass and override the INCLUDE directive, but I'd prefer to write the aforementioned utility script than do this. Can anyone present a clean solution to this problem?

Cheers,
Ovid

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
Re: Dynamically altering static TT templates
by simon.proctor (Vicar) on Apr 04, 2002 at 22:26 UTC
    One way would to be to use the Decorator pattern and write a wrapper object around the Template toolkit object that appends or prepends any information you need. You can then add additional configuration information specific to this additional object to control it much more closely.

    This decorator object can of course contain its own instance of a TT parser so you can use the same syntax where you wish. The advantage to this is that the output it produces is applied to either the top or the bottom of the template regardless of whether the designers remove your comment syntax.

    Of course this only works for the whole template and you want it for each. Taking a look at the docs for the Template toolkit it looks like, to me anyway, that the class you should consider is Template::Context, specifically the include and process functions. One method to play with here is to write your own context object and override those functions so that you may add the bits and bobs you want for your template vars and then call the method from the parent class to do the actual parsing.

    Though the effort involved in getting the parser to call your context object instead of the one supplied may not be worth it. Of course you could just replace these functions by hacking into the namespace but that would be just plain nasty :)

    Update

    I had a quick play with context.pm and I managed to get it to return the processed filename by changing the last line in the process() routine to:
    return $output . $template->[0]{'name'};
    This works because the $template variable passed to process is a document object. We have to mess about with the anonymous array because the routine automatically puts the object into one further up in the code.

    I haven't played with include() but it looks to operate in the same way. Its trivial then to use HTML comments to hide this additional output.

    Warning

    I do not recommend trying to repeat what I did unless you know exactly what you are doing. At best you'll have to reinstall the module, at worst you won't know you need to reinstall it till you do that demo for the important client you have been preparing for all week and everything dies :).
Re: Dynamically altering static TT templates
by perrin (Chancellor) on Apr 04, 2002 at 21:25 UTC
    That would be a really nice debugging option, to have TT insert the name of each template in a comment when compiling it. Probably not hard, but I don't know where to add it without openeing up the code. I'd suggest it on the TT list and see if someone can quickly explain how to do it. I'm tempted to add it myself, but I know I won't be able to get to it soon.
      More generally, it would be good to provide optional pre-processing and post-processing callback hooks.
         MeowChow                                   
                     s aamecha.s a..a\u$&owag.print
      Would adding the following to each template file cover it?:
      open(TEMPLATE FILEHANDLE,$0); print "# ",$0;
      $0 contains the name of the file being read. I haven't played with TT (or templates) yet so this is just a hopeful guess.
      --
      @a = ("a".."z"," ","-","\n");
      @b = (12,0,17,10,24,12,14,14,13,26,8,18,26,0,26,
      22,0,13,13,0,27,1,4,26,15,4,17,11,26,7,0,2,10,4,17,28);
      print map {$a$_} @b;
Re: Dynamically altering static TT templates
by extremely (Priest) on Apr 04, 2002 at 22:38 UTC
    I'm pretty sure you are going to be stuck overriding Template::Context::include();

    Tho maybe a PREINCLUDE and POSTINCLUDE options would be nice... hmmm...

    --
    $you = new YOU;
    honk() if $you->love(perl)

Re: Dynamically altering static TT templates
by jerrygarciuh (Curate) on Apr 05, 2002 at 04:54 UTC
    Ovid,
    Why TT over the more popular HTML::Template? I am curious because I have recently waded into the latter and want to use my learning time to my best advantage. What recommends TT to you?
    TIA
    jg
    _____________________________________________________
    Think a race on a horse on a ball with a fish! TG

      Hi

      I've worked quite a bit with both, and I think they're both excellent modules. However, they're quite different in style, and I think they're suited for different kinds of work. The main differences I can think of are:

        Template Toolkit HTML::Template
      Template Syntax: More complicated, more "Perlish" control structures (keys, values...), and less immmediately HTML-ish (uses custom [% %] notation for template directives, although this can be changed). Simpler, and more HTML-ish at first sight (uses angle brackets <> and attributes).
      Template Data Can work with hashrefs, objects using dot notation, and can pass the values back and forth as arguments. The final value in a dot sequence (foo.bar.thisone) could actually be a method call, or a hash key. Mainly intended to work with key-value pairs and lists of hashrefs. The VAR values are almost always (something like) hash keys.
      Extensibility Easy to extend through the plugins mechanism, and exposes underlying function calls more obviously I wrote a substantial subclass of HTML::Template once ... it wasn't a nice experience. HTML::Template ties the mechanics of a template (reading it, parsing it, preparing it, replacing values) very closely to the implementation of specific template directives (LOOP, VAR, IF) and so on. The parser is a long regex which is trained to look specifically for the sequences like L-O-O-P V-A-R etc, so if you want to add a new tag, you have to rewrite the parser.

      As I say, it's not a criticism of either. One of my clients uses an implementation of HTML::Template extensively. They edit the templates through the browser, the templates are stored in Oracle, and they love it, because all their (cheap) capable HTML-ers find it a doddle to work with. However, the pain factor, for me, of customising HTML::Template was pretty high.

      Template Toolkit's syntax is a bit more scary for people used to vanilla HTML, and the overall flavour of using it is a lot more Perl-ish. But as it exposes more mechanics, it's much easier to customise it to interact with all kinds of different objects that might be relevant to your web application. This might make it a better choice for larger projects.

      Horses for courses, I guess

      //=\\
        Thank you so much for that comparison! Really helpful.
        jg
        _____________________________________________________
        Think a race on a horse on a ball with a fish! TG
        Wow, great link! There are enough threads on templating packages I should write a consolidated template resource reference node!
        Thanks!
        jg
        _____________________________________________________
        Think a race on a horse on a ball with a fish! TG

      When I first had to choose a templating scheme for our company, I investigated several options. HTML::Template and Template Toolkit were the two most likely candidates. Even though HTML::Template could have satisfied our needs at the time, I was concerned that, with some of the projects we were planning, that it might become a bottleneck. On the other hand, if we took the trouble to learn Template Toolkit up front, we would have a vastly more powerful templating system available, albeit with potential that we were not tapping.

      flash forward almost two years

      Many people use templates by creating a program, assembling the data, then calling the template and passing it the data. For my current project, I need to create documents out of multiple templates all tied together, some with dynamic content from a variety of different sources. As a result, I am inverting the process and having templates call programs (plugins). This allows me a much richer templating environment. I don't think I could have done that very easily with HTML::Template.

      If your documents are not likely to be terribly complicated, HTML::Template is a fine tool.

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        Thanks Ovid! This thread has been most helpful!
        jg
        _____________________________________________________
        Think a race on a horse on a ball with a fish! TG
      You might also look at Apache mod-perl's template roundup. It does a good job of non-denominationally comparing the template systems.

      --
      $you = new YOU;
      honk() if $you->love(perl)

        Thank you, that was an extremely good link!
        jg
        _____________________________________________________
        Think a race on a horse on a ball with a fish! TG