[Catalyst] MasonSite helper for Mason view

Michael Gray mjg17 at eng.cam.ac.uk
Fri Apr 28 11:42:22 CEST 2006


I've spent the last day hacking together a Mason equivalent of the 
TTSite helper.  I think TTSite is useful; I hope this will be too.

The mini-site is my mix of the TTSite example, and 
various practices outlined in the Mason Book and elsewhere.  Rather than 
require hand modifications to the Root controller, I've chosen to have 
MasonSite create a MasonEG controller to demo the mini-site.

It should be sufficent to:

 $ # install the patched Catalyst::View::Mason module first
 $ catalyst.pl TryMasonSite
 $ cd TryMasonSite/
 $ ./script/trymasonsite_create.pl view Mason MasonSite
 $ ./script/trymasonsite_server.pl
 $ firefox http://localhost:3000/masoneg

I've also patched Catalyst::View::Mason to permit the Mason 
allow_globals config option to be specified, augmenting it with $c, 
$base and $name.

All of this is attached as a patch against Catalyst::View::Mason version 
0.8.

I'd be delighted if people could try it and give me feedback.  Assuming 
no major howls, I'll also announce it on the Mason list.

Best

-- 
Michael
-------------- next part --------------
diff -Naur Catalyst-View-Mason-0.08/Changes Catalyst-View-Mason-0.09/Changes
--- Catalyst-View-Mason-0.08/Changes	2005-08-19 14:20:26.000000000 +0000
+++ Catalyst-View-Mason-0.09/Changes	2006-04-28 09:14:37.000000000 +0000
@@ -1,5 +1,9 @@
 Revision history for Perl extension Catalyst::View::Mason.
 
+0.09  Thu Apr 27 17:58:00 2006
+        - Added MasonSite helper (Michael Gray)
+        - Allow comp_globals to be set in addition to $c, $base, $name
+
 0.08  Xxx Xxx 00 00:00:00 2005
         - Fixed Content-Type
 	- Stringify root.
diff -Naur Catalyst-View-Mason-0.08/MANIFEST Catalyst-View-Mason-0.09/MANIFEST
--- Catalyst-View-Mason-0.08/MANIFEST	2005-08-19 14:20:26.000000000 +0000
+++ Catalyst-View-Mason-0.09/MANIFEST	2006-04-28 09:14:37.000000000 +0000
@@ -2,6 +2,7 @@
 Changes
 lib/Catalyst/View/Mason.pm
 lib/Catalyst/Helper/View/Mason.pm
+lib/Catalyst/Helper/View/MasonSite.pm
 Makefile.PL
 MANIFEST			This list of files
 META.yml
diff -Naur Catalyst-View-Mason-0.08/META.yml Catalyst-View-Mason-0.09/META.yml
--- Catalyst-View-Mason-0.08/META.yml	2005-08-19 14:20:26.000000000 +0000
+++ Catalyst-View-Mason-0.09/META.yml	2006-04-28 09:14:37.000000000 +0000
@@ -1,20 +1,28 @@
 ---
 name: Catalyst-View-Mason
-version: 0.08
+version: 0.09
 author:
   - |-
     Andres Kievsky C<ank at cpan.org>
     Sebastian Riedel C<sri at cpan.org>
     Marcus Ramberg
+    Michael Gray C<mjg at cpan.org>
 abstract: Mason View Class
 license: perl
+resources:
+  license: http://dev.perl.org/licenses/
 requires:
   Catalyst: 5
   HTML::Mason: 0
 provides:
   Catalyst::Helper::View::Mason:
     file: lib/Catalyst/Helper/View/Mason.pm
+  Catalyst::Helper::View::MasonSite:
+    file: lib/Catalyst/Helper/View/MasonSite.pm
   Catalyst::View::Mason:
     file: lib/Catalyst/View/Mason.pm
-    version: 0.08
-generated_by: Module::Build version 0.25
+    version: 0.09
+generated_by: Module::Build version 0.28
+meta-spec:
+  url: http://module-build.sourceforge.net/META-spec-v1.2.html
+  version: 1.2
diff -Naur Catalyst-View-Mason-0.08/Makefile.PL Catalyst-View-Mason-0.09/Makefile.PL
--- Catalyst-View-Mason-0.08/Makefile.PL	2005-08-19 14:20:26.000000000 +0000
+++ Catalyst-View-Mason-0.09/Makefile.PL	2006-04-28 09:14:37.000000000 +0000
@@ -17,15 +17,15 @@
       
       # Save this 'cause CPAN will chdir all over the place.
       my $cwd = Cwd::cwd();
