NAME

Text::Template - Perl Mongers talk, Feb 20, 2000


SYNOPSIS

Text::Template is a wonderful module by Mark-Jason Dominus (MJD) for embedding Perl into a text document. This Perl can be evaluated by your program to fill in information at runtime, for a ``personalized form letter'' effect.


Text::Template

There are a number of template modules on CPAN, and I've tried out several of them in the quest for the perfect template processing module. Text::Template, so far, comes the closest to what I'm looking for. It has almost everything I need, and almost nothing extra that I don't need.

Although there are a few extra things that I'd like to have, what is there suffices, most of the time, for the purposes to which I put it.


Using it

Quick information for the impatient:

        use Text::Template;
        $template = new Text::Template ( 
                                        TYPE => 'FILE',
                                        SOURCE => 'template.txt"
                                        );
        $filled = $template->fill_in( 
                                HASH => [ $details ],
                                DELIMITERS => [ '[##', '##]' ]
                                );
        print $filled;

That's not the only way to use it, that's just the way that I use it most of the time. In fact, I use this little incantation in almost every CGI program that I write.

Ah, yes, did I mention that I use it for CGI programming? More about this later, since that's not the main point of this paper.


Philosophy: Why use this?

Programs are written for customers. ``Customer'' has several definitions. Sometimes, you're the customer. Sometimes it is your boss, or your co-workers. And sometimes it's a real fee-paying customer. One of the axioms of customer relations (according to Alan Cooper, User Interface Guru) is that you should never make the customer look stupid. Seems pretty simple, but just about every software package on the market violates it.

Customers (at least, my customers) want to change the way that output looks. Perhaps it's as simple as correcting a typo, or chaging that word to blue, and that one to bold. These folks should not have to know Perl in order to make these changes, which have absolutely nothing to do with Perl. Making a change like that should be simple, and having to edit Perl code to make such a change makes the customer look stupid. They know that it should be simple to make a change like that, but, somehow, it's not. This makes them feel like a moron. That's a Bad Thing.

This is one reason for the separation of code and interface. (Not unlike the separation of Church and State, in some strange way that escapes me at the moment.) Those that are good at programming can stick to the code, and those that are good at interface design can stick to the interface. Naturally, there will have to be some of each in each, in order for them to interact with one another, but this is kept to a minimum.


Example

