BUY THIS BOOK
Add to Cart

Print Book $34.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £24.95

What is this?

Looking to Reprint this content?


Embedding Perl in HTML with Mason
Embedding Perl in HTML with Mason By Dave Rolsky, Ken Williams
October 2002
Pages: 318

Cover | Table of Contents | Online Book | Colophon


Table of Contents

Chapter 1: Introduction
At its heart, Mason is simply a mechanism for embedding Perl code into plain text. It is only one of many such mechanisms that all do more or less the same thing. However, Mason represents a particular set of choices about how this embedding should be done, and many people have found that the way Mason does things is very straightforward and extremely conducive to getting jobs done.
In this chapter we'll introduce you to some of Mason's key features and strengths, show you a couple of examples of how to use Mason, and talk about some alternatives to Mason. After reading this chapter, you should have a fairly good idea of how Mason relates to its peers and what kinds of tasks you can accomplish with Mason.
The most common application of Mason is in building large dynamic web sites, and this book focuses mostly on web site building. Mason is broadly applicable to any situation in which fine control over document content is required, however, such as generating mail-merged form letters, creating custom configuration file sets, and even building dynamic GIF images based on varying input parameters. We intend to give you enough facility with Mason that after reading this book, you can imagine Mason-based solutions to problems we haven't ever thought of.
Before we get into the details of Mason and comparisons with its alternatives, we'll just briefly mention some of its guiding design principles. Mason was designed to help you build, organize, and maintain large web sites or other groups of dynamically generated documents. It cooperates fully with Perl, leveraging all the solutions and techniques that Perl developers have come to depend on and that have made Perl such a powerful and widespread tool. It encourages thinking about your site in structural terms rather than as a collection of procedural scripts or modules. All of these things are conducive to getting your job done effectively, letting you concentrate on your goals while Mason takes care of the details.
To help make this discussion a little more concrete (this thing is called Mason, after all), let's look at an example. We'll give more in-depth treatment to the details of Mason's syntax later in the book; these examples are just to put some Mason code in front of your eyes and show you what it looks like.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
A First Example
To help make this discussion a little more concrete (this thing is called Mason, after all), let's look at an example. We'll give more in-depth treatment to the details of Mason's syntax later in the book; these examples are just to put some Mason code in front of your eyes and show you what it looks like.
The following code is a complete chunk of Mason code, called a component:
% my $planet = "World";
Hello, <% $planet %>!
When Mason runs this code, the output is:
Hello, World!
We'll talk more about the details of component syntax in Chapter 2, but two basic elements in the preceding example deserve mention here. The first is that any line that begins with a % character tells Mason that the line contains Perl code. The Perl code can be any syntactically correct Perl — Mason doesn't care what it is or what it does. In this case, it simply sets the value of a variable that will be used later in the component.
The other element in the previous Mason component is the substitution tag, denoted by the sequence <% %>. Mason will evaluate the contents of any such tag and insert the result into the surrounding text. In this case, the variable $planet evaluates to World, and the output of the entire component is Hello, World!
Note that any text that isn't a special Mason construct simply becomes part of the output of the component.
These two lines are relatively simple and not particularly exciting, but they should give you a taste for how Mason code looks in its simplest form.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Main Features of Mason
There are more templating systems written in Perl than you could possibly keep in your head all at once. To help you make sense of Mason's place in the world, this section presents Mason's most important and distinctive features. By the end of this section, you should see that Mason pushes the boundaries of the term "templating system," with lots of features aimed at helping you manage the larger tasks of site design and maintenance.
As we mentioned before, the basic unit of Mason code is called a component. It is a chunk of Mason code that can accept input parameters and generate output text. An important feature of Mason is that any component may call any other component at any point during its execution, much like a Perl subroutine calling another Perl subroutine. Because of this feature, a component may represent a single web page, a part of a web page (like a side navigation bar), or even a shared utility function that generates no output of its own. This separation of design elements allows you to use Mason as a sort of glorified server-side include (SSI) mechanism, as in Example 1-1, Example 1-2, and Example 1-3. Executing mainpage.mas will produce a full page of HTML with the header and footer inserted in place.
Example 1-1. header.mas
<html>
<head><title>Welcome to Wally World!</title></head>
<body bgcolor="#CCFFCC">
Example 1-2. footer.mas
<center><a href="/">Home</a></center>
</body></html>
Example 1-3 introduces the component call tag syntax, <& &>, which is used to call another component and insert its output into the surrounding text. The component tag can also accept arguments, which in this case can help unify site design by moving the page header text into the header.mas component.
Example 1-3. mainpage.mas
<& header.mas &>
<center><h1>Wally World Home</h1></center>
Here at Wally World you'll find all the finest accoutrements.
<& footer.mas &>
The header.mas component in Example 1-4 now accepts an argument called $head that contains the text that should get inserted into the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Alternatives to Mason
Much of this chapter so far may have sounded like a sales pitch, because we wanted you to know about Mason's biggest strengths so you could have some solid reasons for reading the rest of this book. However, you should also be aware that there are many alternatives to using Mason, and an awareness of these alternatives will help you form an accurate picture of the context for which each system was created. It will also help you decide which system to use for each individual project, because no single system was designed to be a solution to all the problems you might encounter. Just as importantly, different people find that different systems suit the way they think better than others do.
There are generally two kinds of systems that people consider to be alternatives to Mason: lightweight solutions and heavyweight solutions. Lightweight solutions generally have the goal of being small and fast and leave much of the major work up to you. They are often simple templating modules like Text::Template or HTML::Template or even homegrown templating schemes. Using templates is certainly a good idea, and it is one of the core ideas in Mason itself. However, when designing an entire site, you're usually going to need some more sophisticated system that helps you manage your site-building resources; if you choose a templating-only solution, you'll probably end up writing this management code yourself. You may have a good idea of what such a system would entail only after writing and maintaining dozens of complicated web sites, so you'd likely spend more time working on your management code than on building your sites. This is the main trade-off with lightweight solutions: you gain flexibility because you can manage your site however you want, but since the burden rests entirely on you, you might end up preferring to use a tool that handles many of these management issues for you.
By contrast, heavyweight solutions implement several layers on top of their templating capabilities. Despite some disagreement on proper use of the term, "application server" is often used to describe such heavyweight systems. Each anticipates the typical needs of a large, sophisticated web site and provides methods for dealing with these situations cleanly. A heavyweight system will typically have support for integrating a site with a database, working with HTML and URLs, preserving state from one request to the next, caching often-used resources, and dealing with error conditions. Each heavyweight solution is tailored to different site requirements and makes different assumptions about the best ways to deal with them.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Philosophy
The final criterion in evaluating an application platform is peace of mind: your peace of mind as a developer, your company's peace of mind as a provider of services and maintainer of site resources, and your users' peace of mind to enjoy (or suffer through) your final product. If you are continually frustrated by your development tools and environment, you will almost certainly not be able to create a satisfactory product.
Mason was created to help you with tasks when you need help and get out of your way when you don't. It was designed to cooperate with Perl to the fullest extent possible. The Mason templating language is extremely simple but full featured and leverages Perl to do all the things that a programming language is good at. Mason is not explicitly tied to the HTML markup language, but it was designed to function well in an HTML environment. Mason's design choices were made to encourage a structural approach to site building rather than a procedural approach, and this often makes building large sites with a consistent feel very simple.
If you're interested in learning more about alternatives to Mason, you might be interested in another book from O'Reilly and Associates, Inc., CGI Programming with Perl, written by Scott Guelich, Shishir Gundavaram, and Gunther Birznieks. It contains more extensive discussions of many of the modules mentioned here.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Getting Started with Mason
To help you try out the various examples you'll see throughout the book, we'll walk you through the typical installation and configuration steps. First we'll describe a fairly bare-bones standalone installation that can be used without a web server, and then we'll describe the more common situation, which is to install Mason for use in conjunction with the Apache web server and its mod_perl-embedded Perl interpreter.
Mason can be installed just like any other typical Perl module and used as a toolset for templating. You'll need these ingredients:
Perl 5.005 or later
Available from http://www.cpan.org/src/. Perl may already be installed on your system, especially if it's a variety of Unix. Mason requires at least Version 5.005 of Perl, though Version 5.6.1 is recommended. Instructions for installing Perl are contained in the INSTALL file, included with the distributions. If you're on some variety of Windows, you may find it much easier to install a version of Perl supplied by ActiveState, available at http://www.activestate.com/Products/ActivePerl/.
Mason 1.10 or later
To install Mason, download it from http://www.cpan.org/modules/by-module/HTML/, http://www.masonhq.com/code/download/, or your favorite CPAN mirror, and issue the standard commands for installing Perl modules: perl Makefile.PL, then make, then make test. If no errors are encountered, issue the command make install. This last step may need to be done as the administrative user, so that Mason is made available to all the users of the computer.
During some of these steps, you'll notice Mason looking around for Apache and mod_perl. You can skip these parts of the installation process when asked, since you won't be using them in this scenario.
You'll also need several other Perl modules that Mason depends on, such as Exception::Class, Class::Container, and Params::Validate. Since it can get fairly tedious to follow all these dependencies yourself, you may want to use the CPAN.pm module to help automate the process. In this case, you can start the CPAN
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Components
As mentioned in Chapter 1, the basic building block of Mason is called a component. A component consists of text of any sort as well as Mason-specific markup syntax. This chapter briefly introduces some core Mason concepts and then goes into the nitty-gritty of component syntax.
In this chapter we'll introduce you to the syntax of Mason components, but we won't spend much time on semantics. In most of the sections, we refer to other parts of the book where you can find out more about each concept.
In order to put Mason into perspective, a basic understanding of how Mason processes a request is helpful. Each request is defined by an initial component path and a set of arguments to be passed to that component.
Requests are handled by the Interpreter object. You can use it directly or its API can be called by the ApacheHandler or CGIHandler modules provided with Mason.
The Interpreter asks the Resolver to fetch the requested component from the filesystem. Then the Interpreter asks the Compiler to create a "compiled" representation of the component. Mason's compilation process consists of turning Mason source code into Perl code, which is then executed in order to create an object representing the component. Mason stores this generated Perl code on disk, so that it doesn't need to go through the parsing and compilation process for every request, and stores the compiled code in an LRU (least recently used) cache in memory.
Once Mason has an object representing the initial component, it creates a request object and tells it to execute that component. The initial component might call several other components during the request. Any output a component generates is sent to STDOUT, which is a reasonable default for most environments in which Mason might be used. Of course, it is possible to change this default and send output elsewhere.
Several parameters can change how elements of this process happen, and you can replace the core Mason classes with your own customized subclasses for specialized behavior. When using the ApacheHandler module, all of these parameters can be specified in the web server's configuration file.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Mason from 10,000 Feet
In order to put Mason into perspective, a basic understanding of how Mason processes a request is helpful. Each request is defined by an initial component path and a set of arguments to be passed to that component.
Requests are handled by the Interpreter object. You can use it directly or its API can be called by the ApacheHandler or CGIHandler modules provided with Mason.
The Interpreter asks the Resolver to fetch the requested component from the filesystem. Then the Interpreter asks the Compiler to create a "compiled" representation of the component. Mason's compilation process consists of turning Mason source code into Perl code, which is then executed in order to create an object representing the component. Mason stores this generated Perl code on disk, so that it doesn't need to go through the parsing and compilation process for every request, and stores the compiled code in an LRU (least recently used) cache in memory.
Once Mason has an object representing the initial component, it creates a request object and tells it to execute that component. The initial component might call several other components during the request. Any output a component generates is sent to STDOUT, which is a reasonable default for most environments in which Mason might be used. Of course, it is possible to change this default and send output elsewhere.
Several parameters can change how elements of this process happen, and you can replace the core Mason classes with your own customized subclasses for specialized behavior. When using the ApacheHandler module, all of these parameters can be specified in the web server's configuration file.
If a fatal error occurs during any part of this process, Mason throws an exception via Perl's built-in die( ) function. In a mod_perl or CGI environment, Mason will make sure that this exception is handled in a reasonable way, by showing the error in the browser and/or recording the error in the server's error log. You can also catch exceptions in your own code and handle them as you please.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Core Concepts
Before diving into component syntax, it is important to understand a few basic Mason concepts, with the key concepts highlighted in italics.
First there is the component . A component is a combination of text and Mason-specific markup. The markup sections may contain Perl code or special Mason directives. A component can correspond to a single web page, but more often a page is built up from several components. However, a component always corresponds to a single file.
A component is usually expected to generate output of some sort, whether HTML, an email message, or an image file. Components are closely analogous to Perl subroutines.
The component root is a directory or list of directories on the filesystem under which Mason expects to find all of your components. This is important in determining how component calls are resolved. If you ask Mason to execute the component /view/books.comp, Mason needs to know where to find such a thing. If your component root is /var/www/mason, Mason will look for a file called /var/www/mason/view/books.comp.
The process of resolving a component path to a component can actually be a bit more complex than that, because you may actually specify multiple directories in which to search for components or use another storage mechanism altogether. We'll leave those complexities aside for now.
When running under Apache, either via mod_perl or CGI, Mason will default to using the web server's document root as the component root. Mason may also be used in ways that don't require a component root at all, such as from a standalone perl script. Since the focus of this book is on building sites, we will generally assume that there is a component root unless we mention otherwise.
It is very important to understand that component paths, like URL paths, always use the forward slash (/) as their directory separator, no matter what operating system Mason is running on. In other words, a component path can be thought of as a unique identifier for a particular component, in much the same way that a URL is a unique identifier for a particular resource. Also much like a URL, a component path usually corresponds to a file on disk with a related path, but it needn't necessarily.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Basic Component Syntax
Mason parses components by taking the text of a component and translating it into actual Perl code. This Perl code, when executed, creates a new HTML::Mason::Component object. This object, in turn, can be used to generate the text originally found in the component. In a sense, this inverts the component, turning it from text with embedded Perl into Perl with embedded text.
The markup language Mason uses can give certain parts of the component special semantics, just like any other markup language such as XML or HTML. In this case, the syntax is used to tell Mason that certain parts of the component's text represent either Perl code, special instructions for Mason, or in some cases both.
The markup language used for Mason components contains a simple tag to do in-place substitution of Perl expressions, a way to mark a single line as being a line of Perl, and a set of block tags, most of which contain Perl code that is given a special meaning based on the particular tag being used (see Table 2-1).
Table 2-1: A portion of Mason's markup language
Tag
Name
Contains
<% ... %>
Substitution
Perl that is evaluated and sent as output
% ...
Perl line
A single line of Perl code
<%perl> ... </%perl>
Perl block
Perl code
<& ... &>
Component call
A call to another component, possibly with arguments
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Component Arguments
Most components will expect to receive named arguments, and these can be passed in one of two ways. Components can receive arguments as the result of external requests, such as those via HTTP, or they can receive arguments when they are called from another component. These arguments are available in the called component via several mechanisms. But from a component's perspective, how it is called is largely irrelevant.
Since we are talking about arguments, it is worth revisiting the <%args> block discussed previously. This block is used to declare the arguments that a component expects. In addition, it can also be used to specify a default value if none is given when the component is called.
The block we used earlier was:
<%args>
 $color
 $size => 20
 @items => ( 1, 2, 'something else' )
 %pairs => ( key1 => 1, key2 => 'value' )
