NAME
Catalyst::View::Seamstress - HTML::Seamstress View Class for Catalyst
SYNOPSIS
# use the helper to create MyApp::View::Seamstress # where comp_root and skeleton are optional
myapp_create.pl view Seamstress Seamstress /path/to/html html::skeleton
^-modulenm ^-helpernm ^-comp_root ^-skeleton
# optionally edit the skeleton and meat_pack routines # in lib/MyApp/View/Seamstress.pm
# render view from lib/MyApp.pm or lib/MyApp::C::SomeController.pm
sub message : Global {
my ( $self, $c ) = @_;
$c->stash->{LOOM} = 'html::hello_world';
$c->stash->{name} = 'Mister GreenJeans';
$c->stash->{date} = 'Today';
# the DefaultEnd plugin would mean no need for this line
$c->forward('MyApp::View::Seamstress');
}
DESCRIPTION
This is the Catalyst view class for HTML::Seamstress. Your application should define a view class which is a subclass of this module. The easiest way to achieve this is using the myapp_create.pl script (where myapp should be replaced with whatever your application is called). This script is created as part of the Catalyst setup.
$ script/myapp_create.pl view Seamstress Seamstress
This creates a MyApp::View::Seamstress.pm module in the lib directory (again, replacing MyApp
with the name of your application).
Now you can modify your action handlers in the main application and/or controllers to forward to your view class. You might choose to do this in the end() method, for example, to automatically forward all actions to the Seamstress view class.
# In MyApp or MyApp::Controller::SomeController
sub end : Private {
my( $self, $c ) = @_;
$c->forward('MyApp::View::Seamstress');
}
Or you might like to use Catalyst::Plugin::DefaultEnd
or even Catalyst::Action::RenderView
CONFIGURATION
The helper app automatically puts the per-application configuration info in MyApp::View::Seamstress
. You configure the per-request information (e.g. $c->stash->{LOOM}
and variables for this template) in your controller.
The two main options which control how View::Seamtress renders HTML are the LOOM (which is taken from the stash) and optionally the skeleton, which is stored in the app config.
If you just configure a LOOM then you are most likely using the "plain meat" method described below. If you also configure a skeleton in your config as well then you're using the "meat and skeleton" method. See below for a more detailed discussion of this!
$c->stash->{LOOM}
The Seamstress view plugin MUST have a LOOM to work on or it will balk with an error:
sub message : Global { my ( $self, $c ) = @_; $c->stash->{LOOM} = 'html::hello_world'; $c->stash->{name} = 'Billy Bob'; $c->stash->{date} = 'medjool sahara'; $c->forward('MyApp::View::Seamstress'); }
MyApp::View::Seamstress->config->{skeleton}
By default this is not set and the HTML output is simply the result of taking
$c->stash->{LOOM}
, callingnew()
to create an HTML tree and then passing this toprocess()
so that it can rework the tree.However, if
MyApp::View::Seamstress->config->{skeleton}
is set, then both its value and the values ofMyApp::View::Seamstress->config->{meat_pack}
and$stash->{LOOM}->fixup()
come into effect as described in "The_meat-skeleton_paradigm" in HTML::Seamstress.Let's take that a little slower:
$stash->{LOOM}->fixup()
means: given a Seamstress-style Perl class, whose name is$stash->{LOOM}
, call the methodfixup()
in that class so that it can do a final fixup of the entire HTML that is about to be shipped back to the client.
The output generated from the LOOM (and possibly its interaction with a skeleton) is stored in $c->response->body
.
Other Config Options
- config->{fixup}
-
Set this to a coderef to allow the view to change the tree after the main processing phase.
- config->{use_xhtml}
-
By default the view will generate html 4 style html by calling as_HTML on the tree object. If you set this to a true value it will generate XHTML style HTML by calling as_XML on the tree object. See HTML::Element for details for these methods.
Also note that this won't apply proper HTML doctypes and what-have-you unless you have them in your original HTML.
- config->{meat_pack}
-
This is the subref which is called to pack meat into the skeleton for the meat skeleton method. Tinker with this to have more creative LOOMS. See "Funny LOOMs" and the meat/skeleton discussions.
Funny LOOMs
In the examples so far the LOOM has always been a class name.
If instead LOOM is an object then we'll assume that is a useful HTML::Element style object and just use that instead of calling new
on the LOOM. In this case we'll also not ->delete it at the end of the request so you'll have to do that yourself!
If the LOOM is in fact an ARRAY reference filled with class names we'll send the meat_pack a hash of class names mapped to objects.
The meat-skeleton paradigm!
Generally Catalyst::View::Seamstress operates in one of 2 ways: a plain meat way or a meat-skeleton way.
Plain meat is simple: the View takes $c-
stash->{LOOM} > and calls new()
and process()
on it and stores the result in $c-
response->body>.
Meat-skeleton is designed to facilitate the way that most web sites are typically designed:
HTML pages typically have meat and a skeleton. The meat varies from page to page while the skeleton is fairly (though not completely) static. For example, the skeleton of a webpage is usually a header, a footer, and a navbar. The meat is what shows up when you click on a link on the page somewhere. While the meat will change with each click, the skeleton is rather static.
Mason accomodates the meat-skeleton paradigm via an autohandler
and $m->call_next()
. Template accomodates it via its WRAPPER
directive.
And Seamstress? Well, here's what you _can_ do:
- 1 generate the meat,
$meat
-
This is typically what you see in the
body
part of an HTML page - 2 generate the skeleton,
$skeleton
-
This is typically the html, head, and maybe some body
- 3 put the meat in the skeleton
So, nothing about this is forced. This is just how I typically do things and that is why Catalyst::View::Seamstress has support for this.
Tips to View Writers
The order of use base is VERY significant
When your helper module creates MyApp::View::Seamstress
it is very important for the use base
to look this way:
use base qw(Catalyst::View::Seamstress HTML::Seamstress );
and not this way:
use base qw(HTML::Seamstress Catalyst::View::Seamstress );
so that certain calls (probably new) get handled properly.
Getting config information from MyApp and MyApp::View::*
assuming Catalyst::View::Seamstress::new()
starts off like this:
sub new {
my $self = shift;
my $c = shift;
$self->config
contains things set in MyApp::View::*
. $c->config
contains things set in MyApp
assuming Catalyst::View::Seamstress::process()
starts off similarly:
sub process {
my ( $self, $c ) = @_;
$self->config
contains things set in MyApp::View::*
. $c->config
contains things set in MyApp
.
There is no automatic merging of the two sources of configuration: you have to do that yourself if you want to do it.
SEE ALSO
Catalyst, Catalyst::View, Catalyst::Helper::View::Seamstress, HTML::Seamstress
A working sample app
The best way to see a fully working Seamstress-style Perl class is to pull down the working sample app from sourceforge.
A working sample app, which does both simple and meat-skeleton rendering is available from Sourceforge CVS:
cvs -d:pserver:anonymous@seamstress.cvs.sourceforge.net:/cvsroot/seamstress login
cvs -z3 -d:pserver:anonymous@seamstress.cvs.sourceforge.net:/cvsroot/seamstress co -P catalyst-simpleapp
SUPPORT
Email the author or ping him on #catalyst
on irc.perl.org
AUTHORS
Terrence Brannon <metaperl@gmail.com>
COPYRIGHT
This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself.