Zero to Mojolicious, Part 2: Content-Wrapping Filter Templates

Tags:

In the previous installment, we built a basic site with Zurb Foundation.

We were able to split the main HTML wrapper into a layout file, but our index.html that we passed to the render function had to have the whole rest of the row and column divisions. We really want to just have our "content" consist only of the body of each page, and let the template system take care of the row/column site structure and any navigation or sidebars.

Doing this highlighted how different Mojolicious is from using something like PHP, or even Ruby on Rails. In using, or trying to use those, I spent more time getting frustrated at PHP's inconsistencies (how many different kinds of 'equal' are there?) or ripping apart Rails (there is One True way to speak to a database, and your existing schema ain't it) and being frustrated at Ruby's zaniness (zero is true!) than I did actually getting anything done.

Glen Hinkle (tempire) comments on this in a post to the Mojolicious group [groups.google.com, 11 November 2011]:

This is a matter of the tools built on top of the platform, rather than the platform itself. Ruby's Rails distributes these sort of tools and touts them as the hotness, but in practicality, they don't provide much value…

Let's say you have a tool that creates your CRUD interface and boilerplate. It looks great, because look at all the work it saved you from doing! In reality, it's saved you nothing. When you customize your app, you're going to have to re-organize and/or re- write every piece of code/HTML. Guaranteed. These tools are a red herring - they're simply not going to save you any time at all.

For example: You create a resource. Oh, but you need to verify the data. Except, how you verify depends on the nature of your data. That's ok, you can just take out the boilerplate and put your own code in. Except, it ties in with the way it stores data in the database. That's ok, you can replace that with your own code. Except, that ties in with the way you've chosen to display your data. That's ok, you can replace the templates with your own code. Except, you need to show your templates in a specific way so that it makes sense. That's ok, you can replace...

In the end, boilerplate templates limit you more than save you time…

Attempt to create boilerplate on any platform, and you'll see how useless it is after the 3rd web app, wherein maintaining the boilerplate was more effort than creating the app itself. If it's not, you don't actually want a custom web app, you want a CMS.

Once I realized that Mojo is just Perl inside, and all the idioms are just old-fashioned syntactic sugar, everything started to become clear.

