Over the last weekend, I finally found some time to finish my conversion from HTML::Template to Template Toolkit, as was suggested by more than a few people back in September when I asked about generating dynamically-static documents. It took that long partly because this is a volunteer position, and work has been particularly crazy, and partly because it took that long for me to figure out the Template Toolkit way of doing things.
So I thought I'd share my perspective on this conversion process, what I think I gained, and what I think I lost. My project wasn't really involved, thankfully, although I did find that DBD::CSV had a new quirk since I last created these documents via HTML::Template.
I started with some HTML templates, CGI::Application, and a home-grown framework that ran a CGI application through each runmode, saving each to a separate HTML file. It was the loss of this last piece in switching computers that caused my query 6 months ago - to see if there was a better way. For the most part, Template Toolkit's ttree was that better way.
One of the first problems I faced, which stalled me for nearly 6 months, was my navigation bar. It is a mostly-common menu system that all my pages share. Yet, it is just a tiny bit different on each page. For starters, depending on which page is being shown, one of the entries in the navigation bar would have a class of "active" so that, via CSS, it would be shown differently (e.g., bold and a different background colour). Also, if a certain page was shown, it would "open" the navigation. e.g., if the current page was "Topic 3", and that topic had 2 sub pages, you would see "Topic 3a" and "Topic 3b" in the navigation bar. But if the current page was "Topic 2", you wouldn't see either 3a or 3b. Of course, if the current page is 3a or 3b, then you would also see both. Figuring out how to do this in TT2 stumped me. I had something like this:
But I couldn't figure out how to modify that to add extra items based on the current page, such as signifying which page was current, or opening and closing sub pages (not all entries would open and close - some would always remain opened). As mentioned, I gave up. I moved the data structure into a Template::Plugin-derived object, and when I would USE it, I would pass in the page name, and let pure-perl massage the object into what I needed based on the current page.[% SET navbar = [ { title = 'Home', url = 'index.html', }, { title = 'Topic 1', url = 'topic1.html', sub_pages = [ { title = 'Topic 1a', url = 'topic1a.html', }, ] }, ] %]
This is not significantly different than what I did with HTML::Template, however. I had an object encapsulating this whole concept. I didn't fully like it there, still don't, but that's not the fault of HTML::Template or Template toolkit. I just don't like seperating information between two places. (If someone tells me how, I may go back to having this in a template because at least it would be physically closer to the templates it is referring to.)
Once I started down this road, the rest became much easier. I created another plugin which had all my DBD-reading and massaging of data. This was pretty much a rip of the code I had for CGI::Application, and plopped right into the plugin. All I did was remove the calls to HTML::Template, and just return the data I was previously sending to HTML::Template via the param flag. However, one small change was that in HTML::Template-land, I found that if I wanted some dissimilar data, I had to generate all of that and put it in a single hash. In TT2-land, it seemed easier to seperate out each into their own variables or methods. So I ended up with a lot more functions in the TT plugin than I had before. At that point, I added Memoize to the mix, and just memoize'd any functions that were called multiple times (since the output was always the same for everything but the navigation bar). If it took any more effort than that, I'd call it premature optimisation. As it was, it didn't cost me any effort, so I figured the trade-off was worth it even for what may be no gain.
Converting the perl code was probably more work than converting the templates, however. The templates were mostly easy - although I had some nested loops that messed me up where I didn't have the [% END %]'s nested properly:
This is the correct way. The wrong way had the /div tags in the wrong place<div class="navbar-level1"> [% FOREACH n1 = NavBar.navbar %] [% PROCESS navbarentry nav = n1 %] [% IF n1.sub_level %] <div class="navbar-level2"> [% FOREACH n2 = n1.sub_level %] [% PROCESS navbarentry nav = n2 %] ... [% END %] </div> [% END %] [% END %] </div>
I found a simple regular expression helped with the majority of the template conversion: s/\<tmpl_var name="([^"]+)"\>/[% $1 %]/g. That's not quite generic because H::T allows you to omit the quotes, or even the name= identifier. However, I never did that, so this worked for me. Converting the tmpl_if's and tmpl_loop's, however, I did completely by hand. Partly because there were fewer of them, partly because I wanted to ensure I had everything lined up properly.
During this, I found that TT didn't like constructs such as:
(There were actually a lot more than that on the line, but I'm leaving it at that to keep from having a too-long line.) The problem seemed to be having more than one "END" on a single line. H::T didn't have a problem with that, which is good, because anything outside the <tmpl_*>'s was literal. If I didn't want an end-of-line, I had to keep everything on one line. With TT2, I could use the "-" modifier on the opening or closing tags, but what I found is that it's much harder to visualise this way. I still have extra blank lines I haven't figured out how to rid myself of, which wasn't an issue with H::T.<a[% IF url %] href="[% url %]"[% END %][% IF active %] class="activ +e"[% END %]>
Testing a single template via tpage was only moderately painful, but it was definitely a far cry from doing the same thing before. So that was a definite plus. Later on, I switched to using ttree, and my only real complaint thus far is the fact that the .ttreerc defaults to one's home directory unless overridden with an environment variable, instead of a command line parameter. Relatively minor, but I still wrapped that in a shell script so I wouldn't be able to forget. I figure that if I do this for this project, I may do it again for another project, and I don't want to create a new user for each project.
The real benefit, of course, is that I will have an easier time sending this whole thing on to another group who wants to steal our look, feel, and production methods. Whereas before I had to tell them that they needed perl experience and some home-grown stuff to run, now they have a chance to know ttree without me explaining it to them. In other words, if I lose it again, it'll be easier to rebuild ;-)
Key points:
All in all, I'm mostly happy with the conversion. It seems a bit easier to handle overall by removing CGI::Application from the mix, and gave me an excuse to get my hands wet with a technology that two-thirds of the monks seem to rave about ;-)
Update: I remembered what my nested problem was, and fixed a typo.
Update2: I'm trying to replicate my multiple-ENDs problem and failing miserably at it. I must have been doing something wrong. Although my conclusion must have been wrong, I will state that my observations were correct: I had a line like that which wouldn't come out, when I split it up it started to work. Since then, I've fixed a number of other seemingly minor issues with the output in getting it to do what I wanted, and now I put it all back on a single line, and it works. I don't know what it was that made it not work. Now I believe, however, that if TT had different end-tags for IF, FOREACH, etc., that it would have detected my problem and told me I was being an idiot for incorrect nesting or something. ;-)
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Thoughts on converting from HTML::Template to Template Toolkit
by brian_d_foy (Abbot) on Mar 22, 2006 at 17:04 UTC | |
by Tanktalus (Canon) on Mar 22, 2006 at 19:51 UTC | |
by brian_d_foy (Abbot) on Mar 22, 2006 at 20:11 UTC | |
|
Re: Thoughts on converting from HTML::Template to Template Toolkit
by merlyn (Sage) on Mar 23, 2006 at 00:00 UTC | |
|
Re: Thoughts on converting from HTML::Template to Template Toolkit
by idsfa (Vicar) on Mar 22, 2006 at 23:29 UTC | |
|
Re: Thoughts on converting from HTML::Template to Template Toolkit
by holli (Abbot) on Mar 22, 2006 at 19:28 UTC | |
by Tanktalus (Canon) on Mar 22, 2006 at 20:01 UTC | |
|
Re: Thoughts on converting from HTML::Template to Template Toolkit
by bsb (Priest) on Mar 28, 2006 at 08:21 UTC |