</%args>
This says, in English, that this component expects two scalars, one named color , which is mandatory, and one named size , which is not mandatory and defaults to 20. It also expects an array named items , which defaults to (1, 2, ' something else' ) and a hash named pairs, which defaults to ( key1 => 1, key2 => 'value' ). Neither of these latter two arguments is mandatory.
These arguments are all available in your component as lexically scoped variables. For example, your component will have a lexically scoped $color variable available. You do not need to declare it anywhere but in the <%args> block.
If a mandatory argument (one with no default) is not provided in the call to the component, an exception is thrown. If an argument with a default is not given a value, the default is transparently assigned to the variable. Just to be clear, we will explicitly note that undef is a valid value for an argument. It is the absence of an argument that causes the exception.
In addition to any lexically scoped variables created via their declaration in an <%args> block, each component body also has a lexically scoped hash called
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Component Return Values
So far, we know three ways to call components: by using the inline component call tag (<& &>), by using the $m->comp( ) method, or via a URL. When using a component call tag, the called component's output is placed exactly where the tag was. When a component is called via a URL, its output is sent to the client. The $m->comp( ) tag offers an additional channel of component output: the return value. By default, Mason components return undef. If you want to return something else, you can add an explicit return( ) statement inside that component, such as this:
<%init>
 my $size = 20;
 return $size;
