File Coverage

blib/lib/Text/Xslate.pm
Criterion Covered Total %
statement 280 299 93.6
branch 87 102 85.2
condition 23 29 79.3
subroutine 36 38 94.7
pod 1 2 50.0
total 427 470 90.8


line stmt bran cond sub pod time code
1             package Text::Xslate;
2             # The Xslate engine class
3 180     180   5089823 use 5.008_001;
  180         714  
4 180     180   1001 use strict;
  180         344  
  180         4193  
5 180     180   979 use warnings;
  180         339  
  180         7979  
6              
7             our $VERSION = '3.3.8';
8              
9 180     180   970 use Carp ();
  180         420  
  180         3369  
10 180     180   953 use File::Spec ();
  180         353  
  180         3252  
11 180     180   915 use Exporter ();
  180         392  
  180         3208  
12 180     180   141198 use Data::MessagePack ();
  180         216999  
  180         4553  
13 180     180   1150 use Scalar::Util ();
  180         353  
  180         3247  
14              
15 180     180   102167 use Text::Xslate::Util ();
  180         527  
  180         10460  
16             BEGIN {
17             # all the exportable functions are defined in ::Util
18 180     180   658 our @EXPORT_OK = qw(
19             mark_raw
20             unmark_raw
21             escaped_string
22             html_escape
23             uri_escape
24             html_builder
25             );
26 180         70936 Text::Xslate::Util->import(@EXPORT_OK);
27             }
28              
29             our @ISA = qw(Text::Xslate::Engine);
30              
31             my $BYTECODE_VERSION = '1.6';
32              
33             # $bytecode_version + $fullpath + $compiler_and_parser_options
34             my $XSLATE_MAGIC = qq{xslate;$BYTECODE_VERSION;%s;%s;};
35              
36             our $DEFAULT_CACHE_DIR;
37              
38             # load backend (XS or PP)
39             my $use_xs = 0;
40             if(!exists $INC{'Text/Xslate/PP.pm'}) {
41             my $pp = ($Text::Xslate::Util::DEBUG =~ /\b pp \b/xms or $ENV{PERL_ONLY});
42             if(!$pp) {
43             eval {
44             require XSLoader;
45             XSLoader::load(__PACKAGE__, $VERSION);
46             $use_xs = 1;
47             };
48             die $@ if $@ && $Text::Xslate::Util::DEBUG =~ /\b xs \b/xms; # force XS
49             }
50             if(!__PACKAGE__->can('render')) {
51             require 'Text/Xslate/PP.pm';
52             }
53             }
54 0     0 0 0 sub USE_XS() { $use_xs }
55              
56             # for error messages (see T::X::Util)
57 2766 100   2766 1 23826 sub input_layer { ref($_[0]) ? $_[0]->{input_layer} : ':utf8' }
58              
59             package Text::Xslate::Engine; # XS/PP common base class
60              
61 180         38844 use Text::Xslate::Util qw(
62             make_error
63             dump
64 180     180   1086 );
  180         1559  