Here's a cool example, using DBI to get the information. Presumably this is part of some larger program, but you get the idea.

        ...
        $sth = $dbh->prepare("select * from user
                                                where userID = $ID");
        $sth->execute;
        $details = $sth->fetchrow_hashref;
        $template = new Text::Template ( 
                                        TYPE => 'FILE',
                                        SOURCE => 'userdetails.html"
                                        );
        $filled = $template->fill_in( 
                                HASH => [ $details ],
                                DELIMITERS => [ '[##', '##]' ]
                                );
        print "Content-type: text/html\r\n\r\n";
        print $filled;
        ...

Rather than lots of print statements with the various details of the user query, you simply pass all of the information off to Text::Template as a hashref, and it handles it, filling in the information in the template.


What does a template look like?

If you use the code above, a template might look something like:

        <table>
        <tr>
        <th align="right">Name</th>
        <td align="left">[##$fname##] [##$lname##]</td>
        </td>
        <tr>
        <th aligh="right">Address</th>
        <td>[##$address##]<br>[##$city##], [##$state##] [##$zipcode##]</td>
        </tr>
        ...

And so on.


Well, that's rather simplistic ...

Yes, I'm being very simplistic here. And if that was all that it could do, there would not really be any point in using this module. After all, you could just do something like ...

        s/\[##\$(.*?)##\]/$details->{$1}/gs;

and be done with it. Why use a huge module for that? Well, fortunately, it does more than that. The fact is, you can put ANY Perl code into your template, and have it evaluated. The output of that code is then included in the output from your template.

One more note before I move on to that.


Delimiters

For some reason, I've been using [## and ##] as my delimiters in my code. This is just my personal preference, and has absolutely no bearing on what you have to do. You can use any delimiter that strikes your fancy. I just use those because they made sense to me at the time, and now it's far too late to change.

If you don't specify a DELIMITERS parameter when you call the fill_in function, Text::Template assumes that the delimiters will be { and }. That works pretty well for a lot of people in a lot of situations, but it did not work for me, and so I specified something else. One of the reasons that it did not work very well for me was that it totally destroyed JavaScript code.

So, if you like using ( ) or ** ** or !!BEGIN PARSING HERE, feel free to specify those delimiters. It's all the same to Text::Template.


Stupid Text::Template tricks

Any Perl code that you put between delimiters in your template will be executed, and whatever return value it has, will be included in the output. While this might have some unexpected results if you're not careful (you know that a lot of Perl functions return '1' on success, right) this is usually what you want.

You can think of the template at its own name space (I don't think it really is, but you can think of it that way), so any variables set at the beginning of the template will be available to any code chunks later on in the template.

        ... early in your template ...

        { $test1 = 'value'; }

        ... later in your template ...
        
        { print $test1; }

Of course, it would rather violate the philosophy of 'separation of code and interface' to really load the template with code, but the fact that you can if you want to is pretty cool.


$OUT

Rather than having your code chunks full of print statements, use the special variable $OUT to accumulate the output. At the end of a chunk of code, Text::Template will display the value of $OUT as the output.

        { # Begin chunk
        for (1..10)     {
                $OUT .= "$_ ... ";
        }
        # End chunk
        }


What I think is missing

One of the things that I've always wanted in Text::Template is a way to set values ahead of time. For example, something that I do very frequently is generate a HTML table of values. It would be very nice if I could define the format of the table in the template file, rather than in my code, and then use that template-within-a-template to format my output. Something like:

        $format = q~<tr><td>%s</td><td>%s</td><td>%s</td></tr>~;

which I could then use in a printf in my code. Or, better yet, perhaps something like:

        $format = q~<tr><td>$name</td><td>$age</td><td>$shoesize</td></tr>~;

which I could then eval, or whatever, in my code, as I looped through a data set.

However, Text::Template runs through the template just once when it fills it in.

A work-around to this I have considered is to have another template file that contains these sub-templates, but I have not quite figured out how to do that. Email to MJD has, so far, produced no response. I'm going to try to corner him next month at ApacheCon.


What are the alternatives?

There are a number of other template modules on CPAN. Many of them are specifically geared towards CGI programming and/or HTML page generation. That seems, to me, a little silly, since there is nothing particularly specific about CGI programming that warrants that it be treated any differently. But, that's the area where this technique has received the most attention. One unfortunate side-effect of this is that if you are looking for Template modules, there's no obvious place to look, other than http://search.cpan.org/

HTML::Template, Mason, EmbPerl, and ePerl are all CGI-focused Template modules. Then, in addition to Text::Template, which is not CGI-centric, there's also Template::Toolkit, which was an aborted attempt to get all of these Template module authors to cooperate on something. When I talked with the author of EmbPerl about this lack of cooperation, he said that each of the authors felt that they had the Right Way to do things, and so did not want to surrender any of their artistic license to a team project. To listen to them talk, they each want to cooperate, but nobody else will budge.

I suppose, in a way, this is a good thing, since each of the modules has its strengths, and so you just need to find the one that is best for you. I find that Text::Template does the best job for me, and so I stick with it.


What about CGI.pm?

Well, I don't really want to go there, but when I've discussed this on various mailing lists, that's what has been asked. The simple answer to this is that CGI.pm is great for quick, one-shot, simple-purpose CGI programs. However, if you ever intend anyone else to use, or, worse still, maintain your code, do them a favor, and don't use CGI.pm. I spent much of this Saturday trying to customize some code that used CGI.pm. Making a simple modification (make this text green, and that text bold) requires you to paw through hundreds of lines of code to find where that text is generated. It's buried in a Object Oriented call somewhere, but exactly where, it's not clear. In one subroutine, I converted 246 lines of code to 43 lines of code and an HTML template file. I could edit the template file with an ordinary HTML editor (I use HomeSite), and play with the layout of the page, without messing with the Perl code. And, more importantly, so could my non-programmer customer.

Said customer could not (and should not have to) understand:

        password_field(-name=>'password',-size=>30);

but could understand, and modify

        <input type="password" name="password" size="30">

Sure, it's obvious to you and me what that first line means, but someone should not have to learn an entirely new skill-set, or language, in order to do something that they already know how do to. That makes them feel stupid. See earlier point.


Conclusion

There's a lot more that you can do with Text::Template. I've just touched on it, and I don't use everything that it can do. My primary interest, as I've said a number of times, is that the customer be able to tinker with what the output looks like without having to mess with Perl code. They don't know Perl, and, frankly, I don't want them to, because that's why they hire me. Or, more pragmatically, on a programming team, you want to make sure that each team member only has to work on the things that they are good at. Work goes faster that way.

For more information on Text::Template, you should see the documentation, which shows a number of other cool things that you can do with it. Your template does not have to be a file. It can be right there in your code, or can be provided after the __END__ token. And other stuff. See the docs.


See Also

http://moose.qx.net/perldocs/Text/Template.html


Author

Rich Bowen - <rbowen@rcbowen.com>