--- /dev/null
+Revision history for Perl extension Catalyst::View::TT.
+
+0.13 Fri Oct 07 13:30:00 2005
+ - Fixed constructor
+ - Big update by Andy Wardley
+ - Much improved docs
+
+0.12 Wed Jul 06 15:24:00 2005
+ - Fixed, don't set Content-Type on failure
+ - Fixed helper to use [%author%]
+ - Fixed helper templates
+ - Rewrote docs
+
+0.11 Fri Apr 15 16:00:00 2005
+ - Fixed broken helper.
+
+0.10 Fri Apr 15 16:00:00 2005
+ - Added POD tests and made them pass.
+ - updated for Catalyst 5
+ - New TT Helpers.
+
+0.09 Wed Mar 29 13:47:00 2005
+ - Don't override user-set charset/content-type
+ - Cleaned up the content-type we set.
+ - Updated README to current POD to current POD
+
+0.08 Wed Mar 29 12:22:00 2005
+ - changed order of stash so stash can override c/base/name
+ - fixed some typos
+ - extended the documentation (Andrew Ford)
+0.07 Sat Mar 04 23:00:00 2005
+ - fixed the bugs produced by draven and the_jester ;)
+
+0.06 Fri Mar 04 20:00:00 2005
+ - new helper api
+
+0.05 Mon Feb 28 10:00:00 2005
+ - added helper
+
+0.04 Sun Feb 27 22:00:00 2005
+ - better debug messages (Marcus Ramberg)
+
+0.03 Thu Feb 17 22:00:00 2005
+ - don't try to render something without a template
+
+0.02 Tue Feb 01 02:00:00 2005
+ - using $c->req->match instead of $c->req->action
+
+0.01 Fri Jan 28 22:00:00 2005
+ - first release
--- /dev/null
+Changes
+lib/Catalyst/Helper/View/TT.pm
+lib/Catalyst/Helper/View/TTSite.pm
+lib/Catalyst/View/TT.pm
+Makefile.PL
+MANIFEST This list of files
+META.yml
+README
+t/01use.t
+t/02pod.t
+t/03podcoverage.t
--- /dev/null
+# Avoid version control files.
+\bRCS\b
+\bCVS\b
+,v$
+\B\.svn\b
+
+# Avoid Makemaker generated and utility files.
+\bMakefile$
+\bblib
+\bMakeMaker-\d
+\bpm_to_blib$
+\bblibdirs$
+^MANIFEST\.SKIP$
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\b_build
+
+# Avoid temp and backup files.
+~$
+\.tmp$
+\.old$
+\.bak$
+\#$
+\b\.#
--- /dev/null
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: Catalyst-View-TT
+version: 0.13
+version_from: lib/Catalyst/View/TT.pm
+installdirs: site
+requires:
+ Catalyst: 5.00
+ Template: 0
+ Template::Timer: 0
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.17
--- /dev/null
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+ NAME => 'Catalyst::View::TT',
+ AUTHOR => 'Sebastian Riedel (sri@oook.de)',
+ PREREQ_PM => {
+ Catalyst => '5.00',
+ Template => 0,
+ Template::Timer => 0
+ },
+ VERSION_FROM => 'lib/Catalyst/View/TT.pm'
+);
--- /dev/null
+NAME
+ Catalyst::View::TT - Template View Class
+
+SYNOPSIS
+ # use the helper to create View myapp_create.pl view TT TT
+
+ # configure in lib/MyApp.pm
+
+ our $ROOT = '/home/dent/catalyst/MyApp';
+
+ MyApp->config({
+ name => 'MyApp',
+ root => $ROOT,
+ 'MyApp::V::TT' => {
+ # any TT configurations items go here
+ INCLUDE_PATH => [
+ "$ROOT/templates/src",
+ "$ROOT/templates/lib"
+ ],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+
+ # two optional config items
+ CATALYST_VAR => 'Catalyst',
+ TIMER => 1,
+ },
+ });
+
+ # render view from lib/MyApp.pm or lib/MyApp::C::SomeController.pm
+
+ sub message : Global {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'message.tt2';
+ $c->stash->{message} = 'Hello World!';
+ $c->forward('MyApp::V::TT');
+ }
+
+ # access variables from template
+
+ The message is: [% message %].
+
+ # example when CATALYST_VAR is set to 'Catalyst'
+ Context is [% Catalyst %]
+ The base is [% Catalyst.req.base %]
+ The name is [% Catalyst.config.name %]
+
+ # example when CATALYST_VAR isn't set
+ Context is [% c %]
+ The base is [% base %]
+ The name is [% name %]
+
+DESCRIPTION
+ This is the Catalyst view class for the Template Toolkit. Your
+ application should defined 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 TT TT
+
+ This creates a MyApp::V::TT.pm module in the lib directory (again,
+ replacing "MyApp" with the name of your application) which looks
+ something like this:
+
+ package FooBar::V::TT;
+
+ use strict;
+ use base 'Catalyst::View::TT';
+
+ __PACKAGE__->config->{DEBUG} = 'all';
+
+ 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 TT view class.
+
+ # In MyApp or MyApp::Controller::SomeController
+
+ sub end : Private {
+ my( $self, $c ) = @_;
+ $c->forward('MyApp::V::TT');
+ }
+
+ CONFIGURATION
+ There are a three different ways to configure your view class. The first
+ way is to call the "config()" method in the view subclass. This happens
+ when the module is first loaded.
+
+ package MyApp::V::TT;
+
+ use strict;
+ use base 'Catalyst::View::TT';
+
+ our $ROOT = '/home/dent/catalyst/MyApp';
+
+ MyApp::V::TT->config({
+ INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ });
+
+ The second way is to define a "new()" method in your view subclass. This
+ performs the configuration when the view object is created, shortly
+ after being loaded. Remember to delegate to the base class "new()"
+ method (via "$self->NEXT::new()" in the example below) after performing
+ any configuration.
+
+ sub new {
+ my $self = shift;
+ $self->config({
+ INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ });
+ return $self->NEXT::new(@_);
+ }
+
+ The final, and perhaps most direct way, is to define a class item in
+ your main application configuration, again by calling the uniquitous
+ "config()" method. The items in the class hash are added to those
+ already defined by the above two methods. This happens in the base class
+ new() method (which is one reason why you must remember to call it via
+ "NEXT" if you redefine the "new()" method in a subclass).
+
+ package MyApp;
+
+ use strict;
+ use Catalyst;
+
+ our $ROOT = '/home/dent/catalyst/MyApp';
+
+ MyApp->config({
+ name => 'MyApp',
+ root => $ROOT,
+ 'MyApp::V::TT' => {
+ INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ },
+ });
+
+ Note that any configuration items defined by one of the earlier methods
+ will be overwritten by items of the same name provided by the latter
+ methods.
+
+ RENDERING VIEWS
+ The view plugin renders the template specified in the "template" item in
+ the stash.
+
+ sub message : Global {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'message.tt2';
+ $c->forward('MyApp::V::TT');
+ }
+
+ If a class item isn't defined, then it instead uses the current match,
+ as returned by "$c->match". In the above example, this would be
+ "message".
+
+ The items defined in the stash are passed to the Template Toolkit for
+ use as template variables.
+
+ sub message : Global { sub default : Private { my ( $self, $c ) = @_;
+ $c->stash->{template} = 'message.tt2'; $c->stash->{message} = 'Hello
+ World!'; $c->forward('MyApp::V::TT'); }
+
+ A number of other template variables are also added:
+
+ c A reference to the context object, $c
+ base The URL base, from $c->req->base()
+ name The application name, from $c->config->{ name }
+
+ These can be accessed from the template in the usual way:
+
+ <message.tt2>:
+
+ The message is: [% message %]
+ The base is [% base %]
+ The name is [% name %]
+
+ If you prefer, you can set the "CATALYST_VAR" configuration item to
+ define the name of a template variable through which the context can be
+ referenced.
+
+ MyApp->config({
+ name => 'MyApp',
+ root => $ROOT,
+ 'MyApp::V::TT' => {
+ CATALYST_VAR => 'Catalyst',
+ },
+ });
+
+ message.tt2:
+
+ The base is [% Catalyst.req.base %]
+ The name is [% Catalyst.config.name %]
+
+ The output generated by the template is stored in
+ "$c->response->output".
+
+ TEMPLATE PROFILING
+ If you have configured Catalyst for debug output, "Catalyst::View::TT"
+ will enable profiling of template processing (using Template::Timer).
+ This will embed HTML comments in the output from your templates, such
+ as:
+
+ <!-- TIMER START: process mainmenu/mainmenu.ttml -->
+ <!-- TIMER START: include mainmenu/cssindex.tt -->
+ <!-- TIMER START: process mainmenu/cssindex.tt -->
+ <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
+ <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
+
+ ....
+
+ <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
+
+ You can suppress template profiling by setting the "TIMER" configuration
+ item to a false value.
+
+ MyApp->config({
+ 'MyApp::V::TT' => {
+ TIMER => 0,
+ },
+ });
+
+ METHODS
+ new The constructor for the TT view. Sets up the template provider, and
+ reads the application config.
+
+ process
+ Renders the template specified in "$c->stash->{template}" or
+ "$c->request->match". Template variables are set up from the
+ contents of "$c->stash", augmented with "base" set to
+ "$c->req->base", "c" to $c and "name" to "$c->config->{name}".
+ Alternately, the "CATALYST_VAR" configuration item can be defined to
+ specify the name of a template variable through which the context
+ reference ($c) can be accessed. In this case, the "c", "base" and
+ "name" variables are omitted. Output is stored in
+ "$c->response->output".
+
+ config
+ This method allows your view subclass to pass additional settings to
+ the TT configuration hash, or to set the "CATALYST_VAR" and "TIMER"
+ options.
+
+ HELPERS
+ The Catalyst::Helper::View::TT and Catalyst::Helper::View::TTSite helper
+ modules are provided to create your view module. There are invoked by
+ the myapp_create.pl script:
+
+ $ script/myapp_create.pl view TT TT
+
+ $ script/myapp_create.pl view TT TTSite
+
+ The Catalyst::Helper::View::TT module creates a basic TT view module.
+ The Catalyst::Helper::View::TTSite module goes a little further. It also
+ creates a default set of templates to get you started. It also
+ configures the view module to locate the templates automatically.
+
+SEE ALSO
+ Catalyst, Catalyst::Helper::View::TT, Catalyst::Helper::View::TTSite,
+ Template::Manual
+
+AUTHORS
+ Sebastian Riedel, "sri@cpan.org"
+
+ Marcus Ramberg, "mramberg@cpan.org"
+
+ Jesse Sheidlower, "jester@panix.com"
+
+ Andy Wardley, "abw@cpan.org"
+
+COPYRIGHT
+ This program is free software, you can redistribute it and/or modify it
+ under the same terms as Perl itself.
+
--- /dev/null
+package Catalyst::Helper::View::TT;
+
+use strict;
+
+=head1 NAME
+
+Catalyst::Helper::View::TT - Helper for TT Views
+
+=head1 SYNOPSIS
+
+ script/create.pl view TT TT
+
+=head1 DESCRIPTION
+
+Helper for TT Views.
+
+=head2 METHODS
+
+=head3 mk_compclass
+
+=cut
+
+sub mk_compclass {
+ my ( $self, $helper ) = @_;
+ my $file = $helper->{file};
+ $helper->render_file( 'compclass', $file );
+}
+
+=head1 SEE ALSO
+
+L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
+L<Catalyst::Response>, L<Catalyst::Helper>
+
+=head1 AUTHOR
+
+Sebastian Riedel, C<sri@oook.de>
+
+=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::TT';
+
+=head1 NAME
+
+[% class %] - TT View Component
+
+=head1 SYNOPSIS
+
+See L<[% app %]>
+
+=head1 DESCRIPTION
+
+TT View Component.
+
+=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;
--- /dev/null
+package Catalyst::Helper::View::TTSite;
+
+use strict;
+use File::Spec;
+
+sub mk_compclass {
+ my ( $self, $helper, @args ) = @_;
+ my $file = $helper->{file};
+ $helper->render_file( 'compclass', $file );
+ $self->mk_templates( $helper, @args );
+}
+
+sub mk_templates {
+ my ( $self, $helper ) = @_;
+ my $base = $helper->{base};
+ my $tdir = File::Spec->catfile( $base, 'root', 'templates' );
+ my $ldir = File::Spec->catfile( $tdir, 'lib' );
+ my $sdir = File::Spec->catfile( $tdir, 'src' );
+
+ $helper->mk_dir($ldir);
+ $helper->mk_dir($sdir);
+
+ my $dir = File::Spec->catfile( $ldir, 'config' );
+ $helper->mk_dir($dir);
+
+ foreach my $file (qw( main col url )) {
+ $helper->render_file( "config_$file",
+ File::Spec->catfile( $dir, $file ) );
+ }
+
+ $dir = File::Spec->catfile( $ldir, 'site' );
+ $helper->mk_dir($dir);
+
+ foreach my $file (qw( wrapper layout html header footer )) {
+ $helper->render_file( "site_$file",
+ File::Spec->catfile( $dir, $file ) );
+ }
+
+ foreach my $file (qw( welcome.tt2 message.tt2 error.tt2 ttsite.css )) {
+ $helper->render_file( $file, File::Spec->catfile( $sdir, $file ) );
+ }
+
+}
+
+=head1 NAME
+
+Catalyst::Helper::View::TTSite - Helper for TT view which builds a skeleton web site
+
+=head1 SYNOPSIS
+
+# use the helper to create the view module and templates
+
+ $ script/myapp_create.pl view TT TTSite
+
+# add something like the following to your main application module
+
+ sub message : Global {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'message.tt2';
+ $c->stash->{message} = $c->req->param('message') || 'Hello World';
+ }
+
+ sub default : Private {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'welcome.tt2';
+ }
+
+ sub end : Private {
+ my ( $self, $c ) = @_;
+ $c->forward('MyApp::V::TT');
+ }
+
+=head1 DESCRIPTION
+
+This helper module creates a TT View module. It goes further than
+Catalyst::Helper::View::TT in that it additionally creates a simple
+set of templates to get you started with your web site presentation.
+
+It creates the templates in a F<templates> directory underneath your
+main project directory. In here two further subdirectories are
+created: F<src> which contains the main page templates, and F<lib>
+containing a library of other templates components (header, footer,
+etc.) that the page templates use.
+
+The view module that the helper creates is automatically configured
+to locate these templates.
+
+=head2 METHODS
+
+=head3 mk_compclass
+
+Generates the component class.
+
+=head3 mk_templates
+
+Generates the templates.
+
+=cut
+
+=head1 SEE ALSO
+
+L<Catalyst>, L<Catalyst::View::TT>, L<Catalyst::Helper>,
+L<Catalyst::Helper::View::TT>
+
+=head1 AUTHOR
+
+Andy Wardley <abw@cpan.org>
+
+=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::TT';
+
+my $root = [% app %]->config->{root};
+
+__PACKAGE__->config({
+ CATALYST_VAR => 'Catalyst',
+ INCLUDE_PATH => [ "$root/templates/src", "$root/templates/lib" ],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ ERROR => 'error.tt2',
+ TIMER => 0
+});
+
+=head1 NAME
+
+[% class %] - TT View Component
+
+=head1 SYNOPSIS
+
+See L<[% app %]>
+
+=head1 DESCRIPTION
+
+TT View Component.
+
+=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_main__
+[% USE Date;
+ year = Date.format(Date.now, '%Y');
+-%]
+[% TAGS star -%]
+[% # config/main
+ #
+ # This is the main configuration template which is processed before
+ # any other page, by virtue of it being defined as a PRE_PROCESS
+ # template. This is the place to define any extra template variables,
+ # macros, load plugins, and perform any other template setup.
+
+ IF Catalyst.debug;
+ # define a debug() macro directed to Catalyst's log
+ MACRO debug(message) CALL Catalyst.log.debug(message);
+ END;
+
+ # define a data structure to hold sitewide data
+ site = {
+ title => 'Catalyst::View::TTSite Example Page',
+ copyright => '[* year *] Your Name Here',
+ };
+
+ # load up any other configuration items
+ PROCESS config/col
+ + config/url;
+
+ # set defaults for variables, etc.
+ DEFAULT
+ message = 'There is no message';
+
+-%]
+__config_col__
+[% TAGS star -%]
+[% site.rgb = {
+ black = '#000000'
+ white = '#ffffff'
+ grey1 = '#46494c'
+ grey2 = '#c6c9cc'
+ grey3 = '#e3e6ea'
+ red = '#CC4444'
+ green = '#66AA66'
+ blue = '#89b8df'
+ orange = '#f08900'
+ };
+
+ site.col = {
+ page = site.rgb.white
+ text = site.rgb.grey1
+ head = site.rgb.grey3
+ line = site.rgb.orange
+ message = site.rgb.green
+ error = site.rgb.red
+ };
+%]
+__config_url__
+[% TAGS star -%]
+[% base = Catalyst.req.base;
+
+ site.url = {
+ base = base
+ home = "${base}welcome"
+ message = "${base}message"
+ }
+-%]
+__site_wrapper__
+[% TAGS star -%]
+[% IF template.name.match('\.(css|js|txt)');
+ debug("Passing page through as text: $template.name");
+ content;
+ ELSE;
+ debug("Applying HTML page layout wrappers to $template.name\n");
+ content WRAPPER site/html + site/layout;
+ END;
+-%]
+__site_html__
+[% TAGS star -%]
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>[% template.title or site.title %]</title>
+ <style type="text/css">
+[% PROCESS ttsite.css %]
+ </style>
+ </head>
+ <body>
+[% content %]
+ </body>
+</html>
+__site_layout__
+[% TAGS star -%]
+<div id="header">[% PROCESS site/header %]</div>
+
+<div id="content">
+[% content %]
+</div>
+
+<div id="footer">[% PROCESS site/footer %]</div>
+__site_header__
+[% TAGS star -%]
+<!-- BEGIN site/header -->
+<h1 class="title">[% template.title or site.title %]</h1>
+<!-- END site/header -->
+__site_footer__
+[% TAGS star -%]
+<!-- BEGIN site/footer -->
+<div id="copyright">© [% site.copyright %]</div>
+<!-- END site/footer -->
+__welcome.tt2__
+[% TAGS star -%]
+[% META title = 'Catalyst/TT View!' %]
+<p>
+ Yay! You're looking at a page generated by the Catalyst::View::TT
+ plugin module.
+</p>
+<p>
+ This is the welcome page. Why not try the equally-exciting
+ <a href="[% site.url.message %]">Message Page</a>?
+</p>
+__message.tt2__
+[% TAGS star -%]
+[% META title = 'Catalyst/TT View!' %]
+<p>
+ Yay! You're looking at a page generated by the Catalyst::View::TT
+ plugin module.
+</p>
+<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="[% site.url.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>
+__error.tt2__
+[% TAGS star -%]
+[% META title = 'Catalyst/TT Error' %]
+<p>
+ An error has occurred. We're terribly sorry about that, but it's
+ one of those things that happens from time to time. Let's just
+ hope the developers test everything properly before release...
+</p>
+<p>
+ Here's the error message, on the off-chance that it means something
+ to you: <span class="error">[% error %]</span>
+</p>
+__ttsite.css__
+[% TAGS star %]
+html {
+ height: 100%;
+}
+
+body {
+ background-color: [% site.col.page %];
+ color: [% site.col.text %];
+ margin: 0px;
+ padding: 0px;
+ height: 100%;
+}
+
+#header {
+ background-color: [% site.col.head %];
+ border-bottom: 1px solid [% site.col.line %];
+}
+
+#footer {
+ background-color: [% site.col.head %];
+ text-align: center;
+ border-top: 1px solid [% site.col.line %];
+ position: absolute;
+ bottom: 0;
+ left: 0px;
+ width: 100%;
+ padding: 4px;
+}
+
+#content {
+ padding: 10px;
+}
+
+h1.title {
+ padding: 4px;
+ margin: 0px;
+}
+
+.message {
+ color: [% site.col.message %];
+}
+
+.error {
+ color: [% site.col.error %];
+}
--- /dev/null
+package Catalyst::View::TT;
+
+use strict;
+use base qw/Catalyst::Base/;
+use Template;
+use Template::Timer;
+use NEXT;
+
+our $VERSION = '0.13';
+
+__PACKAGE__->mk_accessors('template');
+
+=head1 NAME
+
+Catalyst::View::TT - Template View Class
+
+=head1 SYNOPSIS
+
+# use the helper to create View
+ myapp_create.pl view TT TT
+
+# configure in lib/MyApp.pm
+
+ our $ROOT = '/home/dent/catalyst/MyApp';
+
+ MyApp->config({
+ name => 'MyApp',
+ root => $ROOT,
+ 'MyApp::V::TT' => {
+ # any TT configurations items go here
+ INCLUDE_PATH => [
+ "$ROOT/templates/src",
+ "$ROOT/templates/lib"
+ ],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+
+ # two optional config items
+ CATALYST_VAR => 'Catalyst',
+ TIMER => 1,
+ },
+ });
+
+# render view from lib/MyApp.pm or lib/MyApp::C::SomeController.pm
+
+ sub message : Global {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'message.tt2';
+ $c->stash->{message} = 'Hello World!';
+ $c->forward('MyApp::V::TT');
+ }
+
+# access variables from template
+
+ The message is: [% message %].
+
+ # example when CATALYST_VAR is set to 'Catalyst'
+ Context is [% Catalyst %]
+ The base is [% Catalyst.req.base %]
+ The name is [% Catalyst.config.name %]
+
+ # example when CATALYST_VAR isn't set
+ Context is [% c %]
+ The base is [% base %]
+ The name is [% name %]
+
+=head1 DESCRIPTION
+
+This is the Catalyst view class for the L<Template Toolkit|Template>.
+Your application should defined a view class which is a subclass of
+this module. The easiest way to achieve this is using the
+F<myapp_create.pl> script (where F<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 TT TT
+
+This creates a MyApp::V::TT.pm module in the F<lib> directory (again,
+replacing C<MyApp> with the name of your application) which looks
+something like this:
+
+ package FooBar::V::TT;
+
+ use strict;
+ use base 'Catalyst::View::TT';
+
+ __PACKAGE__->config->{DEBUG} = 'all';
+
+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 TT view class.
+
+ # In MyApp or MyApp::Controller::SomeController
+
+ sub end : Private {
+ my( $self, $c ) = @_;
+ $c->forward('MyApp::V::TT');
+ }
+
+=head2 CONFIGURATION
+
+There are a three different ways to configure your view class. The
+first way is to call the C<config()> method in the view subclass. This
+happens when the module is first loaded.
+
+ package MyApp::V::TT;
+
+ use strict;
+ use base 'Catalyst::View::TT';
+
+ our $ROOT = '/home/dent/catalyst/MyApp';
+
+ MyApp::V::TT->config({
+ INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ });
+
+The second way is to define a C<new()> method in your view subclass.
+This performs the configuration when the view object is created,
+shortly after being loaded. Remember to delegate to the base class
+C<new()> method (via C<$self-E<gt>NEXT::new()> in the example below) after
+performing any configuration.
+
+ sub new {
+ my $self = shift;
+ $self->config({
+ INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ });
+ return $self->NEXT::new(@_);
+ }
+
+The final, and perhaps most direct way, is to define a class
+item in your main application configuration, again by calling the
+uniquitous C<config()> method. The items in the class hash are
+added to those already defined by the above two methods. This happens
+in the base class new() method (which is one reason why you must
+remember to call it via C<NEXT> if you redefine the C<new()> method in a
+subclass).
+
+ package MyApp;
+
+ use strict;
+ use Catalyst;
+
+ our $ROOT = '/home/dent/catalyst/MyApp';
+
+ MyApp->config({
+ name => 'MyApp',
+ root => $ROOT,
+ 'MyApp::V::TT' => {
+ INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ },
+ });
+
+Note that any configuration items defined by one of the earlier
+methods will be overwritten by items of the same name provided by the
+latter methods.
+
+=head2 RENDERING VIEWS
+
+The view plugin renders the template specified in the C<template>
+item in the stash.
+
+ sub message : Global {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'message.tt2';
+ $c->forward('MyApp::V::TT');
+ }
+
+If a class item isn't defined, then it instead uses the
+current match, as returned by C<$c-E<gt>match>. In the above
+example, this would be C<message>.
+
+The items defined in the stash are passed to the Template Toolkit for
+use as template variables.
+
+sub message : Global {
+ sub default : Private {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'message.tt2';
+ $c->stash->{message} = 'Hello World!';
+ $c->forward('MyApp::V::TT');
+ }
+
+A number of other template variables are also added:
+
+ c A reference to the context object, $c
+ base The URL base, from $c->req->base()
+ name The application name, from $c->config->{ name }
+
+These can be accessed from the template in the usual way:
+
+<message.tt2>:
+
+ The message is: [% message %]
+ The base is [% base %]
+ The name is [% name %]
+
+If you prefer, you can set the C<CATALYST_VAR> configuration item to
+define the name of a template variable through which the context can
+be referenced.
+
+ MyApp->config({
+ name => 'MyApp',
+ root => $ROOT,
+ 'MyApp::V::TT' => {
+ CATALYST_VAR => 'Catalyst',
+ },
+ });
+
+F<message.tt2>:
+
+ The base is [% Catalyst.req.base %]
+ The name is [% Catalyst.config.name %]
+
+The output generated by the template is stored in
+C<$c-E<gt>response-E<gt>output>.
+
+=head2 TEMPLATE PROFILING
+
+If you have configured Catalyst for debug output,
+C<Catalyst::View::TT> will enable profiling of template processing
+(using L<Template::Timer>). This will embed HTML comments in the
+output from your templates, such as:
+
+ <!-- TIMER START: process mainmenu/mainmenu.ttml -->
+ <!-- TIMER START: include mainmenu/cssindex.tt -->
+ <!-- TIMER START: process mainmenu/cssindex.tt -->
+ <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
+ <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
+
+ ....
+
+ <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
+
+You can suppress template profiling by setting the C<TIMER> configuration
+item to a false value.
+
+ MyApp->config({
+ 'MyApp::V::TT' => {
+ TIMER => 0,
+ },
+ });
+
+=head2 METHODS
+
+=over 4
+
+=item new
+
+The constructor for the TT view. Sets up the template provider,
+and reads the application config.
+
+=cut
+
+sub new {
+ my ( $class, $c, $arguments ) = @_;
+
+ my $root = $c->config->{root};
+
+ my $config = {
+ EVAL_PERL => 0,
+ INCLUDE_PATH => [ $root, "$root/base" ],
+ %{ $class->config },
+ %{$arguments}
+ };
+
+ # if we're debugging and/or the TIMER option is set, then we install
+ # Template::Timer as a custom CONTEXT object, but only if we haven't
+ # already got a custom CONTEXT defined
+
+ if ( $config->{TIMER} || ( $c->debug() && !exists $config->{TIMER} ) ) {
+ if ( $config->{CONTEXT} ) {
+ $c->log->error(
+ 'Cannot use Template::Timer - a TT CONFIG is already defined');
+ }
+ else {
+ $config->{CONTEXT} = Template::Timer->new(%$config);
+ }
+ }
+
+ if ( $c->debug && $config->{DUMP_CONFIG} ) {
+ use Data::Dumper;
+ $c->log->debug( "TT Config: ", Dumper($config) );
+ }
+
+ return $class->NEXT::new(
+ $c,
+ {
+ template => Template->new($config) || do {
+ my $error = Template->error();
+ $c->log->error($error);
+ $c->error($error);
+ return undef;
+ }
+ }
+ );
+}
+
+=item process
+
+Renders the template specified in C<$c-E<gt>stash-E<gt>{template}> or
+C<$c-E<gt>request-E<gt>match>. Template variables are set up from the
+contents of C<$c-E<gt>stash>, augmented with C<base> set to
+C<$c-E<gt>req-E<gt>base>, C<c> to C<$c> and C<name> to
+C<$c-E<gt>config-E<gt>{name}>. Alternately, the C<CATALYST_VAR>
+configuration item can be defined to specify the name of a template
+variable through which the context reference (C<$c>) can be accessed.
+In this case, the C<c>, C<base> and C<name> variables are omitted.
+Output is stored in C<$c-E<gt>response-E<gt>output>.
+
+=cut
+
+sub process {
+ my ( $self, $c ) = @_;
+
+ my $template = $c->stash->{template} || $c->request->match;
+
+ unless ($template) {
+ $c->log->debug('No template specified for rendering') if $c->debug;
+ return 0;
+ }
+
+ $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
+
+ my $output;
+ my $cvar = $self->config->{CATALYST_VAR};
+ my $vars = {
+ defined $cvar
+ ? ( $cvar => $c )
+ : (
+ c => $c,
+ base => $c->req->base,
+ name => $c->config->{name}
+ ),
+ %{ $c->stash() }
+ };
+
+ unless ( $self->template->process( $template, $vars, \$output ) ) {
+ my $error = $self->template->error;
+ $error = qq/Couldn't render template "$error"/;
+ $c->log->error($error);
+ $c->error($error);
+ return 0;
+ }
+
+ unless ( $c->response->content_type ) {
+ $c->response->content_type('text/html; charset=utf-8');
+ }
+
+ $c->response->body($output);
+
+ return 1;
+}
+
+=item config
+
+This method allows your view subclass to pass additional settings to
+the TT configuration hash, or to set the C<CATALYST_VAR> and C<TIMER>
+options.
+
+=back
+
+=head2 HELPERS
+
+The L<Catalyst::Helper::View::TT> and
+L<Catalyst::Helper::View::TTSite> helper modules are provided to create
+your view module. There are invoked by the F<myapp_create.pl> script:
+
+ $ script/myapp_create.pl view TT TT
+
+ $ script/myapp_create.pl view TT TTSite
+
+The L<Catalyst::Helper::View::TT> module creates a basic TT view
+module. The L<Catalyst::Helper::View::TTSite> module goes a little
+further. It also creates a default set of templates to get you
+started. It also configures the view module to locate the templates
+automatically.
+
+=head1 SEE ALSO
+
+L<Catalyst>, L<Catalyst::Helper::View::TT>,
+L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
+
+=head1 AUTHORS
+
+Sebastian Riedel, C<sri@cpan.org>
+
+Marcus Ramberg, C<mramberg@cpan.org>
+
+Jesse Sheidlower, C<jester@panix.com>
+
+Andy Wardley, C<abw@cpan.org>
+
+=head1 COPYRIGHT
+
+This program is free software, you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
+
+1;
--- /dev/null
+use strict;
+use Test::More tests => 2;
+
+BEGIN { use_ok('Catalyst::View::TT') }
+BEGIN { use_ok('Catalyst::Helper::View::TT') }
--- /dev/null
+use Test::More;
+
+eval "use Test::Pod 1.14";
+plan skip_all => 'Test::Pod 1.14 required' if $@;
+plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
+
+all_pod_files_ok();
--- /dev/null
+use Test::More;
+
+eval "use Test::Pod::Coverage 1.04";
+plan skip_all => 'Test::Pod::Coverage 1.04 required' if $@;
+plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
+
+all_pod_coverage_ok();