File Coverage

blib/lib/Catalyst/View/TT/Alloy.pm
Criterion Covered Total %
statement 21 80 26.2
branch 0 32 0.0
condition 0 6 0.0
subroutine 7 12 58.3
pod n/a
total 28 130 21.5


line stmt bran cond sub pod time code
1             #!/bin/false
2              
3 1     1   14678 use strict;
  1         2  
  1         50  
4              
5             package Catalyst::View::TT::Alloy;
6             $Catalyst::View::TT::Alloy::VERSION = '0.00004';
7 1     1   3 use base qw( Catalyst::View );
  1         1  
  1         299  
8              
9 1     1   5 use Carp qw( croak );
  1         4  
  1         54  
10 1     1   443 use Data::Dump qw( dump );
  1         5878  
  1         52  
11 1     1   413 use Path::Class;
  1         33573  
  1         55  
12 1     1   6 use Scalar::Util qw( weaken );
  1         2  
  1         38  
13 1     1   515 use Template::Alloy qw( Compile Parse TT );
  1         18528  
  1         4  
14              
15             __PACKAGE__->mk_accessors('template');
16             __PACKAGE__->mk_accessors('include_path');
17              
18             =head1 NAME
19              
20             Catalyst::View::TT::Alloy - Template::Alloy (TT) View Class
21              
22             =head1 VERSION
23              
24             version 0.00004
25              
26             =head1 SYNOPSIS
27              
28             # use the helper to create your View
29             myapp_create.pl view TT::Alloy TT::Alloy
30              
31             # configure in myapp.yml
32              
33             'View::TT::Alloy':
34             INCLUDE_PATH:
35             - __path_to(root/src)__
36             - __path_to(root/lib)__
37             PRE_PROCESS: 'config/main'
38             WRAPPER: 'site/wrapper'
39             # optional
40             TEMPLATE_EXTENSION: '.tt'
41             CATALYST_VAR: 'Catalyst'
42              
43             # example render view in lib/MyApp/Controller/Root.pm
44              
45             sub default : Private {
46             my ( $self, $c ) = @_;
47             $c->stash->{template} = 'message.tt2';
48             $c->stash->{message} = 'Hello World!';
49             return;
50             }
51              
52             sub end : ActionClass('RenderView') {
53             }
54              
55             # access variables from template
56              
57             The message is: [% message %].
58              
59             # example when CATALYST_VAR is set to 'Catalyst'
60             Context is [% Catalyst %]
61             The base is [% Catalyst.req.base %]
62             The name is [% Catalyst.config.name %]
63              
64             # example when CATALYST_VAR isn't set
65             Context is [% c %]
66             The base is [% base %]
67             The name is [% name %]
68              
69             =cut
70              
71             sub _coerce_paths {
72 0     0     my ( $paths, $dlim ) = shift;
73 0 0         return () if ( !$paths );
74 0 0         return @{$paths} if ( ref $paths eq 'ARRAY' );
  0            
75              
76             # tweak delim to ignore C:/
77 0 0         unless ( defined $dlim ) {
78 0 0         $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
79             }
80 0           return split( /$dlim/, $paths );
81             }
82              
83             sub new {
84 0     0     my ( $class, $c, $arguments ) = @_;
85 0           my $config = {
86             TEMPLATE_EXTENSION => '',
87 0           %{ $class->config },
88 0           %{$arguments},
89             };
90 0 0         if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
91 0           my $delim = $config->{DELIMITER};
92             my @include_path
93 0           = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
94 0 0         if ( !@include_path ) {
95 0           my $root = $c->config->{root};
96 0           my $base = Path::Class::dir( $root, 'base' );
97 0           @include_path = ( "$root", "$base" );
98             }
99 0           $config->{INCLUDE_PATH} = \@include_path;
100             }
101              
102 0 0 0       if ( $c->debug && $config->{DUMP_CONFIG} ) {
103 0           $c->log->debug( "TT Config: ", dump($config) );
104             }
105              
106 0           my $self = $class->next::method(
107             $c, { %$config },
108             );
109              
110             # Set base include paths. Local'd in render if needed
111 0           $self->include_path($config->{INCLUDE_PATH});
112              
113 0           $self->config($config);
114              
115 0           return $self;
116             }
117              
118             sub process {
119 0     0     my ( $self, $c ) = @_;
120              
121 0   0       my $template = $c->stash->{template}
122             || $c->action . $self->config->{TEMPLATE_EXTENSION};
123              
124 0 0         unless (defined $template) {
125 0 0         $c->log->debug('No template specified for rendering') if $c->debug;
126 0           return 0;
127             }
128              
129 0           my $output;
130 0           eval {
131 0           $output = $self->render($c, $template);
132             };
133              
134 0 0         if ($@) {
135 0           my $error = qq/Couldn't render template "$template"/;
136 0           $c->log->error($@);
137 0           $c->error($@);
138 0           return 0;
139             }
140              
141 0 0         unless ( $c->response->content_type ) {
142 0           $c->response->content_type('text/html; charset=utf-8');
143             }
144              
145 0           $c->response->body($output);
146              
147 0           return 1;
148             }
149              
150             sub render {
151 0     0     my ($self, $c, $template, $args) = @_;
152              
153 0 0         $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
154              
155 0           my $config = $self->config;
156 0           $config->{INCLUDE_PATH} = $self->include_path;
157              
158 0           my $vars = {
159 0 0         (ref $args eq 'HASH' ? %$args : %{ $c->stash() }),
160             $self->_template_vars($c)
161             };
162              
163 0           local $config->{INCLUDE_PATH} =
164 0 0         [ @{ $vars->{additional_template_paths} }, @{ $config->{INCLUDE_PATH} } ]
  0            
165             if ref $vars->{additional_template_paths};
166              
167             # until Template::Alloy either gives us a public method to change
168             # INCLUDE_PATH, or supports a coderef there, we need to create a
169             # new object for every call of render()
170 0           my $tt = Template::Alloy->new($config);
171 0           my $output;
172              
173 0 0         unless ( $tt->process( $template, $vars, \$output ) ) {
174 0           croak $tt->error;
175             }
176             else {
177 0           return $output;
178             }
179             }
180              
181             sub _template_vars {
182 0     0     my ( $self, $c ) = @_;
183              
184 0           my $cvar = $self->config->{CATALYST_VAR};
185              
186 0 0         defined $cvar
187             ? ( $cvar => $c )
188             : (
189             c => $c,
190             base => $c->req->base,
191             name => $c->config->{name}
192             )
193             }
194              
195              
196             1;
197              
198             __END__
199              
200             =head1 DESCRIPTION
201              
202             This is the Catalyst view for the L<TT|Template> emulator
203             L<Template::Alloy>.
204              
205             Your application should define a view class which is a subclass of
206             this module. The easiest way to achieve this is using
207             C<script/myapp_create.pl> (replacing C<myapp> with the name of your
208             application).
209              
210             $ script/myapp_create.pl view TT::Alloy TT::Alloy
211              
212             You can either manually forward to the C<TT::Alloy> as normal, or use
213             L<Catalyst::Action::RenderView> to do it for you.
214              
215             # In MyApp::Controller::Root
216              
217             sub end : ActionClass('RenderView') { }
218              
219             =head2 RATIONAL
220              
221             L<Template::Alloy> is a pure-perl module which emulates most common
222             features of L<TT|Template>, and in some cases is faster too. See
223             L<Template::Alloy::TT> for details of which features are missing.
224              
225             L<Catalyst::View::TT::Alloy> is generally compatible with
226             L<Catalyst::View::TT>. The C<TIMER> configuration option isn't supported,
227             and the C<paths()> alias to C<include_path()> has been removed.
228              
229             Although L<Template::Alloy> emulates several other
230             templating modules, the interface differs for each one. For this reason,
231             this module only provides the L<TT|Template> interface.
232              
233             =head2 DYNAMIC INCLUDE_PATH
234              
235             Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time.
236              
237             Additional paths can be added to the start of INCLUDE_PATH via the stash as
238             follows:
239              
240             $c->stash->{additional_template_paths} =
241             [$c->config->{root} . '/test_include_path'];
242              
243             If you need to add paths to the end of INCLUDE_PATH, there is also an
244             include_path() accessor available:
245              
246             push( @{ $c->view('TT')->include_path }, qw/path/ );
247              
248             Note that if you use include_path() to add extra paths to INCLUDE_PATH, you
249             MUST check for duplicate paths. Without such checking, the above code will add
250             "path" to INCLUDE_PATH at every request, causing a memory leak.
251              
252             A safer approach is to use include_path() to overwrite the array of paths
253             rather than adding to it. This eliminates both the need to perform duplicate
254             checking and the chance of a memory leak:
255              
256             $c->view('TT')->include_path([ qw/ path another_path / ]);
257              
258             If you are calling C<render> directly then you can specify dynamic paths by
259             having a C<additional_template_paths> key with a value of additonal directories
260             to search. See L<CAPTURING TEMPLATE OUTPUT> for an example showing this.
261              
262             =head2 RENDERING VIEWS
263              
264             The view plugin renders the template specified in the C<template>
265             item in the stash.
266              
267             sub message : Global {
268             my ( $self, $c ) = @_;
269              
270             $c->stash->{template} = 'message.tt2';
271              
272             $c->forward('MyApp::View::TT::Alloy');
273             }
274              
275             If C<template> isn't defined, then it builds the filename from
276             C<Catalyst/action> and the C<TEMPLATE_EXTENSION> config setting.
277             In the above example, this would be C<message>.
278              
279             The items defined in the stash are passed to L<Template::Alloy> for
280             use as template variables.
281              
282             sub default : Private {
283             my ( $self, $c ) = @_;
284             $c->stash->{template} = 'message.tt2';
285             $c->stash->{message} = 'Hello World!';
286             $c->forward('MyApp::View::TT::Alloy');
287             }
288              
289             A number of other template variables are also added:
290              
291             c A reference to the context object, $c
292             base The URL base, from $c->req->base()
293             name The application name, from $c->config->{ name }
294              
295             These can be accessed from the template in the usual way:
296              
297             <message.tt2>:
298              
299             The message is: [% message %]
300             The base is [% base %]
301             The name is [% name %]
302              
303              
304             The output generated by the template is stored in C<< $c->response->body >>.
305              
306             =head2 CAPTURING TEMPLATE OUTPUT
307              
308             If you wish to use the output of a template for some other purpose than
309             displaying in the response, e.g. for sending an email, this is possible using
310             L<Catalyst::Plugin::Email> and the L<render> method:
311              
312             sub send_email : Local {
313             my ($self, $c) = @_;
314              
315             $c->email(
316             header => [
317             To => 'me@localhost',
318             Subject => 'A TT Email',
319             ],
320             body => $c->view('TT::Alloy')->render($c, 'email.tt', {
321             additional_template_paths => [ $c->config->{root} . '/email_templates'],
322             email_tmpl_param1 => 'foo'
323             }
324             ),
325             );
326             # Redirect or display a message
327             }
328              
329             =head2 METHODS
330              
331             =over 4
332              
333             =item new
334              
335             The constructor for the TT::Alloy view.
336              
337             =item process
338              
339             Renders the template specified in C<< $c->stash->{template} >> or
340             C<< $c->action >> (the private name of the matched action. Calls C<render>
341             to perform actual rendering. Output is stored in C<< $c->response->body >>.
342              
343             =item render
344              
345             Arguments: ($c, $template, \%args)
346              
347             Renders the given template and returns output, or croaks on error.
348              
349             The template variables are set to C<%$args> if $args is a hashref, or
350             $C<< $c->stash >> otherwise. In either case the variables are augmented with
351             C<base> set to C< << $c->req->base >>, C<c> to C<$c> and C<name> to
352             C<< $c->config->{name} >>. Alternately, the C<CATALYST_VAR> configuration item
353             can be defined to specify the name of a template variable through which the
354             context reference (C<$c>) can be accessed. In this case, the C<c>, C<base> and
355             C<name> variables are omitted.
356              
357             =item config
358              
359             This method allows your view subclass to pass additional settings to
360             the TT configuration hash, or to set the options as below:
361              
362             =over 2
363              
364             =item C<CATALYST_VAR>
365              
366             Allows you to change the name of the Catalyst context object. If set, it will also
367             remove the base and name aliases, so you will have access them through <context>.
368              
369             For example:
370              
371             MyApp->config({
372             name => 'MyApp',
373             root => MyApp->path_to('root'),
374             'View::TT::Alloy' => {
375             CATALYST_VAR => 'Catalyst',
376             },
377             });
378              
379             F<message.tt2>:
380              
381             The base is [% Catalyst.req.base %]
382             The name is [% Catalyst.config.name %]
383              
384             =item C<TEMPLATE_EXTENSION>
385              
386             A sufix to add when building the template name, when
387             C<< $c->stash->{template} >> is not set.
388              
389             For example:
390              
391             package MyApp::Controller::Test;
392             sub test : Local { .. }
393              
394             Would by default look for a template in C<< <root>/test/test >>.
395              
396             If you set TEMPLATE_EXTENSION to '.tt', it will look for
397             C<< <root>/test/test.tt >>.
398              
399             =back
400              
401             =back
402              
403             =head2 HELPERS
404              
405             The L<Catalyst::Helper::View::TT::Alloy> module is provided to create
406             your view module. It is invoked by the C<myapp_create.pl> script:
407              
408             $ script/myapp_create.pl view TT::Alloy TT::Alloy
409              
410             =head1 SUPPORT
411              
412             Catalyst Mailing List:
413              
414             L<http://lists.rawmode.org/mailman/listinfo/catalyst>
415              
416             =head1 GIT REPOSITORY
417              
418             L<https://github.com/djzort/Catalyst-View-TT-Alloy>
419              
420             =head1 SEE ALSO
421              
422             L<Catalyst>, L<Catalyst::Helper::View::TT::Alloy>, L<Template::Alloy>
423              
424             =head1 AUTHORS
425              
426             Carl Franks, C<cfranks@cpan.org>
427              
428             Based on the code of C<Catalyst::View::TT>, by
429              
430             Sebastian Riedel, C<sri@cpan.org>
431              
432             Marcus Ramberg, C<mramberg@cpan.org>
433              
434             Jesse Sheidlower, C<jester@panix.com>
435              
436             Andy Wardley, C<abw@cpan.org>
437              
438             =head1 CONTRIBUTORS
439              
440             Moritz Onken, C<onken@netcubed.de>
441              
442             Dean Hamstead C<dean@bytefoundry.com.au>
443              
444             =head1 COPYRIGHT
445              
446             This program is free software, you can redistribute it and/or modify it
447             under the same terms as Perl itself.
448              
449             =cut