</%init>
Perl's return( ) function will end processing of the component, and any values specified will be the return value of $m->comp( ). Since Perl's normal rules of scalar/list context apply, a component may return either a scalar or a list.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Special Globals
All Mason components are given access to certain special variables. We have already discussed %ARGS, which is lexically scoped for each component. Mason also has a few special global variables available.
This variable is an HTML::Mason::Request object, which has a number of methods that allow you to do things such as retrieve information on the current request, call other components, or affect the flow of execution. This object is discussed in detail in Chapter 4.
If Mason is running under mod_perl (as is the case in most Mason setups), all components also have access to the Apache request object via the global variable $r. Mason's special hooks into mod_perl are covered in Chapter 7.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Sample Component
The component shown in Example 2-1 is part of our sample site and the focus of Chapter 8. The component here is responsible for displaying news about the site. It is called news.mas and is not intended to standalone by itself, but rather to form one part of a complete page.
It demonstrates a typical small Mason component. Its <%init> block does some very simple work to figure out the time that the file was last altered, and then it turns that time into a human-readable string.
Example 2-1. news.mas
<table width="100%" cellspacing="0" cellpadding="5">
 <tr>
  <td class="heading"><h2 class="headline">What's New?</h2></td>
 </tr>
 <tr>
  <td>
   <p>
   The whole site, at this point.
   </p>

   <p>
   <em>Last modified: <% $last_mod %></em>
   </p>
  </td>
 </tr>
