the class used to create the TT object can now be customized
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
index 2996deb..f51331f 100644 (file)
@@ -1,15 +1,20 @@
 package Catalyst::View::TT;
 
 use strict;
+use warnings;
+
 use base qw/Catalyst::View/;
-use Data::Dump;
+use Data::Dump 'dump';
 use Template;
 use Template::Timer;
-use NEXT;
+use MRO::Compat;
+use Scalar::Util qw/blessed weaken/;
 
-our $VERSION = '0.25';
+our $VERSION = '0.36';
+$VERSION = eval $VERSION;
 
 __PACKAGE__->mk_accessors('template');
+__PACKAGE__->mk_accessors('expose_methods');
 __PACKAGE__->mk_accessors('include_path');
 
 *paths = \&include_path;
@@ -21,47 +26,45 @@ Catalyst::View::TT - Template View Class
 =head1 SYNOPSIS
 
 # use the helper to create your View
-    myapp_create.pl view TT TT
 
-# configure in lib/MyApp.pm
+    myapp_create.pl view Web TT
 
-    MyApp->config(
-        name     => 'MyApp',
-        root     => MyApp->path_to('root');,
-        'View::TT' => {
-            # any TT configurations items go here
-            INCLUDE_PATH => [
-              MyApp->path_to( 'root', 'src' ), 
-              MyApp->path_to( 'root', 'lib' ), 
-            ],
-            PRE_PROCESS        => 'config/main',
-            WRAPPER            => 'site/wrapper',
-            TEMPLATE_EXTENSION => '.tt',
-
-            # two optional config items
-            CATALYST_VAR => 'Catalyst',
-            TIMER        => 1,
-        },
+# add custom configration in View/Web.pm
+
+    __PACKAGE__->config(
+        # any TT configuration items go here
+        INCLUDE_PATH => [
+          MyApp->path_to( 'root', 'src' ),
+          MyApp->path_to( 'root', 'lib' ),
+        ],
+        TEMPLATE_EXTENSION => '.tt',
+        CATALYST_VAR => 'c',
+        TIMER        => 0,
+        # Not set by default
+        PRE_PROCESS        => 'config/main',
+        WRAPPER            => 'site/wrapper',
+        render_die => 1, # Default for new apps, see render method docs
+        expose_methods => [qw/method_in_view_class/],
     );
-         
-# render view from lib/MyApp.pm or lib/MyApp::C::SomeController.pm
-    
+
+# render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm
+
     sub message : Global {
         my ( $self, $c ) = @_;
         $c->stash->{template} = 'message.tt2';
         $c->stash->{message}  = 'Hello World!';
-        $c->forward('MyApp::V::TT');
+        $c->forward( $c->view('Web') );
     }
 
 # 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 %] 
-    
+    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 %]
@@ -86,6 +89,7 @@ sub new {
     my $config = {
         EVAL_PERL          => 0,
         TEMPLATE_EXTENSION => '',
+        CLASS              => 'Template',
         %{ $class->config },
         %{$arguments},
     };
@@ -117,8 +121,28 @@ sub new {
     }
 
     if ( $c->debug && $config->{DUMP_CONFIG} ) {
-        $c->log->debug( "TT Config: ", Dump($config) );
+        $c->log->debug( "TT Config: ", dump($config) );
     }
+
+    my $self = $class->next::method(
+        $c, { %$config },
+    );
+
+    # Set base include paths. Local'd in render if needed
+    $self->include_path($config->{INCLUDE_PATH});
+
+    $self->expose_methods($config->{expose_methods});
+    $self->config($config);
+
+    # Creation of template outside of call to new so that we can pass [ $self ]
+    # as INCLUDE_PATH config item, which then gets ->paths() called to get list
+    # of include paths to search for templates.
+
+    # Use a weakend copy of self so we dont have loops preventing GC from working
+    my $copy = $self;
+    Scalar::Util::weaken($copy);
+    $config->{INCLUDE_PATH} = [ sub { $copy->paths } ];
+
     if ( $config->{PROVIDERS} ) {
         my @providers = ();
         if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
@@ -131,8 +155,23 @@ sub new {
                 }
                 else
                 {
-                    $prov .="::$pname" if($pname ne '_file_');
+                    if($pname =~ s/^\+//) {
+                        $prov = $pname;
+                    }
+                    else
+                    {
+                        $prov .= "::$pname";
+                    }
+                    # We copy the args people want from the config
+                    # to the args
+                    $p->{args} ||= {};
+                    if ($p->{copy_config}) {
+                        map  { $p->{args}->{$_} = $config->{$_}  }
+                                   grep { exists $config->{$_} }
+                                   @{ $p->{copy_config} };
+                    }
                 }
+                local $@;
                 eval "require $prov";
                 if(!$@) {
                     push @providers, "$prov"->new($p->{args});
@@ -149,27 +188,9 @@ sub new {
         }
     }
 
-    my $self = $class->NEXT::new(
-        $c, { %$config }, 
-    );
-
-    # Set base include paths. Local'd in render if needed
-    $self->include_path($config->{INCLUDE_PATH});
-    
-    $self->config($config);
-
-    # Creation of template outside of call to new so that we can pass [ $self ]
-    # as INCLUDE_PATH config item, which then gets ->paths() called to get list
-    # of include paths to search for templates.
-   
-    # Use a weakend copy of self so we dont have loops preventing GC from working
-    my $copy = $self;
-    Scalar::Util::weaken($copy);
-    $config->{INCLUDE_PATH} = [ sub { $copy->paths } ];
-    
-    $self->{template} = 
-        Template->new($config) || do {
-            my $error = Template->error();
+    $self->{template} =
+        $config->{CLASS}->new($config) || do {
+            my $error = $config->{CLASS}->error();
             $c->log->error($error);
             $c->error($error);
             return undef;
@@ -190,13 +211,13 @@ sub process {
         return 0;
     }
 
-    my $output = $self->render($c, $template);
-
-    if (UNIVERSAL::isa($output, 'Template::Exception')) {
-        my $error = qq/Couldn't render template "$output"/;
-        $c->log->error($error);
-        $c->error($error);
-        return 0;
+    local $@;
+    my $output = eval { $self->render($c, $template) };
+    if (my $err = $@) {
+        return $self->_rendering_error($c, $template . ': ' . $err);
+    }
+    if (blessed($output) && $output->isa('Template::Exception')) {
+        $self->_rendering_error($c, $output);
     }
 
     unless ( $c->response->content_type ) {
@@ -208,43 +229,73 @@ sub process {
     return 1;
 }
 
+sub _rendering_error {
+    my ($self, $c, $err) = @_;
+    my $error = qq/Couldn't render template "$err"/;
+    $c->log->error($error);
+    $c->error($error);
+    return 0;
+}
+
 sub render {
     my ($self, $c, $template, $args) = @_;
 
-    $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
+    $c->log->debug(qq/Rendering template "$template"/) if $c && $c->debug;
 
     my $output;
-    my $vars = { 
+    my $vars = {
         (ref $args eq 'HASH' ? %$args : %{ $c->stash() }),
         $self->template_vars($c)
     };
 
-    local $self->{include_path} = 
+    local $self->{include_path} =
         [ @{ $vars->{additional_template_paths} }, @{ $self->{include_path} } ]
         if ref $vars->{additional_template_paths};
 
-    unless ($self->template->process( $template, $vars, \$output ) ) {
-        return $self->template->error;  
-    } else {
-        return $output;
+    unless ( $self->template->process( $template, $vars, \$output ) ) {
+        if (exists $self->{render_die}) {
+            die $self->template->error if $self->{render_die};
+            return $self->template->error;
+        }
+        $c->log->debug('The Catalyst::View::TT render() method will start dying on error in a future release. Unless you are calling the render() method manually, you probably want the new behaviour, so set render_die => 1 in config for ' . blessed($self) . '. If you wish to continue to return the exception rather than throwing it, add render_die => 0 to your config.') if $c->debug;
+        return $self->template->error;
     }
+    return $output;
 }
 
 sub template_vars {
     my ( $self, $c ) = @_;
 
+    return  () unless $c;
     my $cvar = $self->config->{CATALYST_VAR};
 
-    defined $cvar
+    my %vars = defined $cvar
       ? ( $cvar => $c )
       : (
         c    => $c,
         base => $c->req->base,
         name => $c->config->{name}
-      )
+      );
+
+    if ($self->expose_methods) {
+        my $meta = $self->meta;
+        foreach my $method_name (@{$self->expose_methods}) {
+            my $method = $meta->find_method_by_name( $method_name );
+            unless ($method) {
+                Catalyst::Exception->throw( "$method_name not found in TT view" );
+            }
+            my $method_body = $method->body;
+            my $weak_ctx = $c;
+            weaken $weak_ctx;
+            my $sub = sub {
+                $self->$method_body($weak_ctx, @_);
+            };
+            $vars{$method_name} = $sub;
+        }
+    }
+    return %vars;
 }
 
-
 1;
 
 __END__
@@ -253,23 +304,27 @@ __END__
 
 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.
+this module. Throughout this manual it will be assumed that your application
+is named F<MyApp> and you are creating a TT view named F<Web>; these names
+are placeholders and should always be replaced with whatever name you've
+chosen for your application and your view. The easiest way to create a TT
+view class is through the F<myapp_create.pl> script that is created along
+with the application:
 
-    $ script/myapp_create.pl view TT TT
+    $ script/myapp_create.pl view Web TT
 
-This creates a MyApp::V::TT.pm module in the F<lib> directory (again,
+This creates a F<MyApp::View::Web.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;
-    
+    package FooBar::View::Web;
+
     use strict;
-     use base 'Catalyst::View::TT';
+    use warnings;
+
+    use base 'Catalyst::View::TT';
 
-    __PACKAGE__->config->{DEBUG} = 'all';
+    __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
@@ -277,24 +332,56 @@ 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');
+        $c->forward( $c->view('Web') );
     }
 
+But if you are using the standard auto-generated end action, you don't even need
+to do this!
+
+    # in MyApp::Controller::Root
+    sub end : ActionClass('RenderView') {} # no need to change this line
+
+    # in MyApp.pm
+    __PACKAGE__->config(
+        ...
+        default_view => 'Web',
+    );
+
+This will Just Work.  And it has the advantages that:
+
+=over 4
+
+=item *
+
+If you want to use a different view for a given request, just set 
+<< $c->stash->{current_view} >>.  (See L<Catalyst>'s C<< $c->view >> method
+for details.
+
+=item *
+
+<< $c->res->redirect >> is handled by default.  If you just forward to 
+C<View::Web> in your C<end> routine, you could break this by sending additional
+content.
+
+=back
+
+See L<Catalyst::Action::RenderView> for more details.
+
 =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;
-    
+    package MyApp::View::Web;
+
     use strict;
     use base 'Catalyst::View::TT';
 
-    MyApp::V::TT->config({
+    __PACKAGE__->config({
         INCLUDE_PATH => [
             MyApp->path_to( 'root', 'templates', 'lib' ),
             MyApp->path_to( 'root', 'templates', 'src' ),
@@ -303,59 +390,26 @@ happens when the module is first loaded.
         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 => [
-                MyApp->path_to( 'root', 'templates', 'lib' ),
-                MyApp->path_to( 'root', 'templates', 'src' ),
-            ],
-            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;
-    
-    MyApp->config({
-        name     => 'MyApp',
-        root     => MyApp->path_to('root'),
-        'V::TT' => {
-            INCLUDE_PATH => [
-                MyApp->path_to( 'root', 'templates', 'lib' ),
-                MyApp->path_to( 'root', 'templates', 'src' ),
-            ],
-            PRE_PROCESS  => 'config/main',
-            WRAPPER      => 'site/wrapper',
-        },
-    });
+You may also override the configuration provided in the view class by adding
+a 'View::Web' section to your application config (either in the application
+main class, or in your configuration file). This should be reserved for
+deployment-specific concerns. For example:
+
+    # MyApp_local.conf (Config::General format)
 
-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.  
+    <View Web>
+      WRAPPER "custom_wrapper"
+      INCLUDE_PATH __path_to('root/templates/custom_site')__
+      INCLUDE_PATH __path_to('root/templates')__
+    </View>
+
+might be used as part of a simple way to deploy different instances of the
+same application with different themes.
 
 =head2 DYNAMIC INCLUDE_PATH
 
 Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time.
+
 Additional paths can be added to the start of INCLUDE_PATH via the stash as
 follows:
 
@@ -365,7 +419,7 @@ follows:
 If you need to add paths to the end of INCLUDE_PATH, there is also an
 include_path() accessor available:
 
-    push( @{ $c->view('TT')->include_path }, qw/path/ );
+    push( @{ $c->view('Web')->include_path }, qw/path/ );
 
 Note that if you use include_path() to add extra paths to INCLUDE_PATH, you
 MUST check for duplicate paths. Without such checking, the above code will add
@@ -375,21 +429,21 @@ A safer approach is to use include_path() to overwrite the array of paths
 rather than adding to it. This eliminates both the need to perform duplicate
 checking and the chance of a memory leak:
 
-    @{ $c->view('TT')->include_path } = qw/path another_path/;
+    @{ $c->view('Web')->include_path } = qw/path another_path/;
 
-If you are calling C<render> directly then you can specify dynamic paths by 
+If you are calling C<render> directly then you can specify dynamic paths by
 having a C<additional_template_paths> key with a value of additonal directories
 to search. See L<CAPTURING TEMPLATE OUTPUT> for an example showing this.
 
 =head2 RENDERING VIEWS
 
 The view plugin renders the template specified in the C<template>
-item in the stash.  
+item in the stash.
 
     sub message : Global {
         my ( $self, $c ) = @_;
         $c->stash->{template} = 'message.tt2';
-        $c->forward('MyApp::V::TT');
+        $c->forward( $c->view('Web') );
     }
 
 If a stash item isn't defined, then it instead uses the
@@ -404,7 +458,7 @@ use as template variables.
         my ( $self, $c ) = @_;
         $c->stash->{template} = 'message.tt2';
         $c->stash->{message}  = 'Hello World!';
-        $c->forward('MyApp::V::TT');
+        $c->forward( $c->view('Web') );
     }
 
 A number of other template variables are also added:
@@ -432,13 +486,13 @@ L<Catalyst::Plugin::Email> and the L<render> method:
 
   sub send_email : Local {
     my ($self, $c) = @_;
-    
+
     $c->email(
       header => [
         To      => 'me@localhost',
         Subject => 'A TT Email',
       ],
-      body => $c->view('TT')->render($c, 'email.tt', {
+      body => $c->view('Web')->render($c, 'email.tt', {
         additional_template_paths => [ $c->config->{root} . '/email_templates'],
         email_tmpl_param1 => 'foo'
         }
@@ -453,69 +507,113 @@ See L<C<TIMER>> property of the L<config> method.
 
 =head2 METHODS
 
-=over 4
-
-=item new
+=head2 new
 
-The constructor for the TT view. Sets up the template provider, 
+The constructor for the TT view. Sets up the template provider,
 and reads the application config.
 
-=item process
+=head2 process($c)
 
 Renders the template specified in C<< $c->stash->{template} >> or
-C<< $c->action >> (the private name of the matched action.  Calls L<render> to
+C<< $c->action >> (the private name of the matched action).  Calls L<render> to
 perform actual rendering. Output is stored in C<< $c->response->body >>.
 
-=item render($c, $template, \%args)
+It is possible to forward to the process method of a TT view from inside
+Catalyst like this:
+
+    $c->forward('View::Web');
+
+N.B. This is usually done automatically by L<Catalyst::Action::RenderView>.
 
-Renders the given template and returns output, or a L<Template::Exception>
-object upon error. 
+=head2 render($c, $template, \%args)
 
-The template variables are set to C<%$args> if $args is a hashref, or 
-$C<< $c->stash >> otherwise. In either case the variables are augmented with 
-C<base> set to C< << $c->req->base >>, C<c> to C<$c> and C<name> to
+Renders the given template and returns output. Throws a L<Template::Exception>
+object upon error.
+
+The template variables are set to C<%$args> if C<$args> is a hashref, or
+C<< $c->stash >> otherwise. In either case the variables are augmented with
+C<base> set to C<< $c->req->base >>, C<c> to C<$c>, and C<name> to
 C<< $c->config->{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
+context reference (C<$c>) can be accessed. In this case, the C<c>, C<base>, and
 C<name> variables are omitted.
 
-C<$template> can be anything that Template::process understands how to 
+C<$template> can be anything that Template::process understands how to
 process, including the name of a template file or a reference to a test string.
 See L<Template::process|Template/process> for a full list of supported formats.
 
-=item template_vars
+To use the render method outside of your Catalyst app, just pass a undef context.
+This can be useful for tests, for instance.
+
+It is possible to forward to the render method of a TT view from inside Catalyst
+to render page fragments like this:
+
+    my $fragment = $c->forward("View::Web", "render", $template_name, $c->stash->{fragment_data});
+
+=head3 Backwards compatibility note
+
+The render method used to just return the Template::Exception object, rather
+than just throwing it. This is now deprecated and instead the render method
+will throw an exception for new applications.
+
+This behaviour can be activated (and is activated in the default skeleton
+configuration) by using C<< render_die => 1 >>. If you rely on the legacy
+behaviour then a warning will be issued.
+
+To silence this warning, set C<< render_die => 0 >>, but it is recommended
+you adjust your code so that it works with C<< render_die => 1 >>.
+
+In a future release, C<< render_die => 1 >> will become the default if
+unspecified.
+
+=head2 template_vars
 
 Returns a list of keys/values to be used as the catalyst variables in the
 template.
 
-=item config
+=head2 config
 
 This method allows your view subclass to pass additional settings to
 the TT configuration hash, or to set the options as below:
 
-=over 2
+=head2 paths
 
-=item C<CATALYST_VAR> 
+The list of paths TT will look for templates in.
 
-Allows you to change the name of the Catalyst context object. If set, it will also
-remove the base and name aliases, so you will have access them through <context>.
+=head2 expose_methods
+
+The list of methods in your View class which should be made available to the templates.
 
 For example:
 
-    MyApp->config({
-        name     => 'MyApp',
-        root     => MyApp->path_to('root'),
-        'V::TT' => {
-            CATALYST_VAR => 'Catalyst',
-        },
-    });
+  expose_methods => [qw/uri_for_css/],
+
+  ...
+
+  sub uri_for_css {
+    my ($self, $c, $filename) = @_;
+
+    # additional complexity like checking file exists here
+
+    return $c->uri_for('/static/css/' . $filename);
+  }
 
-F<message.tt2>:
+Then in the template:
+
+  [% uri_for_css('home.css') %]
+
+=head2 C<CATALYST_VAR>
+
+Allows you to change the name of the Catalyst context object. If set, it will also
+remove the base and name aliases, so you will have access them through <context>.
+
+For example, if CATALYST_VAR has been set to "Catalyst", a template might
+contain:
 
     The base is [% Catalyst.req.base %]
     The name is [% Catalyst.config.name %]
 
-=item C<TIMER>
+=head2 C<TIMER>
 
 If you have configured Catalyst for debug output, and turned on the TIMER setting,
 C<Catalyst::View::TT> will enable profiling of template processing
@@ -533,21 +631,82 @@ output from your templates, such as:
     <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
 
 
-=item C<TEMPLATE_EXTENSION>
+=head2 C<TEMPLATE_EXTENSION>
 
 a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
 
 For example:
 
-  package MyApp::C::Test;
-  sub test : Local { .. } 
+  package MyApp::Controller::Test;
+  sub test : Local { .. }
 
 Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
 <root>/test/test.tt.
 
-=back
+=head2 C<PROVIDERS>
 
-=back
+Allows you to specify the template providers that TT will use.
+
+    MyApp->config({
+        name     => 'MyApp',
+        root     => MyApp->path_to('root'),
+        'View::Web' => {
+            PROVIDERS => [
+                {
+                    name    => 'DBI',
+                    args    => {
+                        DBI_DSN => 'dbi:DB2:books',
+                        DBI_USER=> 'foo'
+                    }
+                }, {
+                    name    => '_file_',
+                    args    => {}
+                }
+            ]
+        },
+    });
+
+The 'name' key should correspond to the class name of the provider you
+want to use.  The _file_ name is a special case that represents the default
+TT file-based provider.  By default the name is will be prefixed with
+'Template::Provider::'.  You can fully qualify the name by using a unary
+plus:
+
+    name => '+MyApp::Provider::Foo'
+
+You can also specify the 'copy_config' key as an arrayref, to copy those keys
+from the general config, into the config for the provider:
+
+    DEFAULT_ENCODING    => 'utf-8',
+    PROVIDERS => [
+        {
+            name    => 'Encoding',
+            copy_config => [qw(DEFAULT_ENCODING INCLUDE_PATH)]
+        }
+    ]
+
+This can prove useful when you want to use the additional_template_paths hack
+in your own provider, or if you need to use Template::Provider::Encoding
+
+=head2 C<CLASS>
+
+Allows you to specify a custom class to use as the template class instead of
+L<Template>.
+
+    package MyApp::View::Web;
+
+    use strict;
+    use base 'Catalyst::View::TT';
+
+    use Template::AutoFilter;
+
+    __PACKAGE__->config({
+        CLASS => 'Template::AutoFilter',
+    });
+
+This is useful if you want to use your own subclasses of L<Template>, so you
+can, for example, prevent XSS by automatically filtering all output through
+C<| html>.
 
 =head2 HELPERS
 
@@ -555,9 +714,9 @@ 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 Web TT
 
-    $ script/myapp_create.pl view TT TTSite
+    $ script/myapp_create.pl view Web TTSite
 
 The L<Catalyst::Helper::View::TT> module creates a basic TT view
 module.  The L<Catalyst::Helper::View::TTSite> module goes a little
@@ -565,6 +724,17 @@ 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 NOTES
+
+If you are using the L<CGI> module inside your templates, you will
+experience that the Catalyst server appears to hang while rendering
+the web page. This is due to the debug mode of L<CGI> (which is
+waiting for input in the terminal window). Turning off the
+debug mode using the "-no_debug" option solves the
+problem, eg.:
+
+    [% USE CGI('-no_debug') %]
+
 =head1 SEE ALSO
 
 L<Catalyst>, L<Catalyst::Helper::View::TT>,
@@ -580,9 +750,11 @@ Jesse Sheidlower, C<jester@panix.com>
 
 Andy Wardley, C<abw@cpan.org>
 
+Luke Saunders, C<luke.saunders@gmail.com>
+
 =head1 COPYRIGHT
 
-This program is free software, you can redistribute it and/or modify it 
+This program is free software. You can redistribute it and/or modify it
 under the same terms as Perl itself.
 
 =cut