Templating Modules are a bit like editors. Every web application developer has a favourite one. And every template system is someone's favorite.
Mine is Mason. But not because the Perl MVC tutorials are full of examples using Mason. Not because it's the fastest (use xSlate if you want to trade speed for flexibility). Not because it's the most popular. It's my favourite for a very plain reason: It makes me more productive and allows me to develop web GUIs using all the powerful features a programmer should biterly miss if they are taken away. That includes writing Perl code :P
I never heard of a business that went down because they didn't have fast enough CPUs, so I'm not fussy about trading a few CPU cycles for elegance, ease and speed of development.
2. A bit of myth busting
● Mason is old
● Mason is a viewcontroller
● Mason is too complex
● Mason is slow
● Mason uses embedded Perl
3. Mason is old
Mason 1 is old (HTML::Mason)
Mason 2 released in 02/2011
Complete Moosified rewrite
4. Mason is a viewtroller
Kind of true for Mason 1
But that was 10 years ago
Mason 2 is a pure templating system
The controller bit has been moved to Poet
5. Mason is too complex
Augmentation
Inheritance
Composition
Method modifiers
Dynamic filters
6. Mason is too complex
Augmentation
Inheritance
Composition
Method modifiers
Dynamic filters
But wait..
8. Mason is slow
Hum, well...
Compared to TT (as complex as TT can take
benchmark)
Rate Mason TT
Mason 909/s -- -53%
TT 1923/s 112% --
9. Mason is slow - but
Power comes with a price tag
Experience shows it scales very well with
complexity
10. Mason is slow - but
Power comes with a price tag
Experience shows it scales very well with
complexity
The benchmark I wrote is not bigfat.
Have a look:
https://bitbucket.org/jeteve/mason-pres/
11. Mason is slow - but honestly
Do we use Perl because it's faster than X?
15. The basics - Embedded code
% while( my $product = $products->next() ){
<p>Buy our great
<% $product->name() | H %>.
It's only <% $product->price() | H %>
</p>
%}
With DefaultFilter set to H:
<% $product->name() %>
26. Augmentation - Become specific
Evaluates to
<html>
<head><title>Site</title></head>
<body>
<div class="product">
<h1>Lathe</h1>
</div>
<body>
</html>
27. Augmentation - Wanna go bare?
/products/baremetal.mc
<%flags>
extends => undef
</%flags>
<h1>Some bare content</h1>
Evaluates to
<h1>Some bare content</h1>
40. Actually, I want the menu in the error
pages
No problem:
/errors/Base.mc
<%flags>
extends => '/layout/Base.mc'
</%flags>
<%augment wrap>
<div class="error"><% inner() %></div>
</%augment>
57. Filters - Make your own
package My::Mason::Filters;
use Mason::PluginRole;
method Iterate($on){
Mason::DynamicFilter->new(
filter => sub{ my ($yield) = @_;my $txt = '';
while( my $next = $on->next() ){
$txt .= $yield->($next); }
return $txt;
});}
58. Filters - Make your own
/Base.mc
<%class>
with My::Mason::Filter;
</%class>
/anywhere
% $.Iterate($resultset){{
% my ($result) = @_;
This is result <% $result->name() %>!
%}}
59. Filters - As component
/comp/pager.mi
<%class>
has 'on' => ( isa => 'DBIx::Class::Resulset' );
has 'page' => ( isa => 'Int' , default => 1 );
has 'yield';
</%class>
% my $rs=$.on->search({} , {page => $.page});
<div class="pager">
.. Do stuff with $rs->page() ..</div>
60. Filters - As component
/comp/pager.mi .. Continued
%# Some paging was output
% $.Iterate($rs){{
% my $stuff = $_[0];
<% $.yield->($stuff) %>
% }}
%# Some other paging maybe?
61. Let's use our pager
/products/index.mc
<$class>
has 'products' => ( isa => 'DBIx::Resultset' );
</$class>
% $.CompCall('/comp/page.mi',on=>$.products)
{{
% my ( $product ) = @_;
Product <% product->name() %>
% }}
62. Filters can be curried
<%class>
has 'lang';
has 'Translate' ( lazy_build => 1 );
sub _build_Translate{
my ($self) = @_;
$self->TranslateIn($self->lang));}
</%class>
% $.Translate(){{
Some Text
% }}
63. Filters - One more nice one
% $.Cache($key , '10 minute') {{
<div class="sluggish">
....
</div>
% }}
Combine with currying for cleaner code :)
65. Mason helps writing clean code
Strict by default
Enforce type consistency a-la Moose
Enforce stash content (With Catalyst)
Minimal global variables
Easy unit testing
66. Mason is powerful
Code the view like a programmer with
inheritance, augmentation, method modifiers,
dynamic filters, currying ..
No change of mindset required
Changes are simple and consistent
Writing a new pages is trivial
67. Mason is extensible
Base class injection.
my $mason = Mason->new(base_*_class =>
'MyApp::Mason::*Subclass' );
Or Role based Plugins (and Plugins Bundles)
For instance: Mason::Plugin::Cache
68. Reference
In order of preference
● MasonHQ: http://www.masonhq.com/
● Cpan: Mason
● Cpan: Catalyst::View::Mason2
● Mailing list
● Jerome :P
69. Give it a go
$ sudo apt-get install libmason-perl
$ echo "Hello world" > mason/index.mc
$ mason.pl mason/index.mc
$ ## In catalyst
$ sudo cpan -i Catalyst::View::Mason2