CHP-5>

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.


Subcomponents

CHP-5-SECT-1>

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> <%def> block:def block> block is called a subcomponent subcomponents> , 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>

Since a subcomponent is visible only to the component that defines, and because it has all the capabilities that regular components have, you may think of subcomponents as roughly analogous to privately scoped anonymous subroutine __FOX_NLBF__> references in Perl.


Creating Components on the Fly

CHP-5-SECT-2>

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 components;creating> component text.

For these situations, the Mason interpreter provides the make_component( ) make_component( ) method> 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 __FOX_NLBF__> 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 __FOX_NLBF__> 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( )__FOX_NLBF__> method in Perl's eval eval {} block (Perl)> {} block, and check $@ after the method call.


Sharing Data Among Component Sections

CHP-5-SECT-3>

By default, the scope of variables created within an <%init> <%init> blocks:init blocks> blocks;<%init>> block, a Perl line, or any other Mason markup sections is the entire components;sharing data among> component. This is tremendously convenient, because it lets you initialize variables in the <%init> block, then use their values across the rest of the component. So most of the time, the techniques discussed in this section won't be needed.

There is one limitation to variables created within the <%init> section, however: their values won't be seen by any subcomponents you might define. This is true for two reasons. First, the subcomponents may themselves contain an <%init> section, so the relevance of the main component's <%init> section isn't necessarily clear. Second, a subcomponent may actually be a method (more on this later), in which case it is accessible to the outside world without first calling the main component, so the <%init> section never has a chance to run.

Sometimes you need to share data between a component and its subcomponents, however, and for these situations Mason provides the <%shared> <%shared> block:shared block> <%once> block:once block> blocks;<%shared>>

blocks;<%once>>

and <%once> blocks. A <%shared> block runs before the main component or any of its methods or subcomponents and may run initialization code. Any variables created here will be visible to the entire main component and any of its subcomponents, including the main component's <%init> section, if any. The <%once> block is similar -- the only difference is that code in the <%once> block won't run every time the component is called. It will run only when the component itself is loaded. The initialized values will remain intact for the lifetime of the component object, which may be until you make changes to the component source file and Mason reloads it or until the web server child expires and gets replaced by a new one.

A <%shared> section is great when a component and its subcomponents have a tight relationship and may make complicated use of shared data. In contrast, <%once> sections are useful for caching values that change infrequently but may take a long time to compute. See A<CHP-5-EX-1>Example 5-1.