65              
66             # constants
67             BEGIN {
68 180     180   1814 our @ISA = qw(Exporter);
69              
70 180         516 my $dump_load = scalar($Text::Xslate::Util::DEBUG =~ /\b dump=load \b/xms);
71 180         2759 *_DUMP_LOAD = sub(){ $dump_load };
  0         0  
72              
73 180         2913 my $save_src = scalar($Text::Xslate::Util::DEBUG =~ /\b save_src \b/xms);
74 180         2278 *_SAVE_SRC = sub() { $save_src };
  0         0  
75              
76 180         714005 *_ST_MTIME = sub() { 9 }; # see perldoc -f stat
77             }
78              
79             unless(defined $DEFAULT_CACHE_DIR) {
80             my $cache_dir = '.xslate_cache';
81             foreach my $d($ENV{HOME}, File::Spec->tmpdir) {
82             if(defined($d) and -d $d and -w _) {
83             $cache_dir = File::Spec->catfile($d, '.xslate_cache');
84             last;
85             }
86             }
87              
88             $DEFAULT_CACHE_DIR = $cache_dir;
89             }
90              
91             # the real defaults are defined in the parser
92             my %parser_option = (
93             line_start => undef,
94             tag_start => undef,
95             tag_end => undef,
96             );
97              
98             # the real defaults are defined in the compiler
99             my %compiler_option = (
100             syntax => undef,
101             type => undef,
102             header => undef, # template augment
103             footer => undef, # template augment
104             macro => undef, # template augment
105             );
106              
107             my %builtin = (
108             html_escape => \&Text::Xslate::Util::html_escape,
109             mark_raw => \&Text::Xslate::Util::mark_raw,
110             unmark_raw => \&Text::Xslate::Util::unmark_raw,
111             uri_escape => \&Text::Xslate::Util::uri_escape,
112              
113             is_array_ref => \&Text::Xslate::Util::is_array_ref,
114             is_hash_ref => \&Text::Xslate::Util::is_hash_ref,
115              
116             dump => \&Text::Xslate::Util::dump,
117              
118             # aliases
119             raw => 'mark_raw',
120             html => 'html_escape',
121             uri => 'uri_escape',
122             );
123              
124 289     289   5138 sub default_functions { +{} } # overridable
125              
126             sub parser_option { # overridable
127 632     632   11386 return \%parser_option;
128             }
129              
130             sub compiler_option { # overridable
131 632     632   18161 return \%compiler_option;
132             }
133              
134             sub replace_option_value_for_magic_token { # overridable
135             #my($self, $name, $value) = @_;
136             #$value;
137 26     26   52 return $_[2];
138             }
139              
140             sub options { # overridable
141 292     292   2550 my($self) = @_;
142             return {
143             # name => default
144             suffix => '.tx',
145             path => ['.'],
146             input_layer => $self->input_layer,
147             cache => 1, # 0: not cached, 1: checks mtime, 2: always cached
148             cache_dir => $DEFAULT_CACHE_DIR,
149             module => undef,
150             function => undef,
151             html_builder_module => undef,
152             compiler => 'Text::Xslate::Compiler',
153              
154             verbose => 1,
155             warn_handler => undef,
156             die_handler => undef,
157             pre_process_handler => undef,
158              
159 292         3458 %{ $self->parser_option },
160 292         3589 %{ $self->compiler_option },
  292         3135  
161             };
162             }
163              
164             sub new {
165 292     292   3222198 my $class = shift;
166 292 100       4165 my %args = (@_ == 1 ? %{$_[0]} : @_);
  12         66  
167              
168 292         3658 my $options = $class->options;
169 292         2644 my $used = 0;
170 292         2555 my $nargs = scalar keys %args;
171 292         2354 foreach my $key(keys %{$options}) {
  292         5415  
172 6136 100       19499 if(exists $args{$key}) {
    100          
173 718         9704 $used++;
174             }
175             elsif(defined($options->{$key})) {
176 1565         20448 $args{$key} = $options->{$key};
177             }
178             }
179              
180 292 100       3291 if($used != $nargs) {
181 2         7 my @unknowns = sort grep { !exists $options->{$_} } keys %args;
  17         40  
182 2         600 warnings::warnif(misc
183             => "$class: Unknown option(s): " . join ' ', @unknowns);
184             }
185              
186             $args{path} = [
187 304 100       23729 map { ref($_) ? $_ : File::Spec->rel2abs($_) }
188 248         4406 ref($args{path}) eq 'ARRAY' ? @{$args{path}} : $args{path}
189 291 100       3397 ];
190              
191 291         2455 my $arg_function= $args{function};
192              
193 291         2229 my %funcs;
194 291         2696 $args{function} = \%funcs;
195              
196 291         2486 $args{template} = {}; # template structures
197              
198 291         3419 my $self = bless \%args, $class;
199              
200             # definition of functions and methods
201              
202             # builtin functions
203 290         5055 %funcs = %builtin;
204 290         8065 $self->_register_builtin_methods(\%funcs);
205              
206             # per-class functions
207 290         3681 $self->_merge_hash(\%funcs, $class->default_functions());
208              
209             # user-defined functions
210 290 100       3142 if(defined $args{module}) {
211             $self->_merge_hash(\%funcs,
212 11         27 Text::Xslate::Util::import_from(@{$args{module}}));
  11         59  
213             }
214              
215             # user-defined html builder functions
216 288 100       2814 if(defined $args{html_builder_module}) {
217 1         2 my $raw = Text::Xslate::Util::import_from(@{$args{html_builder_module}});
  1         6  
218             my $html_builders = +{
219             map {
220 1         4 ($_ => &Text::Xslate::Util::html_builder($raw->{$_}))
  1         5  
221             } keys %$raw
222             };
223 1         4 $self->_merge_hash(\%funcs, $html_builders);
224             }
225              
226 288         2714 $self->_merge_hash(\%funcs, $arg_function);
227              
228 288         3593 $self->_resolve_function_aliases(\%funcs);
229              
230 288         6110 return $self;
231             }
232              
233             sub _merge_hash {
234 588     588   4406 my($self, $base, $add) = @_;
235 588         4223 foreach my $name(keys %{$add}) {
  588         8474  
236 98         331 $base->{$name} = $add->{$name};
237             }
238 588         8187 return;
239             }
240              
241             sub _resolve_function_aliases {
242 288     288   2422 my($self, $funcs) = @_;
243              
244 288         2290 foreach my $f(values %{$funcs}) {
  288         4899  
245 7003         48669 my %seen; # to avoid infinite loops
246 7003   100     75884 while(!( ref($f) or Scalar::Util::looks_like_number($f) )) {
247 863 50       7819 my $v = $funcs->{$f} or $self->_error(
248             "Cannot resolve a function alias '$f',"
249             . " which refers nothing",
250             );
251              
252 863 50 33     8198 if( ref($v) or Scalar::Util::looks_like_number($v) ) {
253 863         6345 $f = $v;
254 863         12076 last;
255             }
256             else {
257 0 0       0 $seen{$v}++ and $self->_error(
258             "Cannot resolve a function alias '$f',"
259             . " which makes circular references",
260             );
261             }
262             }
263             }
264              
265 288         4065 return;
266             }
267              
268             sub load_string { # called in render_string()
269 1349     1349   245894 my($self, $string) = @_;
270 1349 100       3868 if(not defined $string) {
271 1         7 $self->_error("LoadError: Template string is not given");
272             }
273 1348         1754 $self->note(' _load_string: %s', join '\n', split /\n/, $string)
274             if _DUMP_LOAD;
275 1348         1662 $self->{source}{''} = $string if _SAVE_SRC;
276 1348         3285 $self->{string_buffer} = $string;
277 1348         4145 my $asm = $self->compile($string);
278 1284         37617 $self->_assemble($asm, '', \$string, undef, undef);
279 1284         1038974 return $asm;
280             }
281              
282             my $updir = File::Spec->updir;
283             sub find_file {
284 2216     2216   9173 my($self, $file) = @_;
285              
286 2216 100       9471 if($file =~ /\Q$updir\E/xmso) {
287 4         24 $self->_error("LoadError: Forbidden component (updir: '$updir') found in file name '$file'");
288             }
289              
290 2212         4489 my $fullpath;
291             my $cachepath;
292 0         0 my $orig_mtime;
293 0         0 my $cache_mtime;
294 2212         5025 foreach my $p(@{$self->{path}}) {
  2212         9520  
295 2227         4045 $self->note(" find_file: %s in %s ...\n", $file, $p) if _DUMP_LOAD;
296              
297 2227         4459 my $cache_prefix;
298 2227 100       6700 if(ref $p eq 'HASH') { # virtual path
299 97 100       405 defined(my $content = $p->{$file}) or next;
300 92         169 $fullpath = \$content;
301              
302             # NOTE:
303             # Because contents of virtual paths include their digest,
304             # time-dependent cache verifier makes no sense.
305 92         148 $orig_mtime = 0;
306 92         137 $cache_mtime = 0;
307 92         178 $cache_prefix = 'HASH';
308             }
309             else {
310 2130         32458 $fullpath = File::Spec->catfile($p, $file);
311 2130 100       56312 defined($orig_mtime = (stat($fullpath))[_ST_MTIME])
312             or next;
313 2115         17778 $cache_prefix = Text::Xslate::uri_escape($p);
314 2115 50       9079 if (length $cache_prefix > 127) {
315             # some filesystems refuse a path part with length > 127
316 0         0 $cache_prefix = $self->_digest($cache_prefix);
317             }
318             }
319              
320             # $file is found
321             $cachepath = File::Spec->catfile(
322             $self->{cache_dir},
323 2207         28249 $cache_prefix,
324             $file . 'c',
325             );
326             # stat() will be failed if the cache doesn't exist
327 2207         33078 $cache_mtime = (stat($cachepath))[_ST_MTIME];
328 2207         7988 last;
329             }
330              
331 2212 100       7204 if(not defined $orig_mtime) {
332 5         21 $self->_error("LoadError: Cannot find '$file' (path: @{$self->{path}})");
  5         61  
333             }
334              
335 2207         4371 $self->note(" find_file: %s (mtime=%d)\n",
336             $fullpath, $cache_mtime || 0) if _DUMP_LOAD;
337              
338             return {
339 2207 100       17260 name => ref($fullpath) ? $file : $fullpath,
340             fullpath => $fullpath,
341             cachepath => $cachepath,
342              
343             orig_mtime => $orig_mtime,
344             cache_mtime => $cache_mtime,
345             };
346             }
347              
348              
349             sub load_file {
350 2100     2100   3460912 my($self, $file, $mtime, $omit_augment) = @_;
351              
352 2100         7827 local $self->{omit_augment} = $omit_augment;
353              
354 2100         4198 $self->note("%s->load_file(%s)\n", $self, $file) if _DUMP_LOAD;
355              
356 2100 100       7687 if($file eq '') { # simply reload it
357 1         9 return $self->load_string($self->{string_buffer});
358             }
359              
360 2099         7593 my $fi = $self->find_file($file);
361              
362 2093   100     7913 my $asm = $self->_load_compiled($fi, $mtime) || $self->_load_source($fi, $mtime);
363              
364             # $cache_mtime is undef : uses caches without any checks
365             # $cache_mtime > 0 : uses caches with mtime checks
366             # $cache_mtime == 0 : doesn't use caches
367 2088         4562 my $cache_mtime;
368 2088 100       7625 if($self->{cache} < 2) {
369 2081   100     11131 $cache_mtime = $fi->{cache_mtime} || 0;
370             }
371              
372 2088         45685 $self->_assemble($asm, $file, $fi->{fullpath}, $fi->{cachepath}, $cache_mtime);
373 2088         70529 return $asm;
374             }
375              
376             sub slurp_template {
377 2050     2050   5325 my($self, $input_layer, $fullpath) = @_;
378              
379 2050 100       6115 if (ref $fullpath eq 'SCALAR') {
380 70         267 return $$fullpath;
381             } else {
382 1980 50   2   89511 open my($source), '<' . $input_layer, $fullpath
  2         17  
  2         4  
  2         16  
383             or $self->_error("LoadError: Cannot open $fullpath for reading: $!");
384 1980         128336 local $/;
385 1980         69347 return scalar <$source>;
386             }
387             }
388              
389             sub _load_source {
390 2024     2024   4765 my($self, $fi) = @_;
391 2024         5056 my $fullpath = $fi->{fullpath};
392 2024         4657 my $cachepath = $fi->{cachepath};
393              
394 2024         4121 $self->note(" _load_source: try %s ...\n", $fullpath) if _DUMP_LOAD;
395              
396             # This routine is called when the cache is no longer valid (or not created yet)
397             # so it should be ensured that the cache, if exists, does not exist
398 2024 100       27124 if(-e $cachepath) {
399 29 50       3438 unlink $cachepath
400             or Carp::carp("Xslate: cannot unlink $cachepath (ignored): $!");
401             }
402              
403 2024         7264 my $source = $self->slurp_template($self->input_layer, $fullpath);
404 2024 100       8704 $source = $self->{pre_process_handler}->($source) if $self->{pre_process_handler};
405 2024         4403 $self->{source}{$fi->{name}} = $source if _SAVE_SRC;
406              
407             my $asm = $self->compile($source,
408             file => $fullpath,
409             name => $fi->{name},
410 2024         8066 );
411              
412 2019 100       8414 if($self->{cache} >= 1) {
413 88         1968 my($volume, $dir) = File::Spec->splitpath($fi->{cachepath});
414 88         937 my $cachedir = File::Spec->catpath($volume, $dir, '');
415 88 100       2441 if(not -e $cachedir) {
416 34         314 require File::Path;
417 34         12361 File::Path::mkpath($cachedir);
418 34 50       202209 if (! -e $cachedir) {
419 0         0 Carp::croak("Xslate: Cannot prepare cache directory $cachepath (ignored): $@");
420             }
421             }
422              
423 88         1032 my $tmpfile = sprintf('%s.%d.%d', $cachepath, $$, Scalar::Util::refaddr($self));
424              
425 88 50       17388 if (open my($out), ">:raw", $tmpfile) {
426 88         809 my $mtime = $self->_save_compiled($out, $asm, $fullpath, utf8::is_utf8($source));
427              
428 88 50       13547 if(!close $out) {
    50          
429 0         0 Carp::carp("Xslate: Cannot close $cachepath (ignored): $!");
430 0         0 unlink $tmpfile;
431             }
432             elsif (rename($tmpfile => $cachepath)) {
433             # set the newest mtime of all the related files to cache mtime
434 88 100       291 if (not ref $fullpath) {
435 62         1922 my $main_mtime = (stat $fullpath)[_ST_MTIME];
436 62 100 66     491 if (defined($main_mtime) && $main_mtime > $mtime) {
437 52         102 $mtime = $main_mtime;
438             }
439 62         1675 utime $mtime, $mtime, $cachepath;
440 62         425 $fi->{cache_mtime} = $mtime;
441             }
442             else {
443 26         543 $fi->{cache_mtime} = (stat $cachepath)[_ST_MTIME];
444             }
445             }
446             else {
447 0         0 Carp::carp("Xslate: Cannot rename cache file $cachepath (ignored): $!");
448 0         0 unlink $tmpfile;
449             }
450             }
451             else {
452 0         0 Carp::carp("Xslate: Cannot open $cachepath for writing (ignored): $!");
453             }
454             }
455 2019         4053 if(_DUMP_LOAD) {
456             $self->note(" _load_source: cache(mtime=%s)\n",
457             defined $fi->{cache_mtime} ? $fi->{cache_mtime} : 'undef');
458             }
459              
460 2019         11272 return $asm;
461             }
462              
463             # load compiled templates if they are fresh enough
464             sub _load_compiled {
465 2093     2093   5110 my($self, $fi, $threshold) = @_;
466              
467 2093 100       6959 if($self->{cache} >= 2) {
468             # threshold is the most latest modified time of all the related caches,
469             # so if the cache level >= 2, they seems always fresh.
470 7         20 $threshold = 9**9**9; # force to purge the cache
471             }
472             else {
473 2086   100     12800 $threshold ||= $fi->{cache_mtime};
474             }
475             # see also tx_load_template() in xs/Text-Xslate.xs
476 2093 100 66     8979 if(!( defined($fi->{cache_mtime}) and $self->{cache} >= 1
      100        
477             and $threshold >= $fi->{orig_mtime} )) {
478 2009         4076 $self->note( " _load_compiled: no fresh cache: %s, %s",
479             $threshold || 0, Text::Xslate::Util::p($fi) ) if _DUMP_LOAD;
480 2009         4651 $fi->{cache_mtime} = undef;
481 2009         12324 return undef;
482             }
483              
484 84         194 my $cachepath = $fi->{cachepath};
485 84 50       3744 open my($in), '<:raw', $cachepath
486             or $self->_error("LoadError: Cannot open $cachepath for reading: $!");
487              
488 84         381 my $magic = $self->_magic_token($fi->{fullpath});
489 84         158 my $data;
490 84         1543 read $in, $data, length($magic);
491 84 100       285 if($data ne $magic) {
492 15         330 return undef;
493             }
494             else {
495 69         293 local $/;
496 69         955 $data = <$in>;
497 69         672 close $in;
498             }
499 69         836 my $unpacker = Data::MessagePack::Unpacker->new();
500 69         296 my $offset = $unpacker->execute($data);
501 69         277 my $is_utf8 = $unpacker->data();
502 69         202 $unpacker->reset();
503              
504 69         203 $unpacker->utf8($is_utf8);
505              
506 69         102 my @asm;
507 69 100       377 if($is_utf8) { # TODO: move to XS?
508 58         112 my $seed = "";
509 58         165 utf8::upgrade($seed);
510 58         227 push @asm, ['print_raw_s', $seed, __LINE__, __FILE__];
511             }
512 69         234 while($offset < length($data)) {
513 1255         4738 $offset = $unpacker->execute($data, $offset);
514 1255         2418 my $c = $unpacker->data();
515 1255         2330 $unpacker->reset();
516              
517             # my($name, $arg, $line, $file, $symbol) = @{$c};
518 1255 100       3565 if($c->[0] eq 'depend') {
    100          
519 2         84 my $dep_mtime = (stat $c->[1])[_ST_MTIME];
520 2 50       12 if(!defined $dep_mtime) {
521 0         0 Carp::carp("Xslate: Failed to stat $c->[1] (ignored): $!");
522 0         0 return undef; # purge the cache
523             }
524 2 50       19 if($dep_mtime > $threshold){
525 0         0 $self->note(" _load_compiled: %s(%s) is newer than %s(%s)\n",
526             $c->[1], scalar localtime($dep_mtime),
527             $cachepath, scalar localtime($threshold) )
528             if _DUMP_LOAD;
529 0         0 return undef; # purge the cache
530             }
531             }
532             elsif($c->[0] eq 'literal') {
533             # force upgrade to avoid UTF-8 key issues
534 3 100       12 utf8::upgrade($c->[1]) if($is_utf8);
535             }
536 1255         3038 push @asm, $c;
537             }
538              
539 69         108 if(_DUMP_LOAD) {
540             $self->note(" _load_compiled: cache(mtime=%s)\n",
541             defined $fi->{cache_mtime} ? $fi->{cache_mtime} : 'undef');
542             }
543              
544 69         590 return \@asm;
545             }
546              
547             sub _save_compiled {
548 88     88   285 my($self, $out, $asm, $fullpath, $is_utf8) = @_;
549 88         831 my $mp = Data::MessagePack->new();
550 88         876 local $\;
551 88         460 print $out $self->_magic_token($fullpath);
552 88 100       627 print $out $mp->pack($is_utf8 ? 1 : 0);
553              
554 88         187 my $newest_mtime = 0;
555 88         149 foreach my $c(@{$asm}) {
  88         269  
556 1403         4748 print $out $mp->pack($c);
557              
558 1403 100       3630 if ($c->[0] eq 'depend') {
559 11         266 my $dep_mtime = (stat $c->[1])[_ST_MTIME];
560 11 50       48 if ($newest_mtime < $dep_mtime) {
561 11         29 $newest_mtime = $dep_mtime;
562             }
563             }
564             }
565 88         657 return $newest_mtime;
566             }
567              
568             sub _magic_token {
569 172     172   375 my($self, $fullpath) = @_;
570              
571             $self->{serial_opt} ||= Data::MessagePack->pack([
572             ref($self->{compiler}) || $self->{compiler},
573             $self->_filter_options_for_magic_token($self->_extract_options($self->parser_option)),
574             $self->_filter_options_for_magic_token($self->_extract_options($self->compiler_option)),
575             $self->input_layer,
576 172   66     1335 [sort keys %{ $self->{function} }],
  103   66     3011  
577             ]);
578              
579 172 100       947 if(ref $fullpath) { # ref to content string
580             $fullpath = join ':', ref($fullpath),
581 40         88 $self->_digest(${$fullpath});
  40         186  
582             }
583 172         3312 return sprintf $XSLATE_MAGIC, $fullpath, $self->{serial_opt};
584             }
585              
586             sub _digest {
587 40     40   74 my($self, $content) = @_;
588 40         290 require 'Digest/MD5.pm'; # we don't want to create its namespace
589 40         332 my $md5 = Digest::MD5->new();
590 40         143 utf8::encode($content);
591 40         179 $md5->add($content);
592 40         373 return $md5->hexdigest();
593             }
594              
595             sub _extract_options {
596 680     680   4867 my($self, $opt_ref) = @_;
597 680         4547 my @options;
598 680         4669 foreach my $name(sort keys %{$opt_ref}) {
  680         10749  
599 2726 100       14201 if(exists $self->{$name}) {
600 137         425 push @options, $name => $self->{$name};
601             }
602             }
603 680         15469 return @options;
604             }
605              
606             sub _filter_options_for_magic_token {
607 206     206   391 my($self, @options) = @_;
608 206         317 my @filterd_options;
609 206         733 while (@options) {
610 29         53 my $name = shift @options;
611 29         143 my $value = $self->replace_option_value_for_magic_token($name, shift @options);
612 29         129 push(@filterd_options, $name => $value);
613             }
614 206         755 @filterd_options;
615             }
616              
617              
618              
619             sub _compiler {
620 3442     3442   10103 my($self) = @_;
621 3442         7626 my $compiler = $self->{compiler};
622              
623 3442 100       11169 if(!ref $compiler){
624 237         104874 require Mouse;
625 237         3849564 Mouse::load_class($compiler);
626              
627 237         39615 my $input_layer = $self->input_layer;
628 237         2882 $compiler = $compiler->new(
629             engine => $self,
630             input_layer => $input_layer,
631             $self->_extract_options($self->compiler_option),
632             parser_option => {
633             input_layer => $input_layer,
634             $self->_extract_options($self->parser_option),
635             },
636             );
637              
638 237         2760 $compiler->define_function(keys %{ $self->{function} });
  237         5840  
639              
640 237         4723 $self->{compiler} = $compiler;
641             }
642              
643 3442         21614 return $compiler;
644             }
645              
646             sub compile {
647 3435     3435   63937 my $self = shift;
648             return $self->_compiler->compile(@_,
649 3435         10710 omit_augment => $self->{omit_augment});
650             }
651              
652             sub _error {
653 10     10   52 die make_error(@_);
654             }
655              
656             sub note {
657 0     0   0 my($self, @args) = @_;
658 0         0 printf STDERR @args;
659             }
660              
661             package Text::Xslate;
662             1;
663             __END__