</table>
<%init>
 my $comp_time = (stat $m->current_comp->source_file)[9];
 my $last_mod =
     Time::Piece->strptime( $comp_time, '%s' )->strftime( '%B %e, %Y %H:%M' );
</%init>
No single component can demonstrate all of Mason's features, so if you're curious to see more, browse some of the components shown in Chapter 8.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Special Components: Dhandlers and Autohandlers
In previous chapters you've seen an overview of the basic structure and syntax of Mason components, and you've seen how components can cooperate by invoking one another and passing arguments.
In this chapter you'll learn about dhandlers and autohandlers, two powerful mechanisms that help lend reusable structure to your site and help you design creative solutions to unique problems. Mason's dhandlers provide a flexible way to create "virtual" URLs that don't correspond directly to components on disk, and autohandlers let you easily control many structural aspects of your site with a powerful object-oriented metaphor.
The term "dhandler" stands for "default handler." The concept is simple: if Mason is asked to process a certain component but that component does not exist in the component tree, Mason will look for a component called dhandler and serve that instead of the requested component. Mason looks for dhandlers in the apparent requested directory and all parent directories. For instance, if your web server receives a request for /archives/2001/March/21 and passes that request to Mason, but no such Mason component exists, Mason will sequentially look for /archives/2001/March/dhandler, /archives/2001/dhandler, /archives/dhandler, and /dhandler. If any of these components exist, the search will terminate and Mason will serve the first dhandler it finds, making the remainder of the requested component path available to the dhandler via $m->dhandler_arg. For instance, if the first dhandler found is /archives/dhandler, then inside this component (and any components it calls), $m->dhandler_arg will return 2001/March/21. The dhandler can use this information to decide how to process the request.
Dhandlers can be useful in many situations. Suppose you have a large number of documents that you want to serve to your users through your web site. These documents might be PDF files stored on a central document server, JPEG files stored in a database, text messages from an electronic mailing list archive (as in the example from the previous paragraph), or even PNG files that you create dynamically in response to user input. You may want to use Mason's features to create or process these documents, but it wouldn't be feasible to create a separate Mason component for each document on your server.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Dhandlers
The term "dhandler" stands for "default handler." The concept is simple: if Mason is asked to process a certain component but that component does not exist in the component tree, Mason will look for a component called dhandler and serve that instead of the requested component. Mason looks for dhandlers in the apparent requested directory and all parent directories. For instance, if your web server receives a request for /archives/2001/March/21 and passes that request to Mason, but no such Mason component exists, Mason will sequentially look for /archives/2001/March/dhandler, /archives/2001/dhandler, /archives/dhandler, and /dhandler. If any of these components exist, the search will terminate and Mason will serve the first dhandler it finds, making the remainder of the requested component path available to the dhandler via $m->dhandler_arg. For instance, if the first dhandler found is /archives/dhandler, then inside this component (and any components it calls), $m->dhandler_arg will return 2001/March/21. The dhandler can use this information to decide how to process the request.
Dhandlers can be useful in many situations. Suppose you have a large number of documents that you want to serve to your users through your web site. These documents might be PDF files stored on a central document server, JPEG files stored in a database, text messages from an electronic mailing list archive (as in the example from the previous paragraph), or even PNG files that you create dynamically in response to user input. You may want to use Mason's features to create or process these documents, but it wouldn't be feasible to create a separate Mason component for each document on your server.
In many situations, the dhandler feature is simply a way to make URLs more attractive to the end user of the site. Most people probably prefer URLs like http://www.yoursite.com/docs/corporate/decisions.pdf over URLs like http://www.yoursite.com/doc.cgi?domain=corporate&format=pdf&content=decisions. It also lets you design an intuitive browsing interface, so that people who chop off the tail end of the URL and request
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Autohandlers
Mason's autohandler feature is one of its most powerful tools for managing complex web sites.
Managing duplication is a problem in any application, and web applications are no exception. For instance, if all pages on a given site should use the same (or similar) header and footer content, you immediately face a choice: should you simply duplicate all the common content in each individual page, or should you abstract it out into a central location that each page can reference? Anyone who's worked on web sites knows that the first approach is foolhardy: as soon as you need to make even a minor change to the common content, you have to do some kind of find-and-replace across your entire site, a tedious and error-prone process.
For this reason, all decent web serving environments provide a way to include external chunks of data into the web pages they serve. A simple example of this is the Server Side Include mechanism in Apache and other web servers. A more sophisticated example is Mason's own ability to call one component from inside another.
Although an include mechanism like this is absolutely necessary for a manageable web site, it doesn't solve all the duplication problems you might encounter.
First, the onus of calling the correct shared elements still rests within each individual page. There is no simple way for a site manager to wave a wand over her web site and say, "Take all the pages in this directory and apply this header and this footer." Instead, she must edit each individual page to add a reference to the proper header and footer, which sounds remarkably like the hassle we were trying to avoid in the first place. Anyone who has had to change the header and footer for one portion of a site without changing other portions of the site knows that include mechanisms aren't the cat pajamas they're cracked up to be.
Second, include mechanisms address only content duplication, not any other kind of shared functionality. They don't let you share access control, content filtering, page initialization, or session management, to name just a few mechanisms that are typically shared across a site or a portion of a site.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Autohandlers and Dhandlers Together
Despite their similar names, the autohandler and dhandler mechanisms are actually totally distinct and can be used independently or in tandem. In this section we look at some ways to use autohandlers and dhandlers together.
Most important about the way dhandlers and autohandlers interact is that Mason first figures out how to resolve a path to a component name, then figures out the inheritance of that component. In other words, Mason determines dhandlers before it determines autohandlers. This has several consequences.
First, it means that a dhandler may use the inheritance mechanism just like any other component can. A component called /trains/dhandler may specify its parent using the inherit flag, or it may inherit from /trains/autohandler or /autohandler by default.
Second, if Mason receives a request for /one/two/three.mas, and the component root contains components called /one/two/autohandler and /one/dhandler but no /one/two/three.mas, Mason will first determine that the proper requested component for this request is /one/dhandler, then it will search the component root for any appropriate parents. Since the autohandler is located in the /one/two/ directory, it won't be invoked when serving /one/.
An example from John Williams (a frequent and important contributor to the Mason core) helps illustrate one powerful way of using dhandlers and autohandlers together. Suppose you're running a web site that serves news articles, with articles identified by the date they were written. Normally articles get published once a day, but once in a while there's a day without an article published.
Say you get a request for /archive/2001/march/21. A dhandler at /archive/dhandler could provide the content for any missing files, for example by finding the latest article whose date is before the requested date. An autohandler at /archive/autohandler or /autohandler could provide the sitewide header and footer in a uniform fashion, not caring whether the article had its own component file or whether it was generated by the dhandler.
Remember, autohandlers and dhandlers are distinct features in Mason, and by combining them creatively you can achieve very powerful results.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: APIs
Mason is more than just a templating system. It provides a framework for translating requests into output. This framework has a number of class/object APIs worth knowing about. You certainly won't need to use most of these methods very often, but you will probably want to use at least some of them in many of your Mason-based projects. This chapter documents those APIs. For a more concise reference to these methods, see Appendix B.
The request object in Mason represents the context of the current request process. For example, it knows where in the component wrapping chain it is, what arguments have been passed to various component calls, if you've been bad or good, and so on. It also allows you to change that context in various ways, such as by calling another component or aborting the request.
The request API provides access to some of the most frequently used Mason features, particularly those relating to component calls, autohandlers, and aborting in the middle of a request.
Recall, as first mentioned in Chapter 2, that the Mason request object is available in all components as $m.
The request class has only two class methods. The first, HTML::Mason::Request->new( ) , is intended for use by other Mason objects and is not documented for external use. If you want to make a new request object, use the make_subrequest( ) method provided by the request object, which is covered as part of the discussion of Mason's subrequest mechanism in Chapter 5.
The second class method, HTML::Mason::Request->instance( ) , returns the current Mason request object. This is useful if you have code outside of a Mason component that needs to access the request object. Inside components, you can just use $m.
The request object's methods can be grouped together into several functional areas.
A number of parameters can be set when creating a new request object. You will most often set these by passing them to the ApacheHandler's constructor or by setting them in your httpd.conf
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Request Class and Object API
The request object in Mason represents the context of the current request process. For example, it knows where in the component wrapping chain it is, what arguments have been passed to various component calls, if you've been bad or good, and so on. It also allows you to change that context in various ways, such as by calling another component or aborting the request.
The request API provides access to some of the most frequently used Mason features, particularly those relating to component calls, autohandlers, and aborting in the middle of a request.
Recall, as first mentioned in Chapter 2, that the Mason request object is available in all components as $m.
The request class has only two class methods. The first, HTML::Mason::Request->new( ) , is intended for use by other Mason objects and is not documented for external use. If you want to make a new request object, use the make_subrequest( ) method provided by the request object, which is covered as part of the discussion of Mason's subrequest mechanism in Chapter 5.
The second class method, HTML::Mason::Request->instance( ) , returns the current Mason request object. This is useful if you have code outside of a Mason component that needs to access the request object. Inside components, you can just use $m.
The request object's methods can be grouped together into several functional areas.
A number of parameters can be set when creating a new request object. You will most often set these by passing them to the ApacheHandler's constructor or by setting them in your httpd.conf file. You may occasionally want to set one of these parameters on the fly for the current request. Finally, you will create a new request object when you want to make a subrequest, and you may want to set these parameters then.
All of the following parameters are also available as get/set methods of the same name:
autoflush
This attribute is discussed in Section 4.1.8, later in this chapter.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Component Object API
Objects that you will deal with in this class actually fall into three categories. The majority will be objects of the HTML::Mason::Component::FileBased class, which is used for components generated from component source files. The next most common will be HTML::Mason::Component::Subcomponent objects, which represent subcomponents and methods. Finally, anonymous components created via the HTML::Mason::Interp->make_component( ) method (covered in Chapter 5 and Chapter 6) will simply be of the HTML::Mason::Component class.
For the most part, these objects all share the same interface.
Component objects are returned from a number of Request object methods as well as the interpreter object's make_component( ) method.
These first methods are the ones you most likely want to use:
attr(name)
Looks for the specified attribute in the component and its parents, returning the first value found. If the attribute is not found, this method throws an exception. Attributes are declared in <%attr> blocks, as covered in "<%flags> and <%attr> blocks" in Chapter 2.
attr_if_exists(name)
Works just like the attr( ) method except that it simply returns undef if the specified attribute does not exist.
Of course, this makes it impossible to distinguish between an attribute with undef as its value and an attribute that is not found. To make that distinction, use the attr( ) method and wrap it in an eval {} block, or use this method in conjunction with the attr_exists( ) method.
attr_exists(name)
Returns true if the specified attribute exists in the component or its parents.
call_method(name, arguments)
Calls the specified method with the given arguments. If the method is not present in the component or any of its parents, an exception is thrown.
scall_method(name, arguments)
This is analogous to the scomp( ) method for the Request object. This method calls the named method with the given arguments and returns the output as a string. If the method is not present in the component or any of its parents, an exception is thrown.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Buffers
Playing with buffers is not for the everyday user but may be useful to you during debugging. Buffer objects have only a few methods:
output
For buffers that store output in a scalar, this method returns the output they have stored so far. If the buffer is a filtering buffer, the output will be filtered before it is returned.
flush
This forces the buffer to pass its output on to its parents, if it has any. Buffers can be set to ignore flushes, in which case this method does nothing.
receive(output, ...)
This method is used to pass output to the buffer. It takes an array of scalars, each of which is considered a piece of output.
clear
This method clears any stored output that the buffer may contain.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: Advanced Features
In the previous chapters you have been introduced to the basic features of Mason, and you should have a fairly good idea by now of how you might actually go about constructing a dynamic web site from Mason components. You have seen a few of Mason's unique features, such as the autohandler mechanism, the dhandler mechanism, and the ability to pass arbitrary data between components.
In this chapter we'll go beyond the basics and learn more about advanced ways to use Mason components to design large dynamic sites. You'll learn how to define multiple components in the same text file, how to create components on the fly from Perl strings, how to manage multiple component root directories, and (finally!) how to use all of Mason's object-oriented features.
Although we often imagine a one-to-one correspondence between text files and Mason components, it is actually possible to define multiple components in a single text file. This is achieved by using a <%def></%def> block, a special Mason directive that defines one component from within another. The component embedded within the <%def> block is called a subcomponent , and it is visible only to the component within which it resides: component A may not access component B's subcomponents directly.
The subcomponent may use any of the standard Mason component directives, such as <%args>, <%init>, %-lines, and so on. The only exceptions are that you may not use <%def> or <%method> blocks within subcomponents nor may you use "global" blocks like <%once> or <%shared>.
Subcomponents are most useful when you have some piece of processing to repeat several times that is used only in a certain specific situation and doesn't merit its own separate component file.
Here is an example of defining and calling a subcomponent. Note that the component is assigned a name inside the <%def> tag (the name often starts with a period, purely by convention) and that you use the regular component-calling mechanisms ($m->comp() or a <& &> tag) to invoke it.
<h2>Information about certain Minnesota cities:</h2>

