Embperl: Modern Templates

Mr. Lerner introduces us to a template system for Perl: what it is, how it works and how to use it.
Keeping Variables' Values

As you can see, variable assignments are kept across square brackets, meaning that you can assign a variable in one block and refer to it later. Variables are global by default, but you can use Perl's “my” convention to create temporary variables, which go out of scope at the end of the block.

One of the nice things about mod_perl is that it compiles programs once, caching them for future invocations. Not only do you save the overhead of forking a new process, but the program runs much faster since it only needs to be interpreted. In many cases, you want variable values to remain intact across several invocations of a program. Such persistence allows you to log into a database server only once, keeping a connection open through the duration of many HTTP requests.

This raises the question of what happens to variables you define in an Embperl document—do they also keep their values across invocations, or do they disappear? The answer is that each Embperl document is processed in its own package, and the variables defined in that package are reset by default upon each invocation. However, variables defined in other packages are kept across invocations. The following Embperl document demonstrates how this works:

<Head><Title>Current time</Title></Head>
[- $counter++; -]
[- $remain::counter++; -]
<P>This is Embperl</P>
<P>Counter: [+ $counter; +]</P>
<P>remain::counter: [+ $remain::counter; +]</P>

If you try this on your system, you may well discover that $counter always remains at 1, while $remain::counter is incremented with each invocation. However, if you are running more than a single copy of Apache, $remain::counter probably jumps around, as if several different copies of it were being incremented. This is indeed the case, since each copy of Apache is running its own copy of mod_perl and Embperl. If you rely on persistent variables across invocations, remember that a given user might connect to more than one copy of Apache, and you cannot rely on the same copy always being available to the same user.

However, persistent variables can be useful when making connections with other than the user's computer. In particular, DBI (the Perl database interface) can take advantage of this with the Apache::DBI module. This module opens a connection to a database server when it is first invoked, and then continues to use that connection throughout the life of the Apache process, immediately sending each query to the database server. Because the persistence is between Apache and the database server, it works regardless of whether a user connects to the same httpd process each time.

When defining subroutines inside of Embperl documents, it's probably best to use another kind of square brackets, with exclamation points as the special characters. Square-bang brackets ([! !]) are the same as square-minus brackets, except that the Perl code contained within is executed only upon the document's first invocation. If you are running Embperl under mod_perl, defining subroutines inside of square-bang brackets means they will be defined and compiled a single time, further increasing the speed of your program.

Embperl Meta-commands

Finally, we come to square-dollar brackets ([$ $]), which allow you to enter Embperl meta-commands. These meta-commands, as you might imagine from the name, are actually part of a small programming language with which you can tell Embperl what to do.

Meta-commands allow you to make sections of HTML and Perl conditional, or to loop over them a given number of times. The same tasks could be performed inside of a normal Embperl block, since Perl is a full-fledged programming language and can handle conditionals and looping just fine. But by using the Embperl meta-commands, you can place even more HTML outside of the Perl blocks, making the Perl blocks somewhat smaller and easier to read.

For example, let's say we run a web site that requires registration. Assuming we have a function called &is_registered that returns “true” or “false”, depending on whether a user is registered with our system, we could print an appropriate greeting with the following code:

[+ &registered($user_id) ? "You are known" : "You are
unknown" +]

Once you start to deal with the formatting associated with those strings, the menus you might want to display for new users and the personalized home pages that registered users should see, the block of Perl inside of square-plus brackets becomes quite large. It's thus easier to use square-dollar brackets and Embperl meta-commands:

[$ if &registered($user_id) $]
You are known, your registered home page:
        [+ &output_home_page($user_id) +]
 [$ else $]
 Welcome, new user! We would like to ask you a few
 [+ &output_questionnaire +]
[$ endif $]
The above, which I have indented in the style of a programming language, is easier to understand than a large block of Perl code. It is also more easily understood and modified by non-programmers on your site, who can clearly see the difference between HTML and other items.