-      my $makefile = File::Spec->rel2abs($0);
       
-      CPAN::Shell->install('Module::Build::Compat')
-	or die " *** Cannot install without Module::Build.  Exiting ...\n";
+      CPAN::Shell->install('Module::Build::Compat');
+      CPAN::Shell->expand("Module", "Module::Build::Compat")->uptodate
+	or die "Couldn't install Module::Build, giving up.\n";
       
       chdir $cwd or die "Cannot chdir() back to $cwd: $!";
-      exec $^X, $makefile, @ARGV;  # Redo now that we have Module::Build
     }
-    use lib '_build/lib';
+    eval "use Module::Build::Compat 0.02; 1" or die [email protected];
+    
     Module::Build::Compat->run_build_pl(args => \@ARGV);
     require Module::Build;
     Module::Build::Compat->write_makefile(build_class => 'Module::Build');
diff -Naur Catalyst-View-Mason-0.08/lib/Catalyst/Helper/View/MasonSite.pm Catalyst-View-Mason-0.09/lib/Catalyst/Helper/View/MasonSite.pm
--- Catalyst-View-Mason-0.08/lib/Catalyst/Helper/View/MasonSite.pm	1970-01-01 00:00:00.000000000 +0000
+++ Catalyst-View-Mason-0.09/lib/Catalyst/Helper/View/MasonSite.pm	2006-04-28 09:14:37.000000000 +0000
@@ -0,0 +1,506 @@
+package Catalyst::Helper::View::MasonSite;
+
+use strict;
+
+=head1 NAME
+
+Catalyst::Helper::View::MasonSite - Helper for Mason view which builds a
+skeleton web site
+
+=head1 SYNOPSIS
+
+    script/create.pl view Mason MasonSite
+
+=head1 DESCRIPTION
+
+This helper module creates a Mason View module, and also creates an
+simple Mason framework and example pages to get you started.
+
+The Mason framework is created under your project's F<root> directory
+within subdirectories F<system> and F<template>, and the example
+pages within subdirectory F<masoneg>.  A controller called C<MasonEg> 
+is also created, so that you can visit C</masoneg> to view the example
+pages when you run your Catalyst application.
+
+=head2 METHODS
+
+=head3 mk_compclass
+
+=cut
+
+sub mk_compclass {
+    my ( $self, $helper, @args ) = @_;
+    my $file = $helper->{file};
+    $helper->render_file( 'compclass', $file );
+    $self->mk_eg_controller( $helper, @args );
+    $self->mk_templates( $helper, @args );
+}
+
+=head3 mk_eg_controller
+
+=cut
+
+sub mk_eg_controller {
+    my ( $self, $helper ) = @_;
+    my $base = $helper->{base};
+    my $appdir = File::Spec->catdir( split /\:\:/, $helper->{app} );
+    my $c_type = ($helper->{type} eq $helper->{long_type}) 
+	? 'Controller' 
+	: 'C';
+    my $file = File::Spec->catfile( $base, 'lib', $appdir, $c_type,
+				    'MasonEG.pm' );
+    $helper->render_file( 'eg_controller', $file, 
+			  { c_type => $c_type } );
+}
+
+=head3 mk_templates
+
+=cut
+
+sub mk_templates {
+    my ( $self, $helper ) = @_;
+    my $base = $helper->{base};
+    my %dir;
+    foreach my $d (qw( masoneg system template )) {
+	my $dir_path = File::Spec->catfile( $base, 'root', $d );
+	$helper->mk_dir($dir_path);
+	$dir{$d} = $dir_path;
+    }
+
+    foreach my $file (qw(
+			 autohandler
+			 intro.mas
+			 message.mhtml
+			 more_details.mas
+			 welcome.mhtml
+			 )) {
+        $helper->render_file( "config_masoneg_$file",
+            File::Spec->catfile( $dir{masoneg}, $file ) );
+    }
+
+    foreach my $file (qw(
+			 colours.mas
+			 handler
+			 links.mas
+			 )) {
+        $helper->render_file( "config_system_$file",
+            File::Spec->catfile( $dir{system}, $file ) );
+    }
+
+    foreach my $file (qw(
+			 handler
+			 mason_site.css
+			 )) {
+        $helper->render_file( "config_template_$file",
+            File::Spec->catfile( $dir{template}, $file ) );
+    }
+}
+
+=head1 SEE ALSO
+
+L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
+L<Catalyst::Response>, L<Catalyst::Helper>
+
+=head1 AUTHOR
+
+Andres Kievsky
+Sebastian Riedel, C<sri at oook.de>
+Michael Gray
+
+=head1 LICENSE
+
+This library is free software . You can redistribute it and/or modify it under
+the same terms as perl itself.
+
+=cut
+
+1;
+
+__DATA__
+
+__compclass__
+package [% class %];
+
+use strict;
+use base 'Catalyst::View::Mason';
+
+# This sets up the global variable '$site'
+# for use in the example Mason framework.
+#
+__PACKAGE__->config->{allow_globals} = ['$site'];
+
+=head1 NAME
+
+[% class %] - Mason View Component
+
+=head1 SYNOPSIS
+
+See L<[% app %]>
+
+=head1 DESCRIPTION
+
+Catalyst MasonSite View
+
+=head1 AUTHOR
+
+[% author %]
+
+=head1 LICENSE
+
+This library is free software . You can redistribute it and/or modify it under
+the same terms as perl itself.
+
+=cut
+
+1;
+
+__eg_controller__
+package [% app %]::[% c_type %]::MasonEG;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+=head1 NAME
+
+[% app %]::[% c_type %]::MasonEG - Catalyst Controller
+
+=head1 SYNOPSIS
+
+See L<[% app %]>
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=head2 message
+
+=cut
+
+sub message : Local {
+    my ( $self, $c ) = @_;
+    $c->stash->{template} = 'masoneg/message.mhtml';
+    $c->stash->{message}  ||= $c->req->param('message') || 'No message';
+}
+
+=head2 default
+
+=cut
+
+sub default : Private {
+    my ( $self, $c ) = @_;
+    $c->stash->{template} = 'masoneg/welcome.mhtml';
+}
+
+=head2 end
+
+Not needed if you have configured the DefaultEnd plugin
+
+=cut
+
+sub end : Private {
+    my ( $self, $c ) = @_;
+
+    # Forward to View unless response body is already defined
+    $c->detach( $c->view('Mason') ) unless $c->response->body;
+}
+
+=head1 AUTHOR
+
+[% author %]
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;
+
+__config_masoneg_autohandler__
+<%doc>
+=head1 Autohandler
+
+Layout and common methods for this application.
+
+</%doc>
+%#
+<%flags>
+ inherit => '../template/handler'
+</%flags>
+%#
+<%method title>
+ Catalyst/Mason View
+</%method>
+%#
+<div id="header">
+ <h1 class="title"><& SELF:title, %ARGS &></h1>
+</div>
+
+<div id="content">
+% $m->call_next;
+</div>
+
+<div id="footer">
+ <div id="copyright">&copy; <% $site->{copyright} %></div>  
+</div>
+__config_masoneg_intro.mas__
+%# $name is provided as a global variable, along with $c and $base,
+%# by Catalyst::View::Mason
+%#
+<p>
+  Yay!  You're looking at a page served by the
+  <strong>Catalyst::View::Mason</strong> plugin module and generated by 
+  its <strong>MasonSite</strong> helper script, running as part of the
+  Catalyst application named "<% $name %>".
+</p>
+__config_masoneg_message.mhtml__
+<%args>
+ $message
+</%args>
+%#
+<%method title>
+ <& PARENT:title &> - Message!
+</%method>
+%#
+<& intro.mas &>
+<p>
+  We have a message for you: <span class="message"><% $message %></span>.
+</p>
+<p>
+  Why not try updating the message?  Go on, it's really exciting, honest!
+</p>
+<form action="<% $c->uri_for('message') %>"
+      method="POST" enctype="application/x-www-form-urlencoded">
+ <input type="text" name="message" value="<% $message %>" />
+ <input type="submit" name="submit" value=" Update Message "/>
+</form>
+<p>
+ Or go back to the Mason
+ <a href="<% $c->uri_for('welcome') %>">Welcome Page</a>.
+</p>
+<hr>
+<& more_details.mas &>
+__config_masoneg_more_details.mas__
+<h2>More details:</h2>
+<ul>
+% foreach my $l (@$links) {
+ <li>
+  <a href="http://<% $l->{urn} %>"><% $l->{desc} %></a>
+%   if ($l->{supp}) {
+  - <% $l->{supp} %>
+%   }
+ </li>
+% }
+</ul>
+%#
+<%init>
+ my $links = $site->{links};
+</%init>
+__config_masoneg_welcome.mhtml__
+<%method title>
+ <& PARENT:title &> - Welcome!
+</%method>
+<& intro.mas &>
+<p>
+  This is the Mason welcome page.  Why not try the equally-exciting 
+  <a href="<% $c->uri_for('message') %>">Message Page</a>?
+</p>
+<hr>
+<& more_details.mas &>
+__config_system_colours.mas__
+<%doc>
+=head1 Colours
+
+Define some colours for use in our style sheet.
+
+</%doc>
+%#
+<%once>
+   my %rgb = (
+     black  => '#000000',
+     white  => '#ffffff',
+     grey1  => '#46494c',
+     grey2  => '#c6c9cc',
+     grey3  => '#e3e6ea',
+     red    => '#CC4444',
+     green  => '#66AA66',
+     blue   => '#89b8df',
+     orange => '#f08900',
+   );
+
+   my %colours = (
+      page    => $rgb{white},
+      text    => $rgb{grey1},
+      head    => $rgb{grey3},
+      line    => $rgb{orange},
+      message => $rgb{green},
+      error   => $rgb{red},
+   );
+</%once>
+%#
+<%init>
+  $site->{rgb}     = \%rgb;
+  $site->{colours} = \%colours;
+</%init>
+__config_system_handler__
+<%doc>
+=head1 System handler
+
+Under Catalyst, most of what you may have put here will probably end
+up in your Catalyst Controllers.
+
+Since this is the top of the Mason content-wrapping inheritance tree,
+we avoid recursion by explicitly turning off any further autohandler.
+
+</%doc>
+%#
+<%flags>
+ inherit => undef
+</%flags>
+%#
+<%once>
+  # $site is declared as a Mason global variable in 
+  # YourApp::View::Mason
+
+  $site = {
+    copyright => '2006 Your Name Here',
+  };
+</%once>
+%#
+<%init>
+  # Call other config components - do it here rather than in %once 
+  # in case any of them do per-request processing.
+  #
+  $m->scomp('colours.mas');
+  $m->scomp('links.mas');
+
+  # No HTML templating in this pseudo-component so we may as well
+  # move straight on:
+  #
+  $m->call_next;
+
+</%init>
+__config_system_links.mas__
+<%doc>
+=head1 Links
+
+Define some links of interest to the example pages.
+
+</%doc>
+%#
+<%once>
+  my @links = (
+    { urn  => "www.masonhq.com",
+      desc => "Mason HQ"               },
+    { urn  => "www.masonbook.com",
+      desc => "Mason Book",
+      supp => "<em>Embedding Perl in HTML with Mason</em>" },
+    { urn  => "dev.catalyst.perl.org",
+      desc => "Catalyst Wiki"          },
+  );
+</%once>
+%#
+<%init>
+  $site->{links} = \@links;
+</%init>
+__config_template_handler__
+<%doc>
+=head1 Template handler
+
+This sets up the overall structure of our pages and pulls in
+the style sheet.
+
+</%doc>
+%#
+<%flags>
+ inherit => '../system/handler'
+</%flags>
+%#
+<%method title>
+%# Should be provided by a more specific component.
+ NOT SET
+</%method>
+%#
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+  <title><& SELF:title, %ARGS &></title>
+  <style type="text/css">
+   <& mason_site.css &>
+  </style>
+ </head>
+ <body>
+% $m->call_next;
+ </body>
+</html>
+__config_template_mason_site.css__
+<%doc>
+=head1 Style sheet
+
+We process this through Mason to fill in the configured colours.
+
+We don't want it to be wrapped in any way so we turn of 
+compononent inheritance.
+
+</%doc>
+%#
+<%flags>
+ inherit => undef
+</%flags>
+
+html {
+    height: 100%;
+}
+
+body { 
+    background-color: <% $site->{colours}->{page} %>;
+    color: <% $site->{colours}->{text} %>;
+    margin: 0px;
+    padding: 0px;
+    height: 100%;
+}
+
+#header {
+    background-color: <% $site->{colours}->{head} %>;
+    border-bottom: 1px solid <% $site->{colours}->{line} %>;
+}
+
+#footer {
+    background-color: <% $site->{colours}->{head} %>;
+    text-align: center;
+    border-top: 1px solid <% $site->{colours}->{line} %>;
+    position: absolute;
+    bottom: 0;
+    left: 0px;
+    width: 100%;
+    padding: 4px;
+}
+
+#content {
+    padding: 10px;
+}
+
+h1.title {
+    padding: 4px;
+    margin: 0px;
+}
+
+.message {
+    color: <% $site->{colours}->{message} %>;
+}
+
+.error {
+    color: <% $site->{colours}->{error} %>;
+}
+
+hr {
+    color: <% $site->{colours}->{line} %>;
+    background-color: <% $site->{colours}->{line} %>;
+    border: 0;
+    height: 1px;
+    width:  100%;
+}
diff -Naur Catalyst-View-Mason-0.08/lib/Catalyst/View/Mason.pm Catalyst-View-Mason-0.09/lib/Catalyst/View/Mason.pm
--- Catalyst-View-Mason-0.08/lib/Catalyst/View/Mason.pm	2005-08-19 14:20:26.000000000 +0000
+++ Catalyst-View-Mason-0.09/lib/Catalyst/View/Mason.pm	2006-04-28 09:14:37.000000000 +0000
@@ -5,7 +5,7 @@
 use HTML::Mason;
 use NEXT;
 
