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   4714951 use 5.008_001;
  180         691  
4 180     180   1052 use strict;
  180         396  
  180         4491  
5 180     180   892 use warnings;
  180         355  
  180         7892  
6              
7             our $VERSION = '3.3.9';
8              
9 180     180   998 use Carp ();
  180         337  
  180         3197  
10 180     180   910 use File::Spec ();
  180         341  
  180         3074  
11 180     180   864 use Exporter ();
  180         336  
  180         3035  
12 180     180   138080 use Data::MessagePack ();
  180         207743  
  180         4394  
13 180     180   1115 use Scalar::Util ();
  180         336  
  180         3156  
14              
15 180     180   99860 use Text::Xslate::Util ();
  180         443  
  180         9986  
16             BEGIN {
17             # all the exportable functions are defined in ::Util
18 180     180   611 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         68898 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 2765 100   2765 1 22165 sub input_layer { ref($_[0]) ? $_[0]->{input_layer} : ':utf8' }
58              
59             package Text::Xslate::Engine; # XS/PP common base class
60              
61 180         37822 use Text::Xslate::Util qw(
62             make_error
63             dump
64 180     180   1058 );
  180         329  
65              
66             # constants
67             BEGIN {
68 180     180   1739 our @ISA = qw(Exporter);
69              
70 180         2762 my $dump_load = scalar($Text::Xslate::Util::DEBUG =~ /\b dump=load \b/xms);
71 180         2685 *_DUMP_LOAD = sub(){ $dump_load };
  0         0  
72              
73 180         2774 my $save_src = scalar($Text::Xslate::Util::DEBUG =~ /\b save_src \b/xms);
74 180         1051 *_SAVE_SRC = sub() { $save_src };
  0         0  
75              
76 180         695210 *_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   4831 sub default_functions { +{} } # overridable
125              
126             sub parser_option { # overridable
127 632     632   10390 return \%parser_option;
128             }
129              
130             sub compiler_option { # overridable
131 632     632   16973 return \%compiler_option;
132             }
133              
134             sub replace_option_value_for_magic_token { # overridable
135             #my($self, $name, $value) = @_;
136             #$value;
137 26     26   53 return $_[2];
138             }
139              
140             sub options { # overridable
141 292     292   2276 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         3253 %{ $self->parser_option },
160 292         3293 %{ $self->compiler_option },
  292         3157  
161             };
162             }
163              
164             sub new {
165 292     292   3501742 my $class = shift;
166 292 100       3863 my %args = (@_ == 1 ? %{$_[0]} : @_);
  12         69  
167              
168 292         3356 my $options = $class->options;
169 292         2471 my $used = 0;
170 292         2325 my $nargs = scalar keys %args;
171 292         2129 foreach my $key(keys %{$options}) {
  292         4878  
172 6136 100       18917 if(exists $args{$key}) {
    100          
173 718         7353 $used++;
174             }
175             elsif(defined($options->{$key})) {
176 1565         20395 $args{$key} = $options->{$key};
177             }
178             }
179              
180 292 100       3148 if($used != $nargs) {
181 2         7 my @unknowns = sort grep { !exists $options->{$_} } keys %args;
  17         41  
182 2         548 warnings::warnif(misc
183             => "$class: Unknown option(s): " . join ' ', @unknowns);
184             }
185              
186             $args{path} = [
187 304 100       21832 map { ref($_) ? $_ : File::Spec->rel2abs($_) }
188 248         3875 ref($args{path}) eq 'ARRAY' ? @{$args{path}} : $args{path}
189 291 100       3057 ];
190              
191 291         2360 my $arg_function= $args{function};
192              
193 291         2081 my %funcs;
194 291         2504 $args{function} = \%funcs;
195              
196 291         2386 $args{template} = {}; # template structures
197              
198 291         3275 my $self = bless \%args, $class;
199              
200             # definition of functions and methods
201              
202             # builtin functions
203 290         4869 %funcs = %builtin;
204 290         7901 $self->_register_builtin_methods(\%funcs);
205              
206             # per-class functions
207 290         3331 $self->_merge_hash(\%funcs, $class->default_functions());
208              
209             # user-defined functions
210 290 100       2913 if(defined $args{module}) {
211             $self->_merge_hash(\%funcs,
212 11         25 Text::Xslate::Util::import_from(@{$args{module}}));
  11         72  
213             }
214              
215             # user-defined html builder functions
216 288 100       2820 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         6  
221             } keys %$raw
222             };
223 1         4 $self->_merge_hash(\%funcs, $html_builders);
224             }
225              
226 288         2607 $self->_merge_hash(\%funcs, $arg_function);
227              
228 288         3234 $self->_resolve_function_aliases(\%funcs);
229              
230 288         5722 return $self;
231             }
232              
233             sub _merge_hash {
234 588     588   4283 my($self, $base, $add) = @_;
235 588         3998 foreach my $name(keys %{$add}) {
  588         7905  
236 98         250 $base->{$name} = $add->{$name};
237             }
238 588         7478 return;
239             }
240              
241             sub _resolve_function_aliases {
242 288     288   2176 my($self, $funcs) = @_;
243              
244 288         2087 foreach my $f(values %{$funcs}) {
  288         4364  
245 7003         45173 my %seen; # to avoid infinite loops
246 7003   100     71606 while(!( ref($f) or Scalar::Util::looks_like_number($f) )) {
247 863 50       7364 my $v = $funcs->{$f} or $self->_error(
248             "Cannot resolve a function alias '$f',"
249             . " which refers nothing",
250             );
251              
252 863 50 33     7752 if( ref($v) or Scalar::Util::looks_like_number($v) ) {
253 863         5890 $f = $v;
254 863         11082 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         3813 return;
266             }
267              
268             sub load_string { # called in render_string()
269 1349     1349   241312 my($self, $string) = @_;
270 1349 100       3738 if(not defined $string) {
271 1         8 $self->_error("LoadError: Template string is not given");
272             }
273 1348         1654 $self->note(' _load_string: %s', join '\n', split /\n/, $string)
274             if _DUMP_LOAD;
275 1348         1583 $self->{source}{''} = $string if _SAVE_SRC;
276 1348         3250 $self->{string_buffer} = $string;
277 1348         3988 my $asm = $self->compile($string);
278 1284         35946 $self->_assemble($asm, '', \$string, undef, undef);
279 1284         1037951 return $asm;
280             }
281              
282             my $updir = File::Spec->updir;
283             sub find_file {
284 2215     2215   7809 my($self, $file) = @_;
285              
286 2215 100       9193 if($file =~ /\Q$updir\E/xmso) {
287 4         24 $self->_error("LoadError: Forbidden component (updir: '$updir') found in file name '$file'");
288             }
289              
290 2211         4583 my $fullpath;
291             my $cachepath;
292 0         0 my $orig_mtime;
293 0         0 my $cache_mtime;
294 2211         5082 foreach my $p(@{$self->{path}}) {
  2211         9290  
295 2226         3918 $self->note(" find_file: %s in %s ...\n", $file, $p) if _DUMP_LOAD;
296              
297 2226         4689 my $cache_prefix;
298 2226 100       6224 if(ref $p eq 'HASH') { # virtual path
299 97 100       382 defined(my $content = $p->{$file}) or next;
300 92         162 $fullpath = \$content;
301              
302             # NOTE:
303             # Because contents of virtual paths include their digest,
304             # time-dependent cache verifier makes no sense.
305 92         159 $orig_mtime = 0;
306 92         131 $cache_mtime = 0;
307 92         170 $cache_prefix = 'HASH';
308             }
309             else {
310 2129         32081 $fullpath = File::Spec->catfile($p, $file);
311 2129 100       53678 defined($orig_mtime = (stat($fullpath))[_ST_MTIME])
312             or next;
313 2114         17689 $cache_prefix = Text::Xslate::uri_escape($p);
314 2114 50       8675 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 2206         27499 $cache_prefix,
324             $file . 'c',
325             );
326             # stat() will be failed if the cache doesn't exist
327 2206         32308 $cache_mtime = (stat($cachepath))[_ST_MTIME];
328 2206         7471 last;
329             }
330              
331 2211 100       7273 if(not defined $orig_mtime) {
332 5         27 $self->_error("LoadError: Cannot find '$file' (path: @{$self->{path}})");
  5         56  
333             }
334              
335 2206         4424 $self->note(" find_file: %s (mtime=%d)\n",
336             $fullpath, $cache_mtime || 0) if _DUMP_LOAD;
337              
338             return {
339 2206 100       16919 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 2099     2099   3638033 my($self, $file, $mtime, $omit_augment) = @_;
351              
352 2099         7682 local $self->{omit_augment} = $omit_augment;
353              
354 2099         4152 $self->note("%s->load_file(%s)\n", $self, $file) if _DUMP_LOAD;
355              
356 2099 100       7274 if($file eq '') { # simply reload it
357 1         9 return $self->load_string($self->{string_buffer});
358             }
359              
360 2098         6769 my $fi = $self->find_file($file);
361              
362 2092   100     7675 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 2087         4638 my $cache_mtime;
368 2087 100       6941 if($self->{cache} < 2) {
369 2080   100     11462 $cache_mtime = $fi->{cache_mtime} || 0;
370             }
371              
372 2087         42478 $self->_assemble($asm, $file, $fi->{fullpath}, $fi->{cachepath}, $cache_mtime);
373 2087         67455 return $asm;
374             }
375              
376             sub slurp_template {
377 2049     2049   5496 my($self, $input_layer, $fullpath) = @_;
378              
379 2049 100       6091 if (ref $fullpath eq 'SCALAR') {
380 70         257 return $$fullpath;
381             } else {
382 1979 50   2   86262 open my($source), '<' . $input_layer, $fullpath
  2         16  
  2         3  
  2         29  
383             or $self->_error("LoadError: Cannot open $fullpath for reading: $!");
384 1979         616471 local $/;
385 1979         66617 return scalar <$source>;
386             }
387             }
388              
389             sub _load_source {
390 2023     2023   4733 my($self, $fi) = @_;
391 2023         5131 my $fullpath = $fi->{fullpath};
392 2023         4588 my $cachepath = $fi->{cachepath};
393              
394 2023         3820 $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 2023 100       26173 if(-e $cachepath) {
399 28 50       3031 unlink $cachepath
400             or Carp::carp("Xslate: cannot unlink $cachepath (ignored): $!");
401             }
402              
403 2023         6624 my $source = $self->slurp_template($self->input_layer, $fullpath);
404 2023 100       8408 $source = $self->{pre_process_handler}->($source) if $self->{pre_process_handler};
405 2023         4260 $self->{source}{$fi->{name}} = $source if _SAVE_SRC;
406              
407             my $asm = $self->compile($source,
408             file => $fullpath,
409             name => $fi->{name},
410 2023         8306 );
411              
412 2018 100       8050 if($self->{cache} >= 1) {
413 87         1696 my($volume, $dir) = File::Spec->splitpath($fi->{cachepath});
414 87         843 my $cachedir = File::Spec->catpath($volume, $dir, '');
415 87 100       1964 if(not -e $cachedir) {
416 34         280 require File::Path;
417 34         11667 File::Path::mkpath($cachedir);
418 34 50       201902 if (! -e $cachedir) {
419 0         0 Carp::croak("Xslate: Cannot prepare cache directory $cachepath (ignored): $@");
420             }
421             }
422              
423 87         872 my $tmpfile = sprintf('%s.%d.%d', $cachepath, $$, Scalar::Util::refaddr($self));
424              
425 87 50       8328 if (open my($out), ">:raw", $tmpfile) {
426 87         756 my $mtime = $self->_save_compiled($out, $asm, $fullpath, utf8::is_utf8($source));
427              
428 87 50       11546 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 87 100       273 if (not ref $fullpath) {
435 61         1678 my $main_mtime = (stat $fullpath)[_ST_MTIME];
436 61 100 66     461 if (defined($main_mtime) && $main_mtime > $mtime) {
437 50         92 $mtime = $main_mtime;
438             }
439 61         1583 utime $mtime, $mtime, $cachepath;
440 61         384 $fi->{cache_mtime} = $mtime;
441             }
442             else {
443 26         501 $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 2018         4091 if(_DUMP_LOAD) {
456             $self->note(" _load_source: cache(mtime=%s)\n",
457             defined $fi->{cache_mtime} ? $fi->{cache_mtime} : 'undef');
458             }
459              
460 2018         10931 return $asm;
461             }
462              
463             # load compiled templates if they are fresh enough
464             sub _load_compiled {
465 2092     2092   5155 my($self, $fi, $threshold) = @_;
466              
467 2092 100       7287 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         13 $threshold = 9**9**9; # force to purge the cache
471             }
472             else {
473 2085   100     12383 $threshold ||= $fi->{cache_mtime};
474             }
475             # see also tx_load_template() in xs/Text-Xslate.xs
476 2092 100 66     8658 if(!( defined($fi->{cache_mtime}) and $self->{cache} >= 1
      100        
477             and $threshold >= $fi->{orig_mtime} )) {
478 2008         3681 $self->note( " _load_compiled: no fresh cache: %s, %s",
479             $threshold || 0, Text::Xslate::Util::p($fi) ) if _DUMP_LOAD;
480 2008         4784 $fi->{cache_mtime} = undef;
481 2008         11990 return undef;
482             }
483              
484 84         177 my $cachepath = $fi->{cachepath};
485 84 50       3462 open my($in), '<:raw', $cachepath
486             or $self->_error("LoadError: Cannot open $cachepath for reading: $!");
487              
488 84         373 my $magic = $self->_magic_token($fi->{fullpath});
489 84         151 my $data;
490 84         1364 read $in, $data, length($magic);
491 84 100       280 if($data ne $magic) {
492 15         311 return undef;
493             }
494             else {
495 69         273 local $/;
496 69         947 $data = <$in>;
497 69         664 close $in;
498             }
499 69         789 my $unpacker = Data::MessagePack::Unpacker->new();
500 69         293 my $offset = $unpacker->execute($data);
501 69         207 my $is_utf8 = $unpacker->data();
502 69         197 $unpacker->reset();
503              
504 69         195 $unpacker->utf8($is_utf8);
505              
506 69         93 my @asm;
507 69 100       358 if($is_utf8) { # TODO: move to XS?
508 59         102 my $seed = "";
509 59         172 utf8::upgrade($seed);
510 59         218 push @asm, ['print_raw_s', $seed, __LINE__, __FILE__];
511             }
512 69         228 while($offset < length($data)) {
513 1255         4551 $offset = $unpacker->execute($data, $offset);
514 1255         2392 my $c = $unpacker->data();
515 1255         2353 $unpacker->reset();
516              
517             # my($name, $arg, $line, $file, $symbol) = @{$c};
518 1255 100       3379 if($c->[0] eq 'depend') {
    100          
519 2         62 my $dep_mtime = (stat $c->[1])[_ST_MTIME];
520 2 50       9 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       20 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       10 utf8::upgrade($c->[1]) if($is_utf8);
535             }
536 1255         3129 push @asm, $c;
537             }
538              
539 69         93 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         560 return \@asm;
545             }
546              
547             sub _save_compiled {
548 87     87   255 my($self, $out, $asm, $fullpath, $is_utf8) = @_;
549 87         757 my $mp = Data::MessagePack->new();
550 87         804 local $\;
551 87         411 print $out $self->_magic_token($fullpath);
552 87 100       567 print $out $mp->pack($is_utf8 ? 1 : 0);
553              
554 87         182 my $newest_mtime = 0;
555 87         140 foreach my $c(@{$asm}) {
  87         254  
556 1397         4734 print $out $mp->pack($c);
557              
558 1397 100       3563 if ($c->[0] eq 'depend') {
559 11         270 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 87         680 return $newest_mtime;
566             }
567              
568             sub _magic_token {
569 171     171   345 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 171   66     1179 [sort keys %{ $self->{function} }],
  103   66     2953  
577             ]);
578              
579 171 100       840 if(ref $fullpath) { # ref to content string
580             $fullpath = join ':', ref($fullpath),
581 40         84 $self->_digest(${$fullpath});
  40         166  
582             }
583 171         3079 return sprintf $XSLATE_MAGIC, $fullpath, $self->{serial_opt};
584             }
585              
586             sub _digest {
587 40     40   101 my($self, $content) = @_;
588 40         251 require 'Digest/MD5.pm'; # we don't want to create its namespace
589 40         331 my $md5 = Digest::MD5->new();
590 40         146 utf8::encode($content);
591 40         161 $md5->add($content);
592 40         336 return $md5->hexdigest();
593             }
594              
595             sub _extract_options {
596 680     680   4390 my($self, $opt_ref) = @_;
597 680         4141 my @options;
598 680         4242 foreach my $name(sort keys %{$opt_ref}) {
  680         10120  
599 2726 100       13196 if(exists $self->{$name}) {
600 137         410 push @options, $name => $self->{$name};
601             }
602             }
603 680         14433 return @options;
604             }
605              
606             sub _filter_options_for_magic_token {
607 206     206   368 my($self, @options) = @_;
608 206         253 my @filterd_options;
609 206         645 while (@options) {
610 29         68 my $name = shift @options;
611 29         117 my $value = $self->replace_option_value_for_magic_token($name, shift @options);
612 29         113 push(@filterd_options, $name => $value);
613             }
614 206         695 @filterd_options;
615             }
616              
617              
618              
619             sub _compiler {
620 3441     3441   10371 my($self) = @_;
621 3441         7395 my $compiler = $self->{compiler};
622              
623 3441 100       10633 if(!ref $compiler){
624 237         102344 require Mouse;
625 237         3797881 Mouse::load_class($compiler);
626              
627 237         37309 my $input_layer = $self->input_layer;
628 237         2874 $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         2478 $compiler->define_function(keys %{ $self->{function} });
  237         5552  
639              
640 237         4302 $self->{compiler} = $compiler;
641             }
642              
643 3441         20898 return $compiler;
644             }
645              
646             sub compile {
647 3434     3434   62334 my $self = shift;
648             return $self->_compiler->compile(@_,
649 3434         10515 omit_augment => $self->{omit_augment});
650             }
651              
652             sub _error {
653 10     10   46 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__