% my @cities = ("Young America", "Sleepy Eye", "Nisswa", "Embarrass",
%               "Saint Cloud", "Little Canada", "Burnsville", "Luverne");
% foreach my $name (@cities) {
 <hr>
 <& .city_info, city => $name, state => 'MN' &>
% }

<%def .city_info>
<%args>
 $city
 $state
</%args>
 <table border="2">
  <tr> <th colspan="2"><% $city %></th> </tr>
  <tr> <td>Population:</td>  <td><% $population %></td>             </tr>
  <tr> <td>Coordinates:</td> <td><% "$latitude, $longitude" %></td> </tr>
  <tr> <td>Mayor:</td>       <td><% $mayor %></td>                  </tr>
 </table>
<%init>
 my ($population, $latitude, $longitude, $mayor) =
   $dbh->selectrow_array("SELECT population, latitude, longitude, mayor
                          FROM cities 
                          WHERE city=? and state=?",
                          undef, $city, $state);
</%init>
</%def>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Subcomponents
Although we often imagine a one-to-one correspondence between text files and Mason components, it is actually possible to define multiple components in a single text file. This is achieved by using a <%def></%def> block, a special Mason directive that defines one component from within another. The component embedded within the <%def> block is called a subcomponent , and it is visible only to the component within which it resides: component A may not access component B's subcomponents directly.
The subcomponent may use any of the standard Mason component directives, such as <%args>, <%init>, %-lines, and so on. The only exceptions are that you may not use <%def> or <%method> blocks within subcomponents nor may you use "global" blocks like <%once> or <%shared>.
Subcomponents are most useful when you have some piece of processing to repeat several times that is used only in a certain specific situation and doesn't merit its own separate component file.
Here is an example of defining and calling a subcomponent. Note that the component is assigned a name inside the <%def> tag (the name often starts with a period, purely by convention) and that you use the regular component-calling mechanisms ($m->comp() or a <& &> tag) to invoke it.
<h2>Information about certain Minnesota cities:</h2>

