woops, backfix, re-added template_vars changes
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
index 93fad62..74d538d 100644 (file)
@@ -1,14 +1,15 @@
 package Catalyst::View::TT;
 
 use strict;
-use base qw/Catalyst::Base/;
+use base qw/Catalyst::View/;
 use Template;
 use Template::Timer;
 use NEXT;
 
-our $VERSION = '0.14';
+our $VERSION = '0.20';
 
 __PACKAGE__->mk_accessors('template');
+__PACKAGE__->mk_accessors('include_path');
 
 =head1 NAME
 
@@ -21,19 +22,18 @@ Catalyst::View::TT - Template View Class
 
 # configure in lib/MyApp.pm
 
-    our $ROOT = '/home/dent/catalyst/MyApp';
-
     MyApp->config({
         name     => 'MyApp',
-        root     => $ROOT,
-        'MyApp::V::TT' => {
+        root     => MyApp->path_to('root');,
+        'V::TT' => {
             # any TT configurations items go here
             INCLUDE_PATH => [
-              "$ROOT/templates/src", 
-              "$ROOT/templates/lib"
+              MyApp->path_to( 'root', 'src' ), 
+              MyApp->path_to( 'root', 'lib' ), 
             ],
-            PRE_PROCESS => 'config/main',
-            WRAPPER     => 'site/wrapper',
+            PRE_PROCESS        => 'config/main',
+            WRAPPER            => 'site/wrapper',
+            TEMPLATE_EXTENSION => '.tt',
 
             # two optional config items
             CATALYST_VAR => 'Catalyst',
@@ -109,10 +109,11 @@ happens when the module is first loaded.
     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"],
+        INCLUDE_PATH => [
+            MyApp->path_to( 'root', 'templates', 'lib' ),
+            MyApp->path_to( 'root', 'templates', 'src' ),
+        ],
         PRE_PROCESS  => 'config/main',
         WRAPPER      => 'site/wrapper',
     });
@@ -126,7 +127,10 @@ performing any configuration.
     sub new {
         my $self = shift;
         $self->config({
-            INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+            INCLUDE_PATH => [
+                MyApp->path_to( 'root', 'templates', 'lib' ),
+                MyApp->path_to( 'root', 'templates', 'src' ),
+            ],
             PRE_PROCESS  => 'config/main',
             WRAPPER      => 'site/wrapper',
         });
@@ -146,13 +150,14 @@ subclass).
     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"],
+        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',
         },
@@ -162,6 +167,15 @@ 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 DYNAMIC INCLUDE_PATH
+
+It is sometimes needed to dynamically add additional paths to the 
+INCLUDE_PATH variable of the template object. This can be done by setting
+'additional_include_paths' on stash to a referrence to an array with 
+additional paths:
+
+    $c->stash->{additional_template_paths} = [$c->config->{root} . '/test_include_path']; 
+
 =head2 RENDERING VIEWS
 
 The view plugin renders the template specified in the C<template>
@@ -202,52 +216,12 @@ These can be accessed from the template in the usual way:
     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
@@ -259,26 +233,49 @@ and reads the application config.
 
 =cut
 
-sub new {
-    my ( $class, $c, $arguments ) = @_;
+sub _coerce_paths {
+    my ( $paths, $dlim ) = shift;
+    return () if ( !$paths );
+    return @{$paths} if ( ref $paths eq 'ARRAY' );
 
-    my $root = $c->config->{root};
+    # tweak delim to ignore C:/
+    unless ( defined $dlim ) {
+        $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
+    }
+    return split( /$dlim/, $paths );
+}
 
+sub new {
+    my ( $class, $c, $arguments ) = @_;
     my $config = {
-        EVAL_PERL    => 0,
-        INCLUDE_PATH => [ $root, "$root/base" ],
+        EVAL_PERL          => 0,
+        TEMPLATE_EXTENSION => '',
         %{ $class->config },
-        %{$arguments}
+        %{$arguments},
     };
+    if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
+        my $delim = $config->{DELIMITER};
+        my @include_path
+            = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
+        if ( !@include_path ) {
+            my $root = $c->config->{root};
+            my $base = Path::Class::dir( $root, 'base' );
+            @include_path = ( "$root", "$base" );
+        }
+        $config->{INCLUDE_PATH} = \@include_path;
+    }
+
+
 
     # 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} ( {
+    if ( $config->{TIMER} ) {
         if ( $config->{CONTEXT} ) {
             $c->log->error(
-                'Cannot use Template::Timer - a TT CONFIG is already defined');
+                'Cannot use Template::Timer - a TT CONFIG is already defined'
+            );
         }
         else {
             $config->{CONTEXT} = Template::Timer->new(%$config);
@@ -289,18 +286,38 @@ sub new {
         use Data::Dumper;
         $c->log->debug( "TT Config: ", Dumper($config) );
     }
+    if ( $config->{PROVIDERS} ) {
+        my @providers = ();
+        if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
+            foreach my $p (@{$config->{PROVIDERS}}) {
+                my $pname = $p->{name};
+                eval "require Template::Provider::$pname";
+                if(!$@) {
+                    push @providers, "Template::Provider::${pname}"->new($p->{args});
+                }
+            }
+        }
+        delete $config->{PROVIDERS};
+        if(@providers) {
+            $config->{LOAD_TEMPLATES} = \@providers;
+        }
+    }
 
-    return $class->NEXT::new(
+    my $self = $class->NEXT::new(
         $c,
-        {
-            template => Template->new($config) || do {
+        {   template => Template->new($config) || do {
                 my $error = Template->error();
                 $c->log->error($error);
                 $c->error($error);
                 return undef;
-              }
-        }
+            },
+            %{$config},
+        },
     );
+    $self->include_path($config->{INCLUDE_PATH});
+    $self->config($config);
+
+    return $self;
 }
 
 =item process
@@ -320,7 +337,9 @@ Output is stored in C<$c-E<gt>response-E<gt>output>.
 sub process {
     my ( $self, $c ) = @_;
 
-    my $template = $c->stash->{template} || $c->request->match;
+    my $template = $c->stash->{template}
+      || ( $c->request->match || $c->request->action )
+      . $self->config->{TEMPLATE_EXTENSION};
 
     unless ($template) {
         $c->log->debug('No template specified for rendering') if $c->debug;
@@ -330,18 +349,11 @@ sub process {
     $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() }
-    };
+    my $vars = { $self->template_vars($c) };
 
+    unshift @{ $self->include_path },
+      @{ $c->stash->{additional_template_paths} }
+      if ref $c->stash->{additional_template_paths};
     unless ( $self->template->process( $template, $vars, \$output ) ) {
         my $error = $self->template->error;
         $error = qq/Couldn't render template "$error"/;
@@ -349,6 +361,9 @@ sub process {
         $c->error($error);
         return 0;
     }
+    splice @{ $self->include_path }, 0,
+      scalar @{ $c->stash->{additional_template_paths} }
+      if ref $c->stash->{additional_template_paths};
 
     unless ( $c->response->content_type ) {
         $c->response->content_type('text/html; charset=utf-8');
@@ -359,11 +374,86 @@ sub process {
     return 1;
 }
 
+=item template_vars
+
+Returns a list of keys/values to be used as the variables in the
+template.
+
+=cut
+
+sub template_vars {
+    my ( $self, $c ) = @_;
+
+    my $cvar = $self->config->{CATALYST_VAR};
+
+    defined $cvar
+      ? ( $cvar => $c )
+      : (
+        c    => $c,
+        base => $c->req->base,
+        name => $c->config->{name}
+      ),
+      %{ $c->stash() }
+
+}
 =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.
+the TT configuration hash, or to set the options as below:
+
+=over 2
+
+=item 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:
+
+    MyApp->config({
+        name     => 'MyApp',
+        root     => MyApp->path_to('root'),
+        'V::TT' => {
+            CATALYST_VAR => 'Catalyst',
+        },
+    });
+
+F<message.tt2>:
+
+    The base is [% Catalyst.req.base %]
+    The name is [% Catalyst.config.name %]
+
+=item 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
+(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) -->
+
+
+=item 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 { .. } 
+
+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
 
 =back