HTML::...assing(3pm)
π HTML::Mason::Subclassing β¨
okay so bestie, welcome to the deep voodoo guide π§βοΈ β this one's for the girlies who wanna build their own custom subclasses for bits of Mason, like the Request or Interp objects. it's giving advanced. it's giving main character energy. let's go π«Ά
this is the HTML::Mason::Subclassing page from the User Contributed Perl Documentation section (manual 3pm), and yes we're doing the whole thing, no skips π
πΈ DESCRIPTION πΈ
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 Interp objects.
π Class::Container π
A bunch 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. slay, king π
It was created to encapsulate some common behaviors for Mason objects β stuff like parameter validation and the creation of "contained" objects.
Basically, any Mason object which takes parameters to its constructor must inherit from this module. And of course, since all the classes you might consider subclassing already inherit from Class::Container, you won't need to inherit from it directly. But 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. it's giving homework but make it cute π
π SUBCLASSABLE CLASSES π
The following classes have been designed with subclassing in mind:
HTML::Mason::Requestβ This object is your old friend$mπ The request contains information about the current request context, and provides methods for calling other components.HTML::Mason::Resolverβ The resolver's job is to translate a component paths into an actual component. Mason comes with a single Resolver subclass,HTML::Mason::Resolver::File, which is used to translate component paths into filesystem paths.HTML::Mason::ComponentSourceβ An object of this class represents a component's source. These objects are instantiated by the resolver when it finds a component matching a given path.HTML::Mason::Lexerβ The lexer is responsible for parsing a component. Creating a new lexer would allow you to change Mason's component syntax. β¨HTML::Mason::Compilerβ The compiler takes the parsed chunks from the lexer and gives them meaning. The default compiler,HTML::Mason::Compiler::ToObject, turns a Mason component into a Mason "object file", which contains actual Perl code.HTML::Mason::ApacheHandlerβ The ApacheHandler class is the bridge between the mod_perl world and Mason, primarily Mason's Interp class.
It also provides its own HTML::Mason::Request and HTML::Resolver::File subclasses which implement some mod_perl specific behaviors and features.
HTML::Mason::Interpβ The Interp is the core of Mason, and is primarily responsible for making all the other objects do their jobs. the mom friend of the group chat fr fr π«Ά
π CONSTRUCTORS π
If you choose to override the constructor β which is always new with Mason objects β make sure you 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;
}
π¦ Request π¦
β¨ What to Subclass? β¨
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 call the alter_superclass() method in your constructor, like this:
sub new
{
my $class = shift;
$class->alter_superclass( $HTML::Mason::ApacheHandler::VERSION ?
'HTML::Mason::Request::ApacheHandler' :
$HTML::Mason::CGIHandler::VERSION ?
'HTML::Mason::Request::CGI' :
'HTML::Mason::Request' );
my $self = $class->SUPER::new(@_);
...
return $self;
}
It is quite important that you do this, because these handler-specific subclasses provide important functionality. The alter_superclass() method is implemented in the HTML::Mason::Request base class, and will do the right thing even in cases of multiple inheritance. It also cooperates with Class::Container to make sure that it sees changes to the inheritance hierarchy. team work makes the dream work π
π₯ The exec() method π₯
The 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];
}
π Subrequests π
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. vibe check complete β
β Examples β
See the MasonX::Request::WithApacheSession module on CPAN.
π§ Resolver and ComponentSource π§
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.
π Lexer π
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.
π Compiler π
See the Compiler class documentation for details on what methods a subclass of this class needs to provide.
If you simply want to tweak Mason's existing behavior, you will probably want to subclass HTML::Mason::Compiler::ToObject, which is the default Compiler class. For example, if you wanted to do something like make attributes dynamic, you could override the _flags_or_attr() method in ToObject.
If you want to drastically change the behavior, you can subclass HTML::Mason::Compiler instead. An example of this would be creating a compiler that generates EmbPerl or Apache::ASP as output. iconic behaviour honestly β¨
π ApacheHandler π
The methods that you are most likely 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.
π CGIHandler π
Like the ApacheHandler, you could subclass this module in order to provide your own argument processing or to step in and provide a different way to handle requests.
π USING SUBCLASSES π
When using your custom subclasses, we recommend that you take advantage of Mason's ability to construct subclassed object on the fly.
For example, if you're subclassed the Interp object, you can still let the ApacheHandler object create the Interp object for you, as long as you give it the appropriate interp_class parameter. This is important because Mason may internally set up certain defaults for contained objects. For example, the ApacheHandler, by default, will tell the Interp object to use the HTML::Mason::Request::ApacheHandler Request subclass. If you create an Interp object manually and you want to use that Interp object with ApacheHandler, you'll have to specify the same Request class.
For example:
my $interp =
My::Interp->new
( request_class => 'HTML::Mason::Request::ApacheHandler',
my_new_interp_param => 42,
);
my $ah = HTML::Mason::ApacheHandler->new( interp => $interp );
It is far easier to simply do this:
my $ah =
HTML::Mason::ApacheHandler->new
( interp_class => 'My::Interp',
my_new_interp_param => 42,
);
Your new parameter, my_new_interp_param, will still be passed to the My::Interp constructor, but this also gives ApacheHandler a chance to set various parameters for the Interp object. Of course, you can still override these defaults explicitly:
my $ah =
HTML::Mason::ApacheHandler->new
( interp_class => 'My::Interp',
resolver_class => 'My::Resolver'.
my_new_interp_param => 42,
);
If you need access to the interp object's methods directly, it will be always be available via $ah->interp. π«Ά
and that's the whole thing bestie, no cap, every single detail preserved π go forth and subclass responsibly
perl v5.38.2 Β· 2024-03-05 β mwah, that's a wrap, ty for coming to my ted talk β¨ππ¦
π¦ where this page comes from
- debian trixie: libhtml-mason-perl 1:1.60-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libhtml-mason-perl 1:1.60-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libhtml-mason-perl 1:1.60-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms