View::TT, perltidy
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
index 39b4f11..d1353e4 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.13';
+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',
@@ -44,9 +44,9 @@ Catalyst::View::TT - Template View Class
 # 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!';
+        my ( $self, $c ) = @_;
+        $c->stash->{template} = 'message.tt2';
+        $c->stash->{message}  = 'Hello World!';
         $c->forward('MyApp::V::TT');
     }
 
@@ -94,7 +94,7 @@ to the TT view class.
     # In MyApp or MyApp::Controller::SomeController
     
     sub end : Private {
-        my($self, $c) = @_;
+        my( $self, $c ) = @_;
         $c->forward('MyApp::V::TT');
     }
 
@@ -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,16 +127,19 @@ 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',
         });
         return $self->NEXT::new(@_);
     }
  
-The final, and perhaps most direct way, is to define a C<template>
+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 C<template> hash are
+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
@@ -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,18 +167,27 @@ 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>
 item in the stash.  
 
     sub message : Global {
-        my ($self, $c) = @_;
-        $c->stash->{ template } = 'message.tt2';
+        my ( $self, $c ) = @_;
+        $c->stash->{template} = 'message.tt2';
         $c->forward('MyApp::V::TT');
     }
 
-If a C<template> item isn't defined, then it instead uses the
+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>.
 
@@ -182,9 +196,9 @@ use as template variables.
 
 sub message : Global {
     sub default : Private {
-        my ($self, $c) = @_;
-        $c->stash->{ template } = 'message.tt2';
-        $c->stash->{ message  } = 'Hello World!';
+        my ( $self, $c ) = @_;
+        $c->stash->{template} = 'message.tt2';
+        $c->stash->{message}  = 'Hello World!';
         $c->forward('MyApp::V::TT');
     }
 
@@ -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,48 +233,85 @@ 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 );
+}
 
-    my %config = (
-        EVAL_PERL    => 0,
-        INCLUDE_PATH => [ $root, "$root/base" ],
+sub new {
+    my ( $class, $c, $arguments ) = @_;
+    my $delim = $class->config->{DELIMITER} || $arguments->{DELIMITER};
+    my $include_path;
+    if ( ref $arguments->{INCLUDE_PATH} eq 'ARRAY' ) {
+        $include_path = $arguments->{INCLUDE_PATH};
+    }
+    elsif ( ref $class->config->{INCLUDE_PATH} eq 'ARRAY' ) {
+        $include_path = $class->config->{INCLUDE_PATH};
+    }
+    else {
+        my @include_path
+            = _coerce_paths( $arguments->{INCLUDE_PATH}, $delim );
+        if ( !@include_path ) {
+            @include_path
+                = _coerce_paths( $class->config->{INCLUDE_PATH}, $delim );
+        }
+        if ( !@include_path ) {
+            my $root = $c->config->{root};
+            my $base = Path::Class::dir( $root, 'base' );
+            @include_path = ( "$root", "$base" );
+        }
+        $include_path = \@include_path;
+    }
+    my $config = {
+        EVAL_PERL          => 0,
+        TEMPLATE_EXTENSION => '',
         %{ $class->config },
-        %{$arguments}
-    );
+        %{$arguments},
+        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} || ( $c->debug() && !exists $config{TIMER} ) ) {
-        if ( $config{CONTEXT} ) {
+    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 );
+            $config->{CONTEXT} = Template::Timer->new(%$config);
         }
     }
 
-    if ( $c->debug && $config{DUMP_CONFIG} ) {
+    if ( $c->debug && $config->{DUMP_CONFIG} ) {
         use Data::Dumper;
-        $c->log->debug( "TT Config: ", Dumper( \%config ) );
+        $c->log->debug( "TT Config: ", Dumper($config) );
     }
 
-    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($include_path);
+    $self->config($config);
+
+    return $self;
 }
 
 =item process
@@ -320,7 +331,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;
@@ -334,14 +347,15 @@ sub process {
     my $vars = {
         defined $cvar
         ? ( $cvar => $c )
-        : (
-            c    => $c,
+        : ( c    => $c,
             base => $c->req->base,
             name => $c->config->{name}
         ),
         %{ $c->stash() }
     };
-
+    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 +363,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');
@@ -362,8 +379,61 @@ sub process {
 =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
 
@@ -388,11 +458,14 @@ automatically.
 L<Catalyst>, L<Catalyst::Helper::View::TT>,
 L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
 
-=head1 AUTHOR
+=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