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.
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.
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.[6]
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.
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).
Tag |
Name |
Contains |
<% ... %> |
Substitution |
Perl that is evaluated and sent as output |
% ... |
Perl line |
A single line of Perl code [a] |
<%perl> ... </%perl> |
Perl block |
Perl code |
<& ... &> |
Component call |
A call to another component, possibly with arguments |
<%init> ... </%init> |
init block |
Perl code that executes before the main body of the component |
<%args> ... </%args> |
args block |
A component’s input argument declarations |
[a] The percent sign (%) must occur at the beginning of the line. |
Substitution Tags: <% %>
The simplest kind of Mason tag is the substitution tag, used to insert the results of a Perl expression into your text. This tag is quite similar to those found in other templating systems. A simple example might look like this:
% $cd_count = 207; # this is embedded Perl You have <% $cd_count %> CDs.
The output of this example would be:
You have 207 CDs.
The contents of the tag are evaluated in a list context and joined
together just as if they had been passed as arguments to
Perl’s built-in print( )
function.
It is possible, and often desirable, to put more complicated Perl expressions into your substitution tags. For example, to handle plurals properly, the second line in the previous example could be rewritten as:
You have <% $cd_count %> CD<% $cd_count != 1 ? 's': '' %>
This could output any of the following, depending on the value of the
$cd_count
variable:
You have 207 CDs. You have 1 CD. You have 0 CDs.
The contents of the substitution tag are evaluated as Perl code, so
whitespace is ignored, meaning <%$cd_count%>
would be perfectly valid, though perhaps a bit difficult to read. Our
style is to always include
whitespace in a
substitution tag.
Escaping substitutions
One very useful feature provided by Mason is the ability to escape the contents of a tag before it is sent as output. Escaping is the process of making unsafe characters safe. In a web context, safe means that we do not generate output that could be mistaken for HTML. In addition, we may need to do URL-style escaping as well.
Substitution
escaping is indicated with a
pipe (|
) followed by
one or more escape flags placed before the close of the tag.
Currently, there are three valid escape flags,
h
for HTML entity escaping (i.e.,
>
into
>
),
u
for URI escaping (i.e.,
>
into %3E
),
and n
for no escaping. The
HTML and URI escape flags can be
combined (i.e., hu
) or used separately. An example
might look like:
Name: <% $name | h %> Homepage: <a href="redirect?url=<% $homepage | u %>">
The HTML escaping mode escapes the string using the
HTML::Entities
module, which means that all
control and high-bit characters are escaped, as well as the
greater-than and
l
ess-than signs (<
and >
), the
ampersand
(&
), and the
double quote character
("
).
HTML escaping is particularly useful when you’re populating a page with data from an external data source like a database. For instance, consider the following code:
<textarea name="foo"><% $foo_data %></textarea>
If $foo_data
contains the string
</textarea>
, your HTML will be broken. Guard
against this possibility by escaping the output:
<textarea name="foo"><% $foo_data | h %></textarea>
However, the current implementation of HTML escaping in Mason comes
with one giant caveat. Mason uses HTML::Entities
internally but does not provide a way to tell
HTML::Entities
not to escape certain characters. By default,
HTML::Entities
assumes that you are using
the
ISO-8859-1 character set and escapes characters accordingly. If you
are generating text for another character set, such as
Big5, this
will simply not work. As of this very moment, Mason does not provide
a workaround for this problem, but it will in a near-future release
and perhaps already has by the time you are reading this.
The URI escaping mode escapes any character besides alphanumerics,
the
underscore (
_
), dash (
-
), and period (
.
).
The “no escape” escaping mode is
used when you have set a default escaping mode via the
default_escape_flags
parameter (see Chapter 6 for details). The n
flag
turns off the default escaping for the substitution tag in which it
is used.
If you want to escape using a different mode than the default, you
can combine the n
escape with another flag, for
example:
# default is 'u' <% $contains_html | nh %>
The use of spaces around the pipe is optional.
The purist will note that $variable | h
is
perfectly valid Perl syntax for obtaining the value of
$variable
bitwise OR’ed against
the output of the h
subroutine (or perhaps the
bareword string h
), and therefore
this valid Perl construct has a different meaning in
<% %>
tags than it has in
other Perl environments. If you really mean to
do the bitwise OR (in which case we strongly suspect you really
shouldn’t mean to), a
workaround looks like this:
<% ($variable | h) %>
No doubt this will cause much consternation among those who write code that involves OR-ing together variables and the output of subroutines with single character names, who are being made second-class citizens in the Mason world. Sorry, but we’re standing firm here.
In a near-future release of Mason we plan to make this escaping behavior customizable, so that you will be able to create your own escaping flags.
Embedded Perl: % Lines and <%perl> Blocks
There are two ways to embed Perl code into
text with Mason. The first, the Perl line,
is a line that starts with a percent sign (
%
). The rest of that line (up to
the newline character) is interpreted as Perl code. This percent sign
cannot be preceded by any horizontal whitespace such as spaces or
tabs. A typical use of these lines is to implement Perl control
structures. For example:
% foreach my $person (@people) { Name: <% $person->{name} %> Age: <% $person->{age} %> Height: <% $person->{height} %> Weight: <% $person->{weight} %> % }
You can put any valid piece of Perl code on these lines. It is possible to use a Perl line for a larger chunk of code too — the previous code could have been equivalently written like the following:
% foreach my $person (@people) { % print "Name: ", $person->{name}, "\n"; % print "Age: ", $person->{age}, "\n"; % print "Height: ", $person->{height}, "\n"; % print "Weight: ", $person->{weight}, "\n"; % }
If you have more than a few lines of Perl code in a row, however, it
is probably best to use a Perl block instead. A Perl block is
equivalent to a bunch of Perl lines in a row. It begins with the
start tag <%perl>
and ends with the end tag
</%perl>
. The contents of these blocks may
be any valid
Perl code.
You may want to use this tag if you need to do some data processing in the midst of your text. For example:
<%perl> my @words = sentence =~ /\b(\S+)\b/g; my @small_words = grep { length <= 3 } @words; my @big_words = grep { length > 3 } @words; </%perl> There were <% scalar @words %> in the sentence. The big words were: % foreach my $word (@big_words) { <% $word %> % } The small words were: % foreach my $word (@small_words) { <% $ word %> % }
Calling Other Components: <& &> Tags
One of the most powerful features in Mason is the ability of one component to execute another, causing the called component’s output to appear inside the calling component’s output. The called component can, in turn, call other components, and so on. There are several ways to call components, but the simplest way is via the ampersand tag, like this:
<html> <head> <title>The Goober Guide</title> </head> <body> <h1>Welcome to The Goober Guide!</h1> <& menu &> ... </body> </html>
The menu
component might contain a
navigation bar used on all the pages for a site. Other example calls
might look like this:
<& /path/to/menu &> <& $component &> <& menu, width => 640, admin => 1 &>
These calls illustrate several facets of Mason’s
component call tag. First, the component can be specified either
directly using its name in plain text or indirectly as the result of
Perl expression like $component
in the example. In
addition, component calls can take arguments (like
width
and admin
in the third
example) just like a Perl subroutine — internally, they actually
are subroutines.
How does Mason figure out which component calls are specified
directly and which indirectly? It applies some simple parsing rules.
In a component call tag, if the first nonwhitespace character is a
letter, number, underscore ( _
),
slash ( /
), or period (
.
), Mason assumes that this text is
a plain text component path rather than a Perl expression. In that
case, everything up to the first comma or end of the tag
(&>
), whichever comes first, is assumed to
be a string specifying the component path. Anything after a comma, if
present, will be considered a list of arguments to pass to the called
component.
If the first nonwhitespace character is something else, it is assumed that the component call contains a Perl expression (perhaps a variable or function call) whose value indicates the desired component.
These rules may seem a little arcane, but they manage to capture most
people’s expectations pretty well. Most of the time
you can just specify the component in the most natural way, and it
will just work. If you want to use a Perl expression (the
“indirect” syntax) starting with
one of the special characters mentioned in the previous paragraph,
however, it is necessary to do something to force Mason to see it as
Perl. An easy way to do this is to wrap the Perl expression in
parentheses or to prefix it with Perl’s no-op unary
plus operator (+
). For example:
<& ( component_path_returner( ) ) &> <& +component_path_returner( ) &>
An alternative to the <& &>
syntax
for calling other components is the $m->comp( )
method. The $m
variable contains the
HTML::Mason::Request
object for the current
request, and you may use the $m->comp( )
method
in Perl code just as you would use a <& &>
tag in the component body.[7] In fact, in the current
version of Mason, the <&
&>
tag is implemented internally with the
$m->comp( )
method. So the following two lines
are equivalent to each other:
<& menu, width => 640, admin => 1 &> % $m->comp('menu', width => 640, admin => 1);
Notice how we used a Perl line, starting with a %
,
to embed the $m->comp( )
call in the component.
In this section we have been intentionally vague about how a Perl expression “specifies” a component. There are two ways it may do so: it may either evaluate to a string that gives the path to the component or evaluate to a component object,[8] rather than a path, and that object will then be executed. There are a few idioms in which this is useful, but they’re used fairly rarely, and you’ll mostly call components by their paths.
Components called with content
With Version 1.10, Mason introduced support for a powerful new construct, which we call “components called with content.” Using this construct, it is possible to pass a Mason content block as part of a component call. Here is an example:
<%args> $name </%args> <&| /i18n/itext, lang => $lang &> %# The bits in here will be available from $m->content in the /i18/text <en>Hello, <% $name %>. These words are in English.</en> <fr>Bonjour, <% $name %>, ces mots sont francais.</fr> <pig>Ellohay <% substr($name,2) . substr($name,0,1) . 'ay' %>, esethat ordsway areyay inyay Igpay Atinlay.</pig> </&>
Presumably, we expect the
/i18n/itext
component to filter this
text so that only the correct language, as specified in
$lang
, is used. The
/i18n/itext
component would probably
look something like this, using the
$m->content()
method to retrieve the content
block:
<% $text %> <%args> $lang </%args> <%init> my ($text) = $m->content =~ m{<$lang>(.+?)</$lang>}s; </%init>
The content block gets executed when
$m->content()
is called, but it still has
access to the variables as declared in the original component, such
as $name
. Components called with content will be
covered in more
depth in Chapter 5.
Other Named Blocks
Mason has a variety of
other named blocks.
These all have the same start and end tag syntax as
<%perl>
blocks, and most of them contain
plan Perl. However, these other blocks are interpreted as having
special meanings by Mason.
If any of these blocks, or a <%perl>
block,
is immediately followed by a newline, then that newline is discarded
from the text output. This is a convenience to prevent you from
having to do this all over the place:
<%args> ... </%args><%init> ... </%init><%perl> ... </%perl>This is the start of the component ...
<%init> blocks
This is one of the most commonly used Mason blocks. The Perl code it
contains is run before any other code except for code in
<%once>
or
<%shared>
blocks. It is run every time the
component is called.
Using this block achieves the same effect as putting a
<%perl>
block at the top of a component but
may be aesthetically more pleasing, because it allows you to isolate
code at the bottom of a component, out of the way of the
component’s main body.
The <%init>
block is typically used for
doing things like checking arguments, creating objects, or retrieving
data from a database. The variables created here are used in
substitutions and perl lines throughout the rest of the component.
It is currently <% $temperature %> degrees. <%init> my $temp = $dbh->selectrow_array("SELECT temperature FROM current_weather"); </%init>
<%args> blocks
As we have mentioned, components can take a variety of arguments, from either an external source (an HTTP request, for example) or an internal one (one component calling another).
It is usually desirable to declare the names and datatypes of the
arguments that a component expects, as well as default values for
these arguments, if they have any. This is done via the
<%args>
block. A typical block might look
like this:
<%args> $color $size => 20 # A default value @items => ( 1, 2, 'something else' ) %pairs => ( key1 => 1, key2 => 'value' ) </%args>
This example demonstrates all the syntax possibilities for this
block. First of all, we have argument types and names. The valid
types are scalar, array, and hash, represented by their corresponding
Perl sigil ($
, @
, or
%
), exactly as would be expected.
It is possible to give an argument a default value to be used if none is provided when the component is called. Any argument without a default is considered a required argument. Calling a component without specifying all its required arguments will cause a fatal exception to be thrown.
An argument’s default can refer to an earlier argument, so this is completely legal:
<%args> $x $y => $x * 2 > 20 ? 50 : 100 </%args>
While this block looks as if it contains Perl, it is important to realize that its syntax is actually something unique to Mason. Importantly, lines should not end with a semicolon or comma, and each variable definition must be on a single line.
It is possible to have comments both after an argument declaration
and on their own line. Comments start with the #
character and continue to the end of the line, just as in Perl. Blank
lines are also allowed.
<%filter> blocks
A <%filter>
block is called after a
component has finished running. It is given the entire output of the
component in the $_
variable, and any changes to
this variable are reflected in the output of the component. For
example, this filter uppercases all of the
component’s
output:
<%filter> s/(\w+)/\U$1/g </%filter>
<%once> blocks
This block is executed whenever the component is loaded into memory.
It is executed before any other block (including an
<%init>
block). Any variables declared here
remain in existence (and in scope) until the component is flushed
from memory or the Perl interpreter running Mason shuts down,
whichever comes first. The <%once>
section
is useful for things like creating database handles or instantiating
large, resource-intensive objects.
The universe is this big: <% $size %> <%once> my $size = calculate_size_of_universe( ); </%once>
<%cleanup> blocks
The cleanup block is executed right before the component exits and is
the counterpart to the <%init>
block. It is
useful if you have created resources — such as circular
references — that need to be freed. Technically, it is the same
as placing a <%perl>
block at the end of a
component.
<%init> my $resource = get_a_resource( ); </%init> ... do something interesting with that resource <%cleanup> $resource->dispose; </%cleanup>
Since cleanup code tends to be put at the end of the component
anyway, <%cleanup>
blocks
aren’t very common. Their chief advantage is that
their name is cleanup
.
Cleanup blocks are not executed if the component dies or aborts.
<%text> blocks
The contents of this block are output exactly as they are, without any parsing. This if useful if you need to write a component containing text about Mason. For example:
<%text> Substitution tags look like this: <% $var %>. </%text>
<%doc> blocks
This block is intended for use by component authors for documentation purposes. Its contents are completely ignored. In the future Mason may do something more useful with them.
<%doc> =head1 My Story This is the part where I tell you what the component does. But I'd rather tell you a story about my childhood. When I was but a child, my mother said to me ... </%doc>
As you can see, there’s no reason not to use POD
(Perl’s Plain Old Documentation markup language) in
these blocks, and you can even run perldoc
on a
component file.
<%flags> and <%attr> blocks
These two blocks share the same syntax and are used to declare one or
more key/value pairs. The key can contain only letters, numbers, and
the underscore character ( _
). The
value can be any Perl expression whose results can fit into a scalar
(such as a number, string, reference, or
undef
).
As in the <%args>
block, the syntax in these
blocks looks like Perl, but it is not. First,
you cannot end a line with a comma or semicolon. Second, the whole
key/value pair must be on a single line.
The difference between these two is that the
<%flags>
block may contain only official
Mason flags, which are used to affect the
component’s behavior. Currently, there is only one
flag defined, inherit
. This is used to specify the
component’s parent component. Component inheritance
is discussed in Chapter 3.
The <%attr>
block may contain any keys that
you want, as the variables defined in this block are not used by
Mason but may be used in your code. Its contents are available by
calling the object’s attr( )
method and giving the desired key as the argument. See Chapter 5 for the details.
<%flags> inherit => '/some/other/component' </%flags> <%attr> color => "I'm so blue" size => 'mucho grande' </%attr> My color: <% $m->base_comp->attr('color') %>
There is one other important difference between flags and attributes: flags refer to only the current component, whereas attributes are part of Mason’s inheritance scheme, discussed in Chapter 5.
<%def> and <%method> blocks
These two blocks use a syntax slightly different from any other Mason
block because their contents are, in turn, components. The
<%def>
block contains a
subcomponent, an embedded component that can be
called via the normal Mason component calling syntax. A
<%method>
block also contains an embedded
component, but one that may be inherited by a
component’s children.
<%def>
and
<%method>
blocks require a name in the
initial tag. In the following example, a subcomponent named
.make_a_link
is defined:
<%def .make_a_link> <a href="<% $url %>"><% $text %></a> <%args> $path %query => ( ) $text </%args> <%init> my $url = ... </%init> </%def>
The name of a subcomponent or method may contain alphanumerics,
underscores ( _
), dashes (
-
), or periods (
.
). Customarily, a period is the
first character of subcomponent names, in order to distinguish them
from nonembedded components. Methods generally do not follow this
convention; they have names without leading periods.
The main difference between subcomponents and methods is simply that subcomponents are visible only within the component in which they are defined, whereas methods are visible outside of the component and can be inherited via Mason’s component inheritance mechanism. Subcomponents and methods are covered in Chapter 5.
<%shared> blocks
This block also contains Perl code. Code in this block is executed
once per request, before the <%init>
block,
but unlike in an <%init>
block, the
variables declared in this block are in scope both in the
component’s main body and in any subcomponents or
methods it may contain. This is useful for sharing a common chunk of
code between all the parts of a single component. The uses of this
block are discussed in Chapter 5.
Escaping a Newline
When using Mason, you may find that you want to suppress a newline in your text. A typical example is this:
<pre> I am % if ($height < 5) { not % } elsif ( $height < 5.75 ) { not very % } elsif ( $height > 6.25 ) { very % } tall </pre>
This will generate the following output if $height
is less than 5:
<pre> I am not tall </pre>
The newlines in the output are not desirable but are unavoidable
because of the need for the Perl code to exist on separate lines.
Mason therefore provides the ability to get rid of a newline simply
by preceding it with a backslash ( \
).
If we rewrote the preceding example with escaped newlines, it would look like this:
<pre> I am\ % if ($height < 5) { not\ % } elsif ( $height < 5.75 ) { not very\ % } elsif ( $height > 6.25 ) { very\ % } tall </pre>
Given this, the output for a $height
less than 5
would then be:
<pre> I am not tall </pre>
This example could be redone on a single line using multiple
<%perl>
blocks, but it would be pretty
hideous looking.
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.
<%args> Block Revisited
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.
%ARGS
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
%ARGS
. This hash
contains all of the arguments with which the component was called.
One point of confusion for those new to Mason is the difference
between %ARGS
and the
<%args>
block. The %ARGS
hash contains the arguments exactly as they were
passed to a component, whether or not they are
declared in the <%args>
block. The keys of
the %ARGS
hash do not contain the Perl sigils
($
, @
, or
%
). An argument declared as
$color
in the <%args>
block would therefore be available via
$ARGS{color}
. Any assignment of defaults by the
<%args>
block is not visible in
%ARGS
; the values are given exactly as they were
passed.
In addition, the %ARGS
hash is always
present,[9] but the
<%args>
block is optional.
If you are expecting input with a large number of similarly named
items, such as input1
,
input2
, and so on through
input20
, declaring all of them in
an <%args>
block may be a bit unwieldy. In
this case, the %ARGS
hash can be quite handy.
%ARGS
is also useful if you expect arguments with
names that cannot be used for Perl variables. For example, when
submitting a web form by clicking on an image named
submit
, the browser will generate
two additional form values, called
submit.x
and
submit.y
. You cannot have a Perl
variable named $submit.x
, so the only way to get
at this argument is to check $ARGS{'submit.x'}
.
There are other ways to retrieve the arguments passed to a component, which are discussed in Chapter 4.
%ARGS Versus @_
The Mason tradition has always been to use named arguments. However,
for simple components, you may prefer to use @_
to
access the
arguments, just as in Perl
subroutines. There are several caveats here. If your component
contains an <%args>
section, Mason expects
it to receive an even number of arguments in @_
so
that it can assign @_
to %ARGS
.
If it receives an odd number of arguments, a fatal error will occur.
But regardless of how arguments are passed, @_
is
always available in components.
So the following pieces of code are near-identical when a component receives an even number of arguments:
% foreach (sort %ARGS) { <% $_ %> % } % foreach (sort @_) { <% $_ %> % }
Argument Examples
Let’s take a look at a number of scenarios involving
argument passing, first via an HTTP URL query
string and then via an internal component call. Then we will see how
this interacts with the component’s
<%args>
block and the
%ARGS
hash.
Arguments submitted via POST and GET requests are treated in exactly the same way, and if both are present they are merged together before the component is called.
Let’s assume that the component being called
contains this <%args>
block:
<%args> $colors @colors %colors </%args>
For each example, we show you two ways to call that component. The first is via an HTTP query string, which is how a component is called to generate a web page. The second is via a component call tag, as a component would be called from another Mason component.
-
/some/component?colors=blue<& /some/component, colors => 'blue' &>
In both cases,
$colors
is the string “blue” and@colors
is a single-element array containing('blue')
. In addition,$ARGS{colors}
would be the string “blue” as well.This component will die when it is called, however, because Mason does not allow you to assign an odd number of elements to a hash, so the assignment to
%colors
is fatal.-
/some/component?colors=blue&colors=red&colors=green<& /some/component, colors => [ 'blue', 'red', 'green' ] &>
Again the URL and internal example give the same result. The
$colors
variables contains a reference to a three-element array,['blue',
'red',
'green']
. This time,$ARGS{colors}
contains the same three-element array reference as$colors
and the@colors
array contains a three-element array with those same elements.Again, assigning an odd number of elements to the
%colors
hash causes a fatal error.-
/some/component?colors=blue&colors=cyan&colors=green&colors=mint <& /some/component, colors => [ 'blue', 'cyan', 'green', 'mint' ] &>
Now,
$colors
contains a reference to a four-element array, and the@colors
array has four elements as well. Finally, the assignment to%colors
works without an error and will result in a hash containing(
'blue'=>'cyan','green'=>'mint'
).$ARGS{colors}
contains the same array reference as$colors
.-
<& /some/component, colors => { blue => 'cyan', green => 'mint' } &>
This set of arguments isn’t representable with a query string, because there’s no way to indicate that the arguments are structured in a hash via a web request.
In this call,
$colors
contains a reference to a hash, not an array, though the@colors
array contains four elements, just as in the previous example. The%colors
hash is likewise the same as the previous example. Now, the$ARGS{colors}
hash entry contains a hash reference.
This discrepancy in how hash assignments are treated, depending on
the way a call is made, is probably not too important because Mason
simply does the right thing based on the contents of
%args
. You declare %colors
as
an argument, and as long as an even number of
colors
elements are passed in, you get a
hash.
Arguments via Component Calls
When calling another component that expects named
arguments,
it is important to remember that arrays and hashes need to be passed
as references. For example, a component named
/display
with an
<%args>
block like this:
<%args> @elements %labels </%args>
Should be called like this:
<& /display, elements => \@some_data, labels => \%data_labels &>
Mason will do the right thing and translate the references back into
an array and a hash in the /display
component.
Arguments via HTTP Requests
When using Mason to make a web application, you must understand the details of how external HTTP requests are converted into component calls. Specifically, we are interested in how query string and POST parameters are converted into arguments.
These requests are expected to be in the standard name/value pair
scheme used by most web interfaces. If a parameter is given only once
(i.e., component?foo=1&bar=2
), it will be
present in the %ARGS
hash as a simple scalar,
regardless of how it is declared in the
<%args>
section.
If a parameter is declared as a scalar ($foo
) but
given multiple values (i.e.,
component?foo=1&foo=2
), the
$foo
parameter will end up containing a reference
to an array, as will $ARGS{foo}
. Future versions
of Mason may provide the ability to coerce these arguments into
specific data structures.
If a parameter is declared as an array (@foo
), it
will contain zero or more values depending on what is in the query
string and/or POST data. A hash is treated more or less like an
array, except that giving a parameter declared as a hash an odd
number of values will cause a fatal error.
One caution: the key/value associations in a declared hash are
determined by the order of the input. Let’s assume
we have a component with this <%args>
block:
<%args> %foo </%args>
A request for component?foo=1&foo=2
will
result in a different hash from
component?foo=2&foo=1
. This
isn’t generally a problem because you can usually
control the order of the arguments by their position in an HTML form.
However, neither the HTTP or HTML specifications specify that a
client needs to respect this ordering when submitting the form, and,
even if it were, some browsers would probably screw it up
eventually.[10]
It’s not a great idea, therefore, to use hashes as
arguments in a top-level component that may be called via an HTTP
request generated by a form. When you can control the query string
yourself, this is not a
problem.
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.
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.
$m
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.
$r
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.
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.
<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.
[6] For the curious, these issues are covered in Chapter 3, Chapter 5, and Chapter 12.
[7] The
HTML::Mason::Request
object provides access to
several properties and methods concerning the currently executing
chain of components. It is treated in detail in Chapter 4.
[8] Component objects are
returned by several of the HTML::Mason::Request
and HTML::Mason::Interp
methods, covered in detail
in Chapter 4 and Chapter 6.
[9] Unless the component is called with an odd number of arguments. See the next section for details on this exception.
[10] We know of no browsers that actually screw it up, but surely there must be some out there. Browsers have a history of simply making up their own unique behaviors, even when there is a specification.
Get Embedding Perl in HTML with Mason now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.