-our $VERSION = '0.08';
+our $VERSION = '0.09';
 
 __PACKAGE__->mk_accessors('template');
 
@@ -69,6 +69,11 @@
 
 =head1 METHODS
 
+=head3 new
+
+The constructor for the Mason view. Sets up the Mason interpreter, 
+and reads the application config.
+
 =cut
 
 sub new {
@@ -85,10 +90,10 @@
         out_method => \$self->{output},
     );
 
+    push @{ $config{allow_globals} }, qw($c $base $name);
+
     $self->template(
-        HTML::Mason::Interp->new(
-            %config, allow_globals => [qw($c $base $name)],
-        )
+	    HTML::Mason::Interp->new( %config )
     );
 
     return $self;
@@ -165,6 +170,23 @@
 
 =cut
 
+=head1 HELPERS
+
+The L<Catalyst::Helper::View::Mason> and
+L<Catalyst::Helper::View::MasonSite> helper modules are provided to create
+your view module.  There are invoked by the F<myapp_create.pl> script:
+
+    $ script/myapp_create.pl view Mason Mason
+
+    $ script/myapp_create.pl view Mason MasonSite
+
+The L<Catalyst::Helper::View::Mason> module creates a basic Mason view
+module.  The L<Catalyst::Helper::View::MasonSite> module goes a little
+further.  It also creates a simple Mason framework and example pages
+to get you started.  It also creates a controller called C<MasonEG>
+for the example pages, so that you can visit C</masoneg> to view them
+when you run your Catalyst application.
+
 =head1 SEE ALSO
 
 L<Catalyst>, L<HTML::Mason>, "Using Mason from a Standalone Script" in L<HTML::Mason::Admin>
@@ -174,6 +196,7 @@
 Andres Kievsky C<ank at cpan.org>
 Sebastian Riedel C<sri at cpan.org>
 Marcus Ramberg
+Michael Gray C<mjg at cpan.org>
 
 =head1 COPYRIGHT
 
diff -Naur Catalyst-View-Mason-0.08/t/01use.t Catalyst-View-Mason-0.09/t/01use.t
--- Catalyst-View-Mason-0.08/t/01use.t	2005-08-19 14:20:26.000000000 +0000
+++ Catalyst-View-Mason-0.09/t/01use.t	2006-04-28 09:14:37.000000000 +0000
@@ -1,4 +1,5 @@
-use Test::More tests => 2;
+use Test::More tests => 3;
 
 use_ok('Catalyst::View::Mason');
 use_ok('Catalyst::Helper::View::Mason');
+use_ok('Catalyst::Helper::View::MasonSite');


More information about the Catalyst mailing list