O'Reilly logo

Embedding Perl in HTML with Mason by Ken Williams, Dave Rolsky

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 12. Custom Mason Subclasses

Something that we have tried very hard to do beginning with the 1.10 release of Mason is to make it easier to customize Mason’s behavior. Jon Swartz was already on this track even back with the release of 0.80, which saw the first appearance of the HTML::Mason::Resolver classes, but 1.10 tries to bring this to new levels.

Starting with 1.10 it has become possible to subclass almost every core class that comes with Mason. Some obvious candidates for subclassing include the Lexer, Compiler, and Resolver. This chapter will demonstrate how you might go about implementing subclasses of various Mason objects.

Class::Container as a Superclass

A number of modules in Mason are subclasses of Class::Container. This is a class that was created to encapsulate some common behaviors for Mason objects. Originally, it was called HTML::Mason::Container, but Ken Williams decided to package this class separately and release it to CPAN, as it solves some fundamental problems of a large object-oriented system. Any Mason object that takes parameters to its constructor must inherit from this module. Of course, since all of the classes that you might consider subclassing inherit from Class::Container already, you shouldn’t need to inherit from it directly. However, you may need to use some of its methods. We will briefly cover a few of them here, but see the Class::Container documentation for more details.

The modules in the Mason core distribution that are Class::Container subclasses are HTML::Mason::ApacheHandler, HTML::Mason::CGIHandler, HTML::Mason::Interp, HTML::Mason::Compiler, HTML::Mason::Lexer, HTML::Mason::Resolver, and HTML::Mason::Request.

The most important methods that Class::Container provides are valid_params( ) and contained_objects( ), both of which are class methods.

The first, valid_params( ), is called in order to register the valid parameters for a class’s new( ) constructor. The second method, contained_objects( ), is used to register the objects, if any, that a given class contains.

The contained_objects( ) method is not something you will have to use for all of your subclasses, since most of the time you won’t be altering the structure of Mason’s framework, you’ll just be plugging your own classes into it. This method is called with a hash that contains as its keys parameter names that the class’s constructor accepts and as its values the default name of the contained class.

For example, HTML::Mason::Compiler contains the following code:

_ _PACKAGE_ _->contained_objects( lexer => 'HTML::Mason::Lexer' );

This says that the HTML::Mason::Compiler->new( ) method will accept a lexer parameter and that, if no such parameter is given, then an object of the HTML::Mason::Lexer class will be constructed.

Class::Container also implements a bit of magic here, so that if HTML::Mason::Compiler->new( ) is called with a lexer_class parameter, it will load the class, instantiate a new object of that class, and use that for the lexer. In fact, it’s even smart enough to notice if parameters given to HTML::Mason::Compiler->new( ) are really intended for this subclass, and it will make sure that they get passed along.

The valid_params( ) method is a bit more complex. It also takes a list of key/value pairs as arguments. The keys are the names of parameters accepted by the new( ) method, while the values are hash references defining a validation specification for the parameter. This specification is largely the same as that used by the Params::Validate module, with a few additions (but no subtractions).

One addition is that each parameter, excluding those that represent contained objects, may also define a value for parse. This tells Mason how to parse this parameter if it is defined as part of an Apache configuration file. If no parse parameter is provided, a sensible default will be guessed from the value of the Params::Validate type argument.

The upshot of this is that your subclasses can define their own constructor parameters and Mason will then check for these parameters in an Apache configuration file.

As an example, HTML::Mason::Compiler contains the following:

_ _PACKAGE_ _->valid_params
    (
     allow_globals =>
     { parse => 'list',   type => ARRAYREF, default => [ ],
       descr => "An array of names of Perl variables that are" .
                " allowed globally within components" },

     default_escape_flags =>
          { parse => 'string', type => SCALAR,   default => '',
            descr => "Escape flags that will apply by default to" .
                " all Mason tag output" },

     lexer =>
       { isa => 'HTML::Mason::Lexer',
         descr => "A Lexer object that will scan component" .
                " text during compilation" },

     preprocess =>
       { parse => 'code',   type => CODEREF,  optional => 1,
         descr => "A subroutine through which all component text" . 
                " will be sent during compilation" },

     postprocess_perl =>
       { parse => 'code',   type => CODEREF,  optional => 1,
         descr => "A subroutine through which all Perl code" .
                " will be sent during compilation" },

     postprocess_text =>
       { parse => 'code',   type => CODEREF,  optional => 1,
         descr => "A subroutine through which all plain text will" .
                " be sent during compilation" },
    );

_ _PACKAGE_ _->contained_objects( lexer => 'HTML::Mason::Lexer' );

The type , default, and optional parameters are part of the validation specification used by Params::Validate. The various constants used, ARRAYREF , SCALAR, and so on, are all exported by Params::Validate. The parameters passed to valid_params( ) correspond to the MasonAllowGlobals, MasonDefaultEscapeFlags, MasonLexerClass, MasonPreprocess, MasonPostprocessPerl, and MasonPostprocessText httpd.conf configuration variables. Yes, Class is added automatically to the lexer param because lexer was also given to the contained_objects( ) method.

The descr parameter is used when we generate the HTML::Mason::Params documentation and is probably not something you’d need to use.

For more details, see both the Class::Container and Params::Validate documentation.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required