File Coverage

blib/lib/MVC/Neaf/View/TT.pm
Criterion Covered Total %
statement 59 60 98.3
branch 14 16 87.5
condition 7 15 46.6
subroutine 11 11 100.0
pod 3 3 100.0
total 94 105 89.5


line stmt bran cond sub pod time code
1             package MVC::Neaf::View::TT;
2              
3 23     23   145418 use 5.006;
  23         142  
4 23     23   155 use strict;
  23         89  
  23         543  
5 23     23   127 use warnings;
  23         39  
  23         1124  
6              
7             our $VERSION = '0.29';
8              
9             =head1 NAME
10              
11             MVC::Neaf::View::TT - Template toolkit-based view module for Neaf.
12              
13             =head1 SYNOPSYS
14              
15             # Somewhere in your app
16             return {
17             -view => 'TT',
18             -template => 'foo.tt',
19             title => 'Page title',
20             ....
21             };
22             # Neaf knows it's time to render foo.tt with returned data as stash
23             # and return result to user
24              
25             # What actually happens
26             my $view = MVC::Neaf::View::TT->new;
27             my $content = $view->render( { ... } );
28              
29             # And if in foo.tt
30             [% title %]
31              
32             # Then in $content it becomes
33             Page title
34              
35             =head1 DESCRIPTION
36              
37             This module is one of core rendering engines of L
38             known under C alias.
39              
40             See also C.
41              
42             =head1 METHODS
43              
44             =cut
45              
46 23     23   146 use Carp;
  23         67  
  23         1611  
47 23     23   12740 use Template;
  23         512006  
  23         774  
48 23     23   172 use Template::Provider;
  23         56  
  23         943  
49              
50             our @CARP_NOT = qw(MVC::Neaf::View MVC::Neaf MVC::Neaf::Request);
51              
52 23     23   962 use parent qw(MVC::Neaf::View);
  23         608  
  23         190  
53              
54             =head2 new( %options )
55              
56             %options may include:
57              
58             =over
59              
60             =item * template - default template to use.
61              
62             =item * preserve_dash - don't strip dashed options. Useful for debugging.
63              
64             =item * preload => { name => 'in-memory template' } - preload some templates.
65             See C below.
66              
67             =item * INCLUDE_PATH => [path, ...] - will be calculated relative
68             to the calling file, if not starts with a '/'.
69              
70             =back
71              
72             Also any UPPERCASE OPTIONS will be forwarded to the backend
73             (i.e. Template object) w/o changes.
74              
75             Any extra options except those above will cause an exception.
76              
77             =cut
78              
79             my %new_opt;
80             $new_opt{$_}++ for qw( template preserve_dash engine preload preload_auto neaf_base_dir );
81              
82             my @opt_provider = qw(
83             INCLUDE_PATH ABSOLUTE RELATIVE DEFAULT ENCODING CACHE_SIZE STAT_TTL
84             COMPILE_EXT COMPILE_DIR TOLERANT PARSER DEBUG EVAL_PERL
85             );
86              
87             sub new {
88 17     17 1 646 my ($class, %opt) = @_;
89              
90 17         44 my %tt_opt;
91             $tt_opt{$_} = delete $opt{$_}
92 17         136 for grep { /^[A-Z]/ } keys %opt;
  22         178  
93 17         57 my @extra = grep { !$new_opt{$_} } keys %opt;
  15         52  
94 17 50       68 croak( "$class->new: Unknown options @extra" )
95             if @extra;
96              
97 17         41 my $engine = delete $opt{engine};
98 17         44 my $preload = delete $opt{preload};
99 17         209 my $self = $class->SUPER::new(%opt);
100              
101 17   33     192 $self->{engine} ||= do {
102             # enforce non-absolute paths to be calculated relative to caller file
103 17   100     186 $tt_opt{INCLUDE_PATH} = $self->dir( $tt_opt{INCLUDE_PATH} || [] );
104              
105 17         48 my %prov_opt;
106 17         53 foreach( @opt_provider) {
107             $prov_opt{$_} = $tt_opt{$_}
108 221 100       499 if defined $tt_opt{$_};
109             };
110              
111             my $prov = delete $tt_opt{LOAD_TEMPLATES} || [
112 17   50     285 Template::Provider->new(\%prov_opt)
113             ];
114 17         1729 $self->{engine_preload} = Template::Provider->new({
115             %prov_opt,
116             CACHE_SIZE => undef,
117             STAT_TTL => 4_000_000_000,
118             });
119             # shallow copy (not unshift) to avoid spoiling original values
120 17         1270 $prov = [ $self->{engine_preload}, @$prov ];
121              
122 17         248 Template->new (%tt_opt, LOAD_TEMPLATES => $prov);
123             };
124              
125              
126             # TODO 0.40 automagically preload from the calling file's DATA section
127 17 100       356355 if ( ref $preload eq 'HASH' ) {
    50          
128             $self->preload( $_ => $preload->{$_} )
129 1         8 for keys %$preload;
130             } elsif ($preload) {
131 0   0     0 $self->_croak("preload must be a hash, not ".(ref $preload || "a scalar") );
132             };
133 17         110 return $self;
134             };
135              
136             =head2 render( \%data )
137              
138             Returns a pair of values: ($content, $content_type).
139              
140             Content-type defaults to text/html.
141              
142             The template is determined from (1) -template in data (2) template in new().
143             If neither is present, empty string and "text/plain" are returned.
144              
145             =cut
146              
147             sub render {
148 21     21 1 6726 my ($self, $data) = @_;
149              
150 21   66     98 my $template = $data->{-template} || $self->{template};
151              
152 21 100       68 if (!defined $template) {
153 1         256 croak __PACKAGE__.": -template option is required";
154             };
155              
156 20         37 my $out;
157             $self->{engine}->process( $template, $data, \$out )
158 20 100       120 or $self->_croak( $self->{engine}->error );
159              
160 16 100       243411 return wantarray ? ($out, "text/html") : $out;
161             };
162              
163             =head2 preload ( name => "[% in_memory_template %]", ... )
164              
165             Store precompiled templates under given names.
166              
167             Returns self, dies on error.
168              
169             =cut
170              
171             sub preload {
172 6     6 1 3446 my ($self, %tpls) = @_;
173              
174 6         24 foreach (keys %tpls) {
175 9 100       251 my $compiled = eval { $self->{engine}->template( \$tpls{$_} ) }
  9         69  
176             or $self->_croak( "$_: $@" );
177              
178 8         149554 $self->{engine_preload}->store( $_, $compiled );
179             };
180              
181 5         546 return $self;
182             };
183              
184             sub _croak {
185 5     5   59198 my ($self, @msg) = @_;
186              
187 5         48 my $where = [caller(1)]->[3];
188 5         101 $where =~ s/.*:://;
189              
190 5   33     310 croak join "", (ref $self || $self), '->', $where, "(): ", @msg;
191             };
192              
193             =head1 SEE ALSO
194              
195             L