X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FView%2FTT.pm;h=f51331feb31d63673028b778a8e52f9dc0ef7d31;hb=7bd88b6108e3a78197a7a6a436e4e3466eb38571;hp=2996debe25dfa439e24ae82b3a0f9c87eee51463;hpb=c969f23abd5a64ae3c8ada1699789c3ff41356dd;p=catagits%2FCatalyst-View-TT.git diff --git a/lib/Catalyst/View/TT.pm b/lib/Catalyst/View/TT.pm index 2996deb..f51331f 100644 --- a/lib/Catalyst/View/TT.pm +++ b/lib/Catalyst/View/TT.pm @@ -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