The very first thing we need to do to work in the "Foundation style" is to build a hierarchy of nested sub-templates. Specifically, we want rows and columns in a master template and then use the standard [content](http://mojolicio.us/perldoc/Mojolicious/Plugin/DefaultHelpers#content) mechanism to drop text into the body.

With Mojolicious now, in an ep (Encapsulated Perl) file, you can specify:

% layout 'template_name'

and that layout can then say:

% extends 'subtemplate_name'

but be careful: the latter does not let you nest; the 'extending' template's content is discarded. (Unless, that is, there has been no content yet defined: an unlikely situation.)

So let's take the "Lite app" from Part I and add the lines shown in bold here:

#!/usr/bin/env perl
use Mojolicious::Lite;

get '/' => sub {
 my $c = shift;
 $c->render('index',
 msg => 'Welcome to the Mojolicious real-time web framework!');
};

app->start;
__DATA__

@@ index.html.ep
<strong>% layout 'site_design';</strong>
% title 'Welcome';
<div class="row">
 <h2><%= $msg %></h2>
 <div class="small-2 columns">2 columns</div>
 <div class="small-10 columns">10 columns</div>
</div>
<div class="row">
 <div class="small-3 columns">3 columns</div>
 <div class="small-9 columns">9 columns</div>
</div>

<strong>@@ layouts/site_design.html.ep</strong>
<strong>% extends 'layouts/zurb';</strong>

<strong>This text does not appear.</strong>

@@ layouts/zurb.html.ep
<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="utf-8">
 <!-- Zurb Foundation stuff -->
 <meta name="viewport" content=
 "width=device-width, initial-scale=1.0">
 <link rel="stylesheet" href="/css/normalize.css">
 <link rel="stylesheet" href="/css/foundation.min.css">
 <script src="/js/vendor/modernizr.js"></script>
 <!-- end Zurb -->
 <title><%= title %></title>
 </head>
 <body>
 <script src="/js/vendor/jquery.js"></script>
 <script src="/js/foundation.min.js"></script>
 <script>
 $(document).foundation();
 </script>
<%= content %>
 </body>
</html>

Now the index HTML calls for the site_design template, which in turn extends our Zurb Foundation template. The wrinkle is: In order to nest templates, we must do this a bit differently.

As of Mojolicions 6.01, the built-in content helper functions are:

content
stash
content_for
content_with

The first lets us define the content stash (but, if that contains anything at all, the function has no effect); the second function returns the value of any stash including content; content_with replaces the content (which we will use to wrap the content); and content_for appends to the content stash.

NOTE: An earlier version of this article led to the addition of content_with in Mojolicious core. (See

[

this commit ](https://github.com/kraih/mojo/commit/275f0e75bf350d40542a67e5a9eaef84eaa08236) .)

Let's take a bit of a sidetrack for a little understanding of what is really going on. According to "Rendering" in the Mojolicious Guides,

The renderer is a tiny black box turning stash data into actual responses utilizing multiple template systems and data encoding modules.

Well that's all wonderful, but what does the black box do exactly? In Mojolicious/Renderer.pm in your Perl installation, you can see the loop in the render function, just below the comment:

`

sub render … # Extends `

The extends loop there descends through the template definition, which has the effect of rendering each of the include, extends, and layout calls. Again, do realize that in your template,

% layout 'site_design';

is a simple Perl function call, not some kind of magic. Understand too that the layout's processing is deferred until after the remainder of the containing template.

Back to the story. We write our index.html to declare what we want in each of the containers: header, footer, sidebar, and then the content, leaving the details of the rows and columns to our nested site layout template, as follows (new parts in bold):

#!/usr/bin/env perl
use Mojolicious::Lite;

get '/' => sub {
  my $c = shift;
  $c->render('index',
         msg => 'Welcome to the Mojolicious real-time web framework!');
};

app->helper(content_with => sub {
  my ($c, $name, $content) = @_;
  return unless defined $content;
  my $hash = $c->stash->{'mojo.content'} ||= {};
  return $hash->{$name} = 
    ref $content eq 'CODE' ? $content->() : $content;
});

app->start;
__DATA__

@@ index.html.ep
% layout 'site_design';
% title 'Welcome';
<strong>% content header => begin
<h2><%= $msg %></h2>
% end
% content footer => begin
<h5>Copyright ⓒ <%= ((localtime())[5]+1900) %></h5>
% end
% content sidebar => begin
<ul>
  <li>Sidebar item 1</li>
  <li>Sidebar item 2</li>
</ul>
% end

This plain text is the content − the body of the page.
</strong>
<strong>@@ layouts/site_design.html.ep
% extends 'layouts/zurb';

% content_with content => begin
<div class="row">
  <div class="large-12 columns"><%= content 'header' %></div>
</div>
<div class="row">
  <div class="small-3 columns"><%= content 'sidebar' %></div>
  <div class="small-9 columns"><%= content %></div>
</div>
<div class="row">
  <div class="large-12 columns"><%= content 'footer' %></div>
</div>
% end</strong>

@@ layouts/zurb.html.ep
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <!-- Zurb Foundation stuff -->
    <meta name="viewport" content=
       "width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/css/normalize.css">
    <link rel="stylesheet" href="/css/foundation.min.css">
    <script src="/js/vendor/modernizr.js"></script>
    <!-- end Zurb -->
    <title><%= title %></title>
  </head>
  <body>
    <script src="/js/vendor/jquery.js"></script>
    <script src="/js/foundation.min.js"></script>
    <script>
      $(document).foundation();
    </script>
<%= content %>
  </body>
</html>

Note the little trick for displaying the current year: We use the list-returning version of localtime() but only want the year element (the number of years since 1900) and print all four digits.:

<h5>Copyright ⓒ <%= ((localtime())[5]+1900) %></h5>

Thanks to everyone on #mojo IRC, particularly jberger.

Next time, we will start adding database functionality. Meantime, have fun with easy Foundation enabled Mojo sites!