File Coverage

blib/lib/Mojolicious/Plugin/TtRenderer/Engine.pm
Criterion Covered Total %
statement 137 139 98.5
branch 42 56 75.0
condition 10 21 47.6
subroutine 29 29 100.0
pod 1 1 100.0
total 219 246 89.0


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::TtRenderer::Engine;
2              
3 9     9   573613 use warnings;
  9         33  
  9         317  
4 9     9   53 use strict;
  9         22  
  9         166  
5 9     9   166 use 5.010001;
  9         46  
6 9     9   59 use base 'Mojo::Base';
  9         29  
  9         977  
7 9     9   68 use Carp ();
  9         20  
  9         169  
8 9     9   53 use File::Spec ();
  9         20  
  9         222  
9 9     9   463 use Mojo::ByteStream 'b';
  9         3299  
  9         534  
10 9     9   4749 use Template ();
  9         173362  
  9         273  
11 9     9   134 use Cwd qw/abs_path/;
  9         23  
  9         478  
12 9     9   64 use Scalar::Util 'weaken';
  9         28  
  9         377  
13 9     9   549 use POSIX ':errno_h';
  9         6155  
  9         73  
14              
15             # ABSTRACT: Template Toolkit renderer for Mojolicious
16             our $VERSION = '1.60'; # VERSION
17              
18             __PACKAGE__->attr('tt');
19              
20             sub build {
21 8     8 1 741 my $self = shift->SUPER::new(@_);
22 8         120 weaken($self->{app});
23 8         33 $self->_init(@_);
24 35     35   591115 sub { $self->_render(@_) }
25 8         57 }
26              
27             sub _init {
28 8     8   19 my $self = shift;
29 8         30 my %args = @_;
30              
31             #$Template::Parser::DEBUG = 1;
32              
33 8         16 my $dir;
34 8   66     59 my $app = delete $args{mojo} || delete $args{app};
35 8 100       33 if($dir=$args{cache_dir}) {
36              
37 1 50 33     6 if($app && substr($dir,0,1) ne '/') {
38 1         7 $dir=$app->home->rel_file($dir);
39             }
40             }
41              
42             # TODO
43             # take and process options :-)
44              
45 8 50       107 my @renderer_paths = $app ? map { abs_path($_) } grep { -d $_ } @{ $app->renderer->paths } : ();
  8         482  
  9         306  
  8         50  
46 8         36 push @renderer_paths, 'templates';
47              
48             my %config = (
49             INCLUDE_PATH => \@renderer_paths,
50             COMPILE_EXT => '.ttc',
51             UNICODE => 1,
52             ENCODING => 'utf-8',
53             CACHE_SIZE => 128,
54             RELATIVE => 1,
55 8 50       20 %{$args{template_options} || {}},
  8         89  
56             );
57              
58 8 50       37 if ( !exists( $config{COMPILE_DIR} ) ) {
59 0   0     0 $config{COMPILE_DIR} //= $dir || do {
      0        
60             my $tmpdir = File::Spec->catdir(File::Spec->tmpdir, "ttr$<");
61             mkdir $tmpdir unless -d $tmpdir;
62             $tmpdir;
63             };
64             }
65              
66             $config{LOAD_TEMPLATES} =
67             [Mojolicious::Plugin::TtRenderer::Provider->new(%config, renderer => $app->renderer)]
68 8 50       77 unless $config{LOAD_TEMPLATES};
69              
70 8 50       83 $self->tt(Template->new(\%config))
71             or Carp::croak "Could not initialize Template object: $Template::ERROR";
72              
73 8         182823 $self;
74             }
75              
76             sub _render {
77 35     35   130 my ($self, $renderer, $c, $output, $options) = @_;
78              
79             # Inline
80 35         138 my $inline = $options->{inline};
81              
82             # Template
83 35         112 my $t = $renderer->template_name($options);
84 35 100       630 $t = 'inline' if defined $inline;
85 35 50       117 return unless $t;
86              
87 35         317 my $helper = Mojolicious::Plugin::TtRenderer::Helper->new(ctx => $c);
88              
89             # fixes for t/lite_app_with_default_layouts.t
90 35 100       351 unless ($c->stash->{layout}) {
91 34   66     414 $c->stash->{content} ||= $c->stash->{'mojo.content'}->{content};
92             }
93              
94 35         684 my @params = ({%{$c->stash}, c => $c, h => $helper}, $output, {binmode => ':utf8'});
  35         220  
95 35         676 my $provider = $self->tt->{SERVICE}->{CONTEXT}->{LOAD_TEMPLATES}->[0];
96 35         315 $provider->options($options);
97 35         126 $provider->ctx($c);
98              
99 35         304 my $ok = do {
100 35 100       119 if (defined $inline) {
101 1         5 $self->tt->process(\$inline, @params);
102             }
103             else {
104 34         265 my @ret = $provider->fetch($t);
105              
106 34 100       32338 if (not defined $ret[1]) {
    50          
107 26         122 $self->tt->process($ret[0], @params);
108             }
109             elsif (not defined $ret[0]) { # not found
110 0         0 return;
111             }
112             else { # error
113 8 100 66     167 return if $! == ENOENT && (not ref $ret[0]); # not found when not blessed exception
114 2         27 die $ret[0];
115             }
116             }
117             };
118              
119             # Error
120 27 100       14087 die $self->tt->error unless $ok;
121             }
122              
123             1; # End of Mojolicious::Plugin::TtRenderer::Engine
124              
125             package
126             Mojolicious::Plugin::TtRenderer::Helper;
127              
128 9     9   12804 use strict;
  9         26  
  9         287  
