By Simon Cozens
Book Price: $39.95 USD
£28.50 GBP
PDF Price: $31.99
Cover | Table of Contents | Colophon
my—the perl interpreter looks up the variable name in the symbol table. For now, we'll consider the symbol table to be a mapping between a variable's name and some storage for its value, as in Figure 1-1.$a, we know where the box is, and we can get and set the values directly. In Perl terms, the symbol table maps to a reference to $a.
$a, @a, %a, &a, the filehandle a, and the directory handle a.a to a glob, which is a structure holding references to all the variables called a, as in Figure 1-2.
@INC) to handle inheritance, for instance, or using the symbol tables for method dispatch—we can fiddle with almost every aspect of it.Object. Perl doesn't quite have the same concept, but there is a single hard-wired class called UNIVERSAL
, which acts as a last-resort class for method lookups. By default, UNIVERSAL provides three methods: isa, can, and VERSION.@ISA array and determines whether or not it derives from a given class:
package Coffee;
our @ISA = qw(Beverage::Hot);
sub new { return bless { temp => 80 }, shift }
package Tea;
use base 'Beverage::Hot';
package Latte;
use base 'Coffee';
package main;
my $mug = Latte->new;
Tea->isa("Beverage::Hot"); # 1
Tea->isa("Coffee"); # 0
if ($mug->isa("Beverage::Hot")) {
warn 'Contents May Be Hot';
}
$thing->isa(...) on an unblessed reference, Perl will die.<<, on filehandles to mean print:
cout << "Hello world";
$object *= $value;
$object is in at this point and hence what method has been called.
<html> tag at the start and an </html> at the end, with some stuff in the middle. The parser can find that pattern in the document and then look to see what the stuff in the middle is likely to be. See Figure 2-2. This is called a top-down parse because it starts with all the possible parses and works down until it matches the actual contents of the document.
Parse::RecDescent module is the most widely used parser generator for Perl. While most traditional parser generators, such as yacc, produce bottom-up parsers, Parse::RecDescent creates top-down parsers. Indeed, as its name implies, it produces a recursive descent parser. One of the benefits of top-down parsing is that you don't usually have to split the data into tokens before parsing, which makes it easier and more intuitive to use.Parse::RecDescent module is the most widely used parser generator for Perl. While most traditional parser generators, such as yacc, produce bottom-up parsers, Parse::RecDescent creates top-down parsers. Indeed, as its name implies, it produces a recursive descent parser. One of the benefits of top-down parsing is that you don't usually have to split the data into tokens before parsing, which makes it easier and more intuitive to use.http://www.red-bean.com/sgf/) for exchanging information about Go games. Here's an example of an SGF file:
(;GM[1]FF[4]CA[UTF-8]AP[CGoban:2]ST[2]
RU[Japanese]SZ[19]HA[5]KM[5.50]TM[ ]
PW[Simon Cozens]PB[Keiko Aihara]AB[dd][pd][jj][dp][pp]
;W[df];B[fd];W[cn]
(;B[dl])
(;B[fp]CR[fp]C[This is the usual response.])
(;B[co]CR[co]C[This way is stronger still.]
;W[dn];B[fp])
)
Parse::RecDescent.Parse::Yapp module. This is more or less a straight port of yacc to Perl.Parse::Yapp to implement the calculator in Chapter 3 of lex & yacc
(O'Reilly). This is a very simple calculator with a symbol table, so you can say things like this:
a = 25
b = 30
a + b
55
%{
double vbltable[26];
%}
%union {
double dval;
int vblno;
}
%token <vblno> NAME
%token <dval> NUMBER
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS
%type <dval> expression
%%
statement_list: statement '\n'
| statement_list statement '\n'
;
statement: NAME '=' expression { vbltable[$1] = $3; }
| expression { printf("= %g\n", $1); }
;
expression: expression '+' expression { $$ = $1 + $3; }
| expression '-' expression { $$ = $1--$3; }
| expression '*' expression { $$ = $1 * $3; }
| expression '/' expression
{ if($3 = = 0.0)
yyerror("divide by zero");
else
$$ = $1 / $3;
}
| '-' expression %prec UMINUS { $$ = -$2; }
| '(' expression ')' { $$ = $2; }
| NUMBER
| NAME { $$ = vbltable[$1]; }
;
%%
HTML::Parser module.HTML::Parser is incredibly flexible. It supports several methods of operation: you can use OO inheritance, you can use callbacks, you can determine what data gets sent to callbacks and when the callbacks are called, and so on. We'll only look here at the simplest way of using it: by subclassing the module.HTML::Parser, we need to say something like this:
package DumpLinks;
use strict;
use base 'HTML::Parser';
<a> tag, then we ignore it. If it is, we make a note of its href attribute and remember that we're currently in an <a> tag.
sub start {
my ($self, $tag, $attr) = @_;
return unless $tag eq "a";
$self->{_this_url} = $attr->{href};
$self->{_in_link} = 1;
}
Parse::RecDescent or Parse::Yapp, or choosing a ready-made parsing module, Perl is perfect for throwing around data and converting it into a different format.comp.lang.perl.moderated enumerated the Perl rites of passage—the perfectly good wheels that every journeyman Perl programmer reinvents. These were found to be a templating system, a database abstraction layer, an HTML parser, a processor for command-line arguments, and a time/date handling module.
my $template = q{
Dear $name,
We have received your request for a quote for $product, and have
calculated that it can be delivered to you by $date at a cost of
approximately $cost.
Thank you for your interest,
Acme Integrated Foocorp.
};
s/(\$\w+)/$1/eeg, and eventually you get something that more or less does the job.s/(\$\w+)/$1/eeg to complete independent templating languages.printf) and substr:
for (@mails) {
printf "%5i %10s %40s %21s\n",
$_->id,
substr($_->received,0,10),
substr($_->from_address,-40,40),
substr($_->subject,0,21);
}
for (@mails) {
print pack("A5 A10 A40 A21\n",
$_->id, $_->received, $_->from_address, $_->subject);
}
format STDOUT =
@<<<< @<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<
$_->id $_->received $_->from_address $_->subject
.
for (@mails) {
write;
}
@ or ^ and are followed by <, |, or > characters specifying left, center, and right justified respectively. After each line of fields comes a line of expressions that fill those fields, one expression for each field. If we like, we could change the format to multiple lines of fields and expressions:Text::Template has established itself as the de facto standard templating system for plain text. Its templating language is very simple indeed—anything between { and } is evaluated by Perl; everything else is left alone.
use Text::Template;
my $template = Text::Template->new(TYPE => "FILE",
SOURCE => "email.tmpl");
my $output = $template->fill_in();
Dear {$who},
Thank you for the {$modulename} Perl module, which has saved me
{$hours} hours of work this year. This would have left me free to play
{ int($hours*2.4) } games of go, which I would have greatly appreciated
had I not spent the time goofing off on IRC instead.
Love,
Simon
use Text::Template;
my $template = Text::Template->new(TYPE => "FILE",
SOURCE => "email.tmpl");
$who = "Mark";
$modulename = "Text::Template";
$hours = 15;
print $template->fill_in();
Dear Mark,
Thank you for the Text::Template Perl module, which has saved me
15 hours of work this year. This would have left me free to play
36 games of go, which I would have greatly appreciated
had I not spent the time goofing off on IRC instead.
Love,
Simon
$who, $modulename, and so on—are not my variables. When you think about it, this ought to be obvious—the my variables are not in Text::Template's scope, and therefore it wouldn't be able to see them. This is a bit unpleasant: Text::Template has access to your package variables, and you have to do a bit more work if you want to avoid giving HTML::Template, is similar to the method we saw in Text::Template; the template is stored somewhere, and a Perl program grabs it and fills it in. The other school of thought is represented by HTML::Mason, which we'll look at next; this is inside-out—instead of running a Perl program that prints out a load of HTML, you create an HTML file that contains embedded snippets of Perl and run that.HTML::Template, HTML::Mason, and Template Toolkit, an aggregator of RSS (Remote Site Summary) feeds to grab headlines from various web sites and push them onto a single page. (Similar to Amphetadesk, http://www.disobey.com/amphetadesk/, and O'Reilly's Meerkat, http://www.oreillynet.com/meerkat/.) RSS is an XML-based format for providing details of individual items on a site; it's generally used for providing a feed of stories from news sites.HTML::Template does its stuff, how to get values into it, and how to get HTML out.Text::Template, templates are specified in separate files. HTML::Template's templates are ordinary HTML files, but with a few special tags. The most important of these is <TMPL_VAR>, which is replaced by the contents of a Perl variable. For instance, here's a very simple page:
<html>
<head><title>Product details for <TMPL_VAR NAME=PRODUCT></title></head>
<body>
<h1> <TMPL_VAR NAME=PRODUCT> </h1>
<div class="desc">
<TMPL_VAR NAME=DESCRIPTION>
</div>
<p class="price">Price: $<TMPL_VAR NAME=PRICE></p>
<hr />
<p>Price correct as at <TMP_VAR NAME=DATE></p>
</body>
</html>
HTML::Template is that it forces us, to some degree, to mix program logic and presentation, something that we sought to avoid by using templates. For instance, that last template got a little difficult to follow, with variable and HTML tags crowding up the template and obscuring what was actually going on. What we would prefer, then, is a system that allows us to further abstract out the individual elements of what we expect our templates to do, and this is where HTML::Mason comes in.HTML::Mason is an inside-out templating system. As well as templating, it could also be described as a component abstraction system for building HTML web pages out of smaller, reusable pieces of logic. Here's a brief overview of how to use it, before we go on to implement the same RSS aggregator application.<& /Header &> <p> Hello World </p> <& /Footer &>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Some Web Application</title>
<link rel=stylesheet type="text/css" href="nt.css">
</head>
<body>
<hr>
<div class="footer">
<address>
<a href="mailto:webmaster@yourcompany.com">webmaster@yourcompany.com</a>
</address>
</div>
</body>
</html>
HTML::Mason builds up the page by including the components specified inside <& and &> tags. When creating test.html, Mason first includes the Headercomponent found at the document root, then the rest of the HTML, then the Footer component.http://www.template-toolkit.org/) is slightly different. It uses its own templating language to express components, loops, method calls, data structure elements, and more; it's therefore useful for teaching to designers who have no knowledge of the Perl side of your application but who need to work on the presentation. As the documentation puts it, you should think of the Template Toolkit language as a set of layout directives for displaying data, not calculating it.Text::Template. We take a template object, feed it some values, and give it a template to process:
use Template;
my $template = Template->new();
my $variables = {
who => "Andy Wardley",
modulename => "Template Toolkit",
hours => 30,
games => int(30*2.4)
};
$template->process("thankyou.txt", $variables);
Dear [% who %],
Thank you for the [% modulename %] Perl module, which has saved me
[% hours %] hours of work this year. This would have left me free to play
[% games %] games of go, which I would have greatly appreciated
had I not spent the time goofing off on IRC instead.
Love,
Simon
http://www.axkit.org) is a slightly different kettle of fish from the modules we've seen so far; this is no mere templating system, it's a fully fledged XML application server for Apache. The most common use of AxKit is to transform XML to HTML on-the-fly for delivery over the web.
<p>
Good
<xsp:logic>
if ((localtime)[2] >= 12) {
<i>Afternoon</i>
}
else {
<i>Morning</i>
}
</xsp:logic>
</p>
<i>Afternoon</i> is data, not Perl code, and treats it appropriately. This also means that if you have an XML guru handy, he can find a way of validating your HTML-with-embedded-XSP. In fact, since AxKit parses everything as XML, your HTML must be well-formed and valid or you won't get anything out of AxKit at all.AxKit::XSP::ESQL taglib provides a wrapper around the DBI libraries. These tag libraries define their own XML namespaces and place tags inside them. So your XML would use a namespace declaration to import the tag library:
<xsp:page
language="perl"
xmlns:xsp="http://apache.org/xsp/core/v1"
xmlns:esql="http://apache.org/xsp/SQL/v2"
>
<esql:...> tags in your page:
<esql:connection>
<esql:driver>Pg</esql:driver>
<esql:dburl>dbname=rss</esql:dburl>
<esql:username>www</esql:username>
<esql:password></esql:password>
<esql:execute-query>
<esql:query>
select description, url, title from feeds
</esql:query>
<esql:results>
<ul>
<esql:row-results>
<li>
<a>
<xsp:attribute name="href">
<esql:get-string column="url"/>
</xsp:attribute>
<esql:get-string column="name"/>
</a> - <esql-get-string column="description"/>
</li>
</esql:row-results>
</ul>
</esql:results>
<esql:no-results> <p> Couldn't get any results! </p> </esql:no-results>
</esql:execute-query>
</esql:connection>sprintf, and the like—on through Text::Template and HTML::Template, and then up to the more sophisticated solutions of HTML::Mason and Template Toolkit.Text::Template and Text::Autoformat, and inside-out modules like HTML::Mason. If the main purpose of your program is to provide some templated output, as in the case of a web-based application, then you probably want to gravitate toward the HTML::Mason and Template Toolkit end of the spectrum.HTML::Template all tend to keep the templater away from Perl, whereas HTML::Mason forces the templater to get down and dirty with it.HTML::Template, preferring the way Mason does things; I find AxKit very powerful but at times very frustrating because of its insistence on clean XML; and I'm beginning to like Template Toolkit the more I use it, but prefer Mason basically because I'm more used to it.DBI and big expensive servers running expensive software packages, but a database is really just anything you can get data in to and back out of.http://www.sleepycat.com/download.html, and the GNU libgdbm, from http://www.gnu.org/order/ftp.html. When Perl is compiled and installed, it supplies Perl libraries to interface with the C libraries that it finds and to the SDBM library, which is shipped along with Perl. I prefer to use the Berkeley DB, with its Perl interface DB_File
.
use DB_File;
tie %persistent, "DB_File", "languages.db" or die $!;
$persistent{"Thank you"} = "arigatou";
# ... sometime later ...
use DB_File;
tie %persistent, "DB_File", "languages.db" or die $!;
print $persistent{"Thank you"} # "arigatou"DBI and big expensive servers running expensive software packages, but a database is really just anything you can get data in to and back out of.http://www.sleepycat.com/download.html, and the GNU libgdbm, from http://www.gnu.org/order/ftp.html. When Perl is compiled and installed, it supplies Perl libraries to interface with the C libraries that it finds and to the SDBM library, which is shipped along with Perl. I prefer to use the Berkeley DB, with its Perl interface DB_File
.
use DB_File;
tie %persistent, "DB_File", "languages.db" or die $!;
$persistent{"Thank you"} = "arigatou";
# ... sometime later ...
use DB_File;
tie %persistent, "DB_File", "languages.db" or die $!;
print $persistent{"Thank you"} # "arigatou"
Class::DBI: a database of CDs in a collection, with information about the tracks, artists, bands, singers, and so on.Class::Accessor::Assert module, which not only creates constructors and accessors for the data slots we want, but also ensures that relationships are handled by constraining the type of data that goes in the slots. So, for instance, the CD class would look like this:
package CD;
use base "Class::Accessor::Assert";
_ _PACKAGE_ _->mk_accessors(qw(
artist=CD::Artist title publishdate=Time::Piece songs=ARRAY
));
Class::DBI and Template Toolkit; partly for the sake of example, partly because I personally think they fit together extremely well, and partly for another reason that will become apparent shortly.Class::DBI. The idea spread through the mailing lists and Perl-mongers groups until, in 2003, Kate Pugh wrote a perl.com article (http://www.perl.com/lpt/a/2003/07/15/nocode.htmlClass::DBI. Finally, we showed how this view of databases works in concert with the templating techniques we looked at in Chapter 3 to create application frameworks like Maypole, allowing you to write large web applications with very little code.