% my @cities = ("Young America", "Sleepy Eye", "Nisswa", "Embarrass",
%               "Saint Cloud", "Little Canada", "Burnsville", "Luverne");
% foreach my $name (@cities) {
 <hr>
 <& .city_info, city => $name, state => 'MN' &>
% }

<%def .city_info>
<%args>
 $city
 $state
</%args>
 <table border="2">
  <tr> <th colspan="2"><% $city %></th> </tr>
  <tr> <td>Population:</td>  <td><% $population %></td>             </tr>
  <tr> <td>Coordinates:</td> <td><% "$latitude, $longitude" %></td> </tr>
  <tr> <td>Mayor:</td>       <td><% $mayor %></td>                  </tr>
 </table>
<%init>
 my ($population, $latitude, $longitude, $mayor) =
   $dbh->selectrow_array("SELECT population, latitude, longitude, mayor
                          FROM cities 
                          WHERE city=? and state=?",
                          undef, $city, $state);
</%init>
</%def>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating Components on the Fly
You may encounter situations in which you want to use Mason's templating features and data management tools, but you don't want to create a full-blown component root hierarchy on disk to house your components. Perhaps you want to create a component from an isolated file or directly from a string containing the component text.
For these situations, the Mason interpreter provides the make_component( ) method. It accepts a comp_file or comp_source parameter (letting you create a component from a file or a string, respectively) and returns a Component object.
# Creating a component from scratch
#!/usr/bin/perl -w

use strict;
use HTML::Mason;

my $source = <<'EOF';
<%args>
 $planet
</%args>
Hello, <% $planet %>!
EOF

my $interp = HTML::Mason::Interp->new( );
my $comp = $interp->make_component(comp_source => $source);
$interp->exec($comp, planet => 'Neptune');
And here is a component that creates another component at runtime:
<& $comp &>

<%init>
 my $comp = $m->interp->make_component(
   comp_file => '/home/slappy/my_comps/foo',
 );
</%init>
Of course, creating components at runtime is slower than creating them ahead of time, so if you need to squeeze out all the performance you possibly can, you might need to think of a speedier method to achieve your goals. And as always, benchmark everything so you really know what the effects are.
If the compiler encounters syntax errors when attempting to compile the component, a fatal exception will be thrown inside the make_component( ) method. If you want to trap these errors, you may wrap the make_component( ) method in Perl's eval {} block, and check $@ after the method call.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Sharing Data Among Component Sections
Content preview·Buy PDF of this chapter|