129 9     9   71 use warnings;
  9         62  
  9         363  
130              
131 9     9   55 use base 'Mojo::Base';
  9         24  
  9         2734  
132              
133             our $AUTOLOAD;
134              
135             __PACKAGE__->attr('ctx');
136              
137             sub AUTOLOAD {
138 8     8   2328 my $self = shift;
139              
140 8         19 my $method = $AUTOLOAD;
141              
142 8 50       49 return if $method =~ /^[A-Z]+?$/;
143 8 50       25 return if $method =~ /^_/;
144 8 50       35 return if $method =~ /(?:\:*?)DESTROY$/;
145              
146 8         43 $method = (split '::' => $method)[-1];
147              
148 8 100       45 die qq/Unknown helper: $method/ unless $self->ctx->app->renderer->helpers->{$method};
149              
150 7         139 $self->ctx->$method(@_);
151             }
152              
153             1;
154              
155             package
156             Mojolicious::Plugin::TtRenderer::Provider;
157              
158 9     9   80 use strict;
  9         21  
  9         231  
159 9     9   50 use warnings;
  9         24  
  9         302  
160              
161 9     9   57 use base 'Template::Provider';
  9         20  
  9         939  
162 9     9   69 use Scalar::Util 'weaken';
  9         21  
  9         4921  
163              
164             sub new {
165 8     8   68 my $class = shift;
166 8         41 my %params = @_;
167              
168 8         35 my $renderer = delete $params{renderer};
169              
170 8         89 my $self = $class->SUPER::new(%params);
171 8         6388 $self->renderer($renderer);
172 8         38 weaken($self->{renderer});
173 8         39 $self;
174             }
175              
176 42 100   42   282 sub renderer { @_ > 1 ? $_[0]->{renderer} = $_[1] : $_[0]->{renderer} }
177 35 50   35   147 sub ctx { @_ > 1 ? $_[0]->{ctx} = $_[1] : $_[0]->{ctx} }
178 35 50   35   157 sub options { @_ > 1 ? $_[0]->{options} = $_[1] : $_[0]->{options} }
179              
180             sub _template_modified {
181 104     104   275510 my($self, $template) = @_;
182 104 100 100     391 $self->SUPER::_template_modified($template) || $template =~ /^templates(?:\/|\\)/ || undef;
183             }
184              
185             sub _template_content {
186 41     41   1164 my $self = shift;
187 41         113 my ($path) = @_;
188              
189 41         149 my $options = delete $self->{options};
190            
191             # Convert backslashes to forward slashes to make inline templates work on Windows
192 41         128 $path =~ s/\\/\//g;
193 41         271 my ($t) = ($path =~ m{templates\/(.*)$});
194            
195 41 100       467 if (-r $path) {
196 7         73 return $self->SUPER::_template_content(@_);
197             }
198              
199 34         97 my $data;
200 34         75 my $error = '';
201              
202             # Try DATA section
203 34 100       102 if(defined $options) {
204 26         89 $data = $self->renderer->get_data_template($options);
205             } else {
206 8         21 foreach my $class (@{ $self->renderer->classes }) {
  8         30  
207 11         82 $data = Mojo::Loader::data_section($class, $t);
208 11 100       138 last if $data;
209             }
210             }
211              
212 34 100       1028 unless($data) {
213 8         43 $data = '';
214 8         24 $error = "$path: not found";
215             }
216 34 50       207 wantarray ? ($data, $error, time) : $data;
217             }
218              
219             1;
220              
221             __END__