File Coverage

blib/lib/Dancer2/Template/TextTemplate/FakeEngine.pm
Criterion Covered Total %
statement 62 63 98.4
branch 26 32 81.2
condition 11 18 61.1
subroutine 15 15 100.0
pod 1 1 100.0
total 115 129 89.1


line stmt bran cond sub pod time code
1             package Dancer2::Template::TextTemplate::FakeEngine;
2             # ABSTRACT: Fake Template::Toolkit-like, persistent engine around Text::Template.
3              
4 5     5   347189 use strict;
  5         7  
  5         137  
5 5     5   19 use warnings;
  5         6  
  5         202  
6              
7             our $VERSION = '1.002'; # TRIAL VERSION
8              
9 5     5   1774 use Moo;
  5         32936  
  5         23  
10 5     5   6757 use MooX::Types::MooseLike::Base qw( InstanceOf Bool ArrayRef Int Str );
  5         23321  
  5         442  
11 5     5   38 use Carp 'croak';
  5         8  
  5         210  
12 5     5   3257 use Text::Template 1.46;
  5         11916  
  5         206  
13 5     5   2568 use CHI;
  5         296289  
  5         193  
14 5     5   2911 use Safe 2.26;
  5         154162  
  5         343  
15 5     5   50 use Scalar::Util 'blessed';
  5         8  
  5         351  
16 5     5   2437 use namespace::clean;
  5         38560  
  5         34  
17              
18              
19              
20             has _cache => (
21             is => 'rwp',
22             isa => InstanceOf['CHI::Driver'],
23             lazy => 1,
24             builder => '_build_cache',
25             );
26              
27             sub _build_cache {
28 2     2   54 my $self = shift;
29 2         30 return CHI->new(
30             driver => 'Memory', # THIS should be generalized
31             expires_on_backend => 1,
32             global => 1, # CHI::Driver::Memory-specific
33             );
34             }
35              
36              
37             has caching => (
38             is => 'rw',
39             isa => Bool,
40             default => 1,
41             );
42              
43              
44             has expires => (
45             is => 'rw',
46             isa => Int,
47             default => 3600,
48             );
49              
50              
51             has delimiters => (
52             is => 'rw',
53             isa => ArrayRef[Str],
54             default => sub { [ '{', '}' ] },
55             );
56              
57              
58             has cache_stringrefs => (
59             is => 'rw',
60             isa => Bool,
61             default => 1,
62             );
63              
64              
65             has prepend => (
66             is => 'rw',
67             isa => Str,
68             default => <<'END',
69             use strict;
70             use warnings FATAL => 'all';
71             END
72             );
73              
74             # Text::Template's HASH variables (as exclusively used by FakeEngine) are not
75             # installed in the template evaluation package in a "use strict"-compatible
76             # way, but we enforce "use strict" in PREPEND, so we need to declare ourselves
77             # these variables just after the PREPENDed code.
78             sub _declare_arg_variables {
79 21     21   105 my $hash = shift;
80 21         22 my @decls;
81 21         107 while ( my ( $name, $value ) = each %$hash ) {
82 7 50       17 next unless defined $value;
83 7         7 push @decls, do {
84 7 50       29 if ( ref $value eq 'ARRAY' ) { '@' }
  0 100       0  
85 6         24 elsif ( ref $value eq 'HASH' ) { '%' }
86 1         6 else { '$' }
87             }
88             . $name;
89             }
90 21         266 return join "\n" => map { "our $_;" } @decls;
  7         127  
91             }
92              
93              
94             has safe => (
95             is => 'rw',
96             isa => Bool,
97             default => 1,
98             );
99              
100             has safe_opcodes => (
101             is => 'rw',
102             isa => ArrayRef[Str],
103             default => sub { [qw[ :default require caller dofile ]] },
104             trigger => sub {
105             my $self = shift;
106             $self->_safe->permit_only(@{ $_[0] });
107             },
108             );
109              
110             has safe_disposable => (
111             is => 'rw',
112             isa => Bool,
113             default => 0,
114             trigger => sub {
115             my $self = shift;
116             $self->_rebuild_safe if $_[0];
117             },
118             );
119              
120             has _safe => (
121             is => 'rw',
122             isa => InstanceOf['Safe'],
123             lazy => 1,
124             builder => '_build_safe',
125             );
126              
127             sub _build_safe {
128 12     12   138 my $self = shift;
129 12         59 my $safe = Safe->new;
130 12         7237 $safe->permit_only(@{ $self->safe_opcodes });
  12         222  
131 12         277 return $safe;
132             }
133              
134             sub _rebuild_safe {
135 9     9   150 my $self = shift;
136 9 50       109 $self->_safe($self->_build_safe) if $self->safe_disposable;
137 9         823 return;
138             }
139              
140              
141             sub process {
142 21     21 1 15593 my ( $self, $template, $tokens ) = @_;
143              
144 21 50 33     255 defined $template
      66        
      33        
145             && !blessed($template)
146             && ( ref $template || -f $template )
147             or croak "$template is not a regular file (name) or a string reference";
148              
149 21 100       386 my $tt = $self->caching
    100          
150             ? $self->_cache->get( ref $template ? $$template : $template )
151             : undef;
152 21 100       144902 unless ($tt) { # either we don't cache or the cached instance expired
153 19 100       293 $tt = Text::Template->new(
    100          
154             TYPE => ref $template ? 'STRING' : 'FILE',
155             SOURCE => ref $template ? $$template : $template,
156             DELIMITERS => $self->delimiters,
157             );
158             }
159              
160 21 50       2135 my $computed = $tt->fill_in(
    100          
161             HASH => $tokens,
162             PREPEND => $self->prepend . _declare_arg_variables($tokens),
163             $self->safe ? ( SAFE => $self->_safe ) : (),
164             ) or our $ERROR = $Text::Template::ERROR;
165              
166 21 100 66     19754 $self->_rebuild_safe if $self->safe && $self->safe_disposable;
167              
168 21 100 100     690 if ( defined $computed && $self->caching ) {
169 5 100 66     82 if ( ref $template && $self->cache_stringrefs ) {
170 2         50 $self->_cache->set( $$template, $tt, 'never' );
171             }
172             else { # filenames
173 3 50       40 $self->_cache->set( $template, $tt,
174             $self->expires > 0
175             ? { expires_in => $self->expires }
176             : 'never' );
177             }
178             }
179              
180 21         1465 return $computed;
181             }
182              
183             1;
184              
185             __END__