HTML::Mason::Subclassing - Documentation on Subclassing Internal Mason classes
This is the deep voodoo guide, for folks who want to create their own custom subclasses for parts of Mason, such as the Request or Buffer objects.
A number of modules in Mason are subclasses of Class::Container
.
This module was originally part of the Mason core as
HTML::Mason::Container
, but Ken Williams decided to release it separately on CPAN.
It was created to encapsulate some common behaviors for Mason objects such as parameter validation and the creation of ``contained'' objects.
Basically, any Mason object which takes parameters to its constructor
must inherit from this module. Of course, since all of the classes
that you might consider subclassing already inherit from
Class::Container
, you won't need to inherit from it directly.
However, you may need to use some of its methods.
So before you go further we highly recommend familiarizing yourself
with Class::Container
and its methods. Also feel free to look at
some of the Mason core modules to see how Class::Container
is used
within Mason itself.
The following classes have been designed with subclassing in mind:
$m
. The request contains
information about the current request context, and provides methods
for calling other components.
HTML::Mason::Resolver::File
, which is used to translate component
paths into filesystem paths.
HTML::Mason::Compiler::ToObject
,
turns a Mason component into a Mason ``object file'', which contains
actual Perl code.
It also provides its own HTML::Mason::Request
and
HTML::Resolver::File
subclasses which implement some mod_perl
specific behaviors and features.
If you choose to override the constructor, which is always new
with
Mason objects, that you make sure to call the superclass's constructor
and that you use the object returned by it. A good boilerplate for an
overridden constructor looks something like this:
sub new { my $class = shift;
my $self = $class->SUPER::new(@_);
$self->_do_some_init;
return $self; }
One important thing to know about this class is that it is actually
several classes. The first, HTML::Mason::Request
, is used when
ApacheHandler is not loaded. The other,
HTML::Mason::Request::ApacheHandler
, is loaded by ApacheHandler and
used to provide some mod_perl specific features. Similar, the
CGIHandler class provides its own request subclass,
HTML::Mason::Request::CGIHandler
.
It is impossible to know which one of these to subclass at compile time, since it is possible that your subclass will be loaded before either ApacheHandler or CGIHandler.
To handle this, simply set @ISA
in your constructor, like this:
sub new { @ISA = ( $HTML::Mason::ApacheHandler::VERSION ? 'HTML::Mason::Request::ApacheHandler' : $HTML::Mason::CGIHandler::VERSION ? 'HTML::Mason::Request::CGI' : 'HTML::Mason::Request' );
my $class = shift;
my $self = $class->SUPER::new(@_);
...
return $self; }
It is quite important that you do this as these handler-specific subclasses provide important functionality.
exec()
methodThe exec
method is called in order to execute a request, and is the
method that you are most likely to want to override.
However, if you do override it we suggest that you make sure to call
the parent class's exec
method to implement the actual component
execution and there is no need for you to re-implement them.
Since the exec()
method is scalar/list context-sensitive, your
exec
method will need to preserve that. Here is a boilerplate:
sub exec { my $self = shift;
... # do something cool
my @r; if (wantarray) { @r = $self->SUPER::exec(@_); } else { $r[0] = $self->SUPER::exec(@_); }
... # maybe do some cleanup
return wantarray ? @r : $r[0]; }
Your custom request class will also be used to implement subrequests,
which are implemented by calling exec
just like any other method.
If you only want to do certain things in exec
for the first
request, you can simply check the value of $self->is_subrequest
.
See the HTML::Mason::Request::WithApacheSession
module on CPAN.
The resolver takes a component path and figures out what component that path corresponds to.
All resolver classes must implement two methods, get_info
and
glob_path
. The first takes a component path and returns a new
HTML::Mason::ComponentSource
object. This object contains
information about the component, such as its last modified time and
its source. See the
HTML::Mason::ComponentSource
documentation for more details.
You may choose to provide your own ComponentSource subclass as well, if your resolver implementation can take advantage of it.
The glob_path
method is responsible for translating a component
path like /foo/*/bar into a list of component paths that match that
glob pattern.
The rationale for providing your own lexer would be to extend or replace Mason's syntax.
The lexer is called by the compiler via its lex
method. The
arguments it receives are the component name, source, and the compiler
object. See the Compiler class documentation
for details on what methods the lexer can call.
See the Compiler class|HTML::Mason::Compiler
documentation for
details on what methods a subclass of this class needs to provide.
The public API documented in
HTML::Mason::Buffer
is the complete Buffer
class API, except for one method, _initialize
, which is called as
part of the buffer's construction, from the new
method.
Those interested in subclassing this class should also know that the
constructor may take an additional parameter, parent
, which should
be a Buffer object. This parameter is automatically supplied by the
new_child
method.
Any subclass of this class you create should declare itself to be a
subclass of the HTML::Mason::Buffer
class.
The methods that you are mostly to want to subclass are documented in
the ApacheHandler class
documentation.
Providing an ApacheHandler subclass gives you a chance to do your own client parameter parsing, as well as the capability of providing a different way of handling requests.