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 183     183   3033826 use 5.008_001;
  183         459  
4 183     183   634 use strict;
  183         204  
  183         3096  
5 183     183   545 use warnings;
  183         194  
  183         6265  
6              
7             our $VERSION = '3.4.0';
8              
9 183     183   629 use Carp ();
  183         212  
  183         2266  
10 183     183   566 use File::Spec ();
  183         246  
  183         2145  
11 183     183   543 use Exporter ();
  183         206  
  183         2094  
12 183     183   75215 use Data::MessagePack ();
  183         150393  
  183         3566  
13 183     183   852 use Scalar::Util ();
  183         220  
  183         2192  
14              
15 183     183   61787 use Text::Xslate::Util ();
  183         282  
  183         8923  
16             BEGIN {
17             # all the exportable functions are defined in ::Util
18 183     183   464 our @EXPORT_OK = qw(
19             mark_raw
20             unmark_raw
21             escaped_string
22             html_escape
23             uri_escape
24             html_builder
25             );
26 183         51167 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 2768 100   2768 1 14123 sub input_layer { ref($_[0]) ? $_[0]->{input_layer} : ':utf8' }
58              
59             package Text::Xslate::Engine; # XS/PP common base class
60              
61 183         25189 use Text::Xslate::Util qw(
62             make_error
63             dump
64 183     183   2208 );
  183         834  
65              
66             # constants
67             BEGIN {
68 183     183   1402 our @ISA = qw(Exporter);
69              
70 183         329 my $dump_load = scalar($Text::Xslate::Util::DEBUG =~ /\b dump=load \b/xms);
71 183         1191 *_DUMP_LOAD = sub(){ $dump_load };
  0         0  
72              
73 183         286 my $save_src = scalar($Text::Xslate::Util::DEBUG =~ /\b save_src \b/xms);
74 183         712 *_SAVE_SRC = sub() { $save_src };
  0         0  
75              
76 183         473206 *_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 292     292   3354 sub default_functions { +{} } # overridable
125              
126             sub parser_option { # overridable
127 636     636   6613 return \%parser_option;
128             }
129              
130             sub compiler_option { # overridable
131 636     636   11291 return \%compiler_option;
132             }
133              
134             sub replace_option_value_for_magic_token { # overridable
135             #my($self, $name, $value) = @_;
136             #$value;
137 26     26   46 return $_[2];
138             }
139              
140             sub options { # overridable
141 295     295   1491 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 295         2129 %{ $self->parser_option },
160 295         2227 %{ $self->compiler_option },
  295         1941  
161             };
162             }
163              
164             sub new {
165 295     295   2023661 my $class = shift;
166 295 100       2927 my %args = (@_ == 1 ? %{$_[0]} : @_);
  12         53  
167              
168 295         2213 my $options = $class->options;
169 295         1622 my $used = 0;
170 295         1509 my $nargs = scalar keys %args;
171 295         1287 foreach my $key(keys %{$options}) {
  295         3293  
172 6199 100       11136 if(exists $args{$key}) {
    100          
173 720         5374 $used++;
174             }
175             elsif(defined($options->{$key})) {
176 1585         11361 $args{$key} = $options->{$key};
177             }
178             }
179              
180 295 100       2078 if($used != $nargs) {
181 2         7 my @unknowns = sort grep { !exists $options->{$_} } keys %args;
  17         23  
182 2         454 warnings::warnif(misc
183             => "$class: Unknown option(s): " . join ' ', @unknowns);
184             }
185              
186             $args{path} = [
187 307 100       14795 map { ref($_) ? $_ : File::Spec->rel2abs($_) }
188 250         2453 ref($args{path}) eq 'ARRAY' ? @{$args{path}} : $args{path}
189 294 100       2112 ];
190              
191 294         1442 my $arg_function= $args{function};
192              
193 294         1363 my %funcs;
194 294         1611 $args{function} = \%funcs;
195              
196 294         1465 $args{template} = {}; # template structures
197              
198 294         2392 my $self = bless \%args, $class;
199              
200             # definition of functions and methods
201              
202             # builtin functions
203 293         3534 %funcs = %builtin;
204 293         5014 $self->_register_builtin_methods(\%funcs);
205              
206             # per-class functions
207 293         2259 $self->_merge_hash(\%funcs, $class->default_functions());
208              
209             # user-defined functions
210 293 100       1983 if(defined $args{module}) {
211             $self->_merge_hash(\%funcs,
212 11         18 Text::Xslate::Util::import_from(@{$args{module}}));
  11         57  
213             }
214              
215             # user-defined html builder functions
216 291 100       1779 if(defined $args{html_builder_module}) {
217 1         1 my $raw = Text::Xslate::Util::import_from(@{$args{html_builder_module}});
  1         5  
218             my $html_builders = +{
219             map {
220 1         3 ($_ => &Text::Xslate::Util::html_builder($raw->{$_}))
  1         4  
221             } keys %$raw
222             };
223 1         3 $self->_merge_hash(\%funcs, $html_builders);
224             }
225              
226 291         1730 $self->_merge_hash(\%funcs, $arg_function);
227              
228 291         2450 $self->_resolve_function_aliases(\%funcs);
229              
230 291         3813 return $self;
231             }
232              
233             sub _merge_hash {
234 594     594   2677 my($self, $base, $add) = @_;
235 594         2490 foreach my $name(keys %{$add}) {
  594         5173  
236 98         150 $base->{$name} = $add->{$name};
237             }
238 594         4708 return;
239             }
240              
241             sub _resolve_function_aliases {
242 291     291   1396 my($self, $funcs) = @_;
243              
244 291         1327 foreach my $f(values %{$funcs}) {
  291         2957  
245 7075         27170 my %seen; # to avoid infinite loops
246 7075   100     44225 while(!( ref($f) or Scalar::Util::looks_like_number($f) )) {
247 872 50       4620 my $v = $funcs->{$f} or $self->_error(
248             "Cannot resolve a function alias '$f',"
249             . " which refers nothing",
250             );
251              
252 872 50 33     4993 if( ref($v) or Scalar::Util::looks_like_number($v) ) {
253 872         3691 $f = $v;
254 872         6611 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 291         2337 return;
266             }
267              
268             sub load_string { # called in render_string()
269 1371     1371   192254 my($self, $string) = @_;
270 1371 100       2853 if(not defined $string) {
271 1         6 $self->_error("LoadError: Template string is not given");
272             }
273 1370         1047 $self->note(' _load_string: %s', join '\n', split /\n/, $string)
274             if _DUMP_LOAD;
275 1370         992 $self->{source}{''} = $string if _SAVE_SRC;
276 1370         2130 $self->{string_buffer} = $string;
277 1370         2673 my $asm = $self->compile($string);
278 1306         26880 $self->_assemble($asm, '', \$string, undef, undef);
279 1306         1026077 return $asm;
280             }
281              
282             my $updir = File::Spec->updir;
283             sub find_file {
284 2218     2218   4803 my($self, $file) = @_;
285              
286 2218 100       7065 if($file =~ /\Q$updir\E/xmso) {
287 4         17 $self->_error("LoadError: Forbidden component (updir: '$updir') found in file name '$file'");
288             }
289              
290 2214         2779 my $fullpath;
291             my $cachepath;
292 0         0 my $orig_mtime;
293 0         0 my $cache_mtime;
294 2214         2762 foreach my $p(@{$self->{path}}) {
  2214         6635  
295 2229         2455 $self->note(" find_file: %s in %s ...\n", $file, $p) if _DUMP_LOAD;
296              
297 2229         2747 my $cache_prefix;
298 2229 100       4237 if(ref $p eq 'HASH') { # virtual path
299 100 100       293 defined(my $content = $p->{$file}) or next;
300 95         122 $fullpath = \$content;
301              
302             # NOTE:
303             # Because contents of virtual paths include their digest,
304             # time-dependent cache verifier makes no sense.
305 95         106 $orig_mtime = 0;
306 95         87 $cache_mtime = 0;
307 95         122 $cache_prefix = 'HASH';
308             }
309             else {
310 2129         22582 $fullpath = File::Spec->catfile($p, $file);
311 2129 100       33159 defined($orig_mtime = (stat($fullpath))[_ST_MTIME])
312             or next;
313 2114         12752 $cache_prefix = Text::Xslate::uri_escape($p);
314 2114 50       5596 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 2209         18042 $cache_prefix,
324             $file . 'c',
325             );
326             # stat() will be failed if the cache doesn't exist
327 2209         18111 $cache_mtime = (stat($cachepath))[_ST_MTIME];
328 2209         4846 last;
329             }
330              
331 2214 100       4763 if(not defined $orig_mtime) {
332 5         14 $self->_error("LoadError: Cannot find '$file' (path: @{$self->{path}})");
  5         43  
333             }
334              
335 2209         2822 $self->note(" find_file: %s (mtime=%d)\n",
336             $fullpath, $cache_mtime || 0) if _DUMP_LOAD;
337              
338             return {
339 2209 100       11781 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 2101     2101   3163586 my($self, $file, $mtime, $omit_augment) = @_;
351              
352 2101         5195 local $self->{omit_augment} = $omit_augment;
353              
354 2101         2384 $self->note("%s->load_file(%s)\n", $self, $file) if _DUMP_LOAD;
355              
356 2101 100       5147 if($file eq '') { # simply reload it
357 1         6 return $self->load_string($self->{string_buffer});
358             }
359              
360 2100         4705 my $fi = $self->find_file($file);
361              
362 2094   100     5164 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 2089         2613 my $cache_mtime;
368 2089 100       4215 if($self->{cache} < 2) {
369 2082   100     6948 $cache_mtime = $fi->{cache_mtime} || 0;
370             }
371              
372 2089         33482 $self->_assemble($asm, $file, $fi->{fullpath}, $fi->{cachepath}, $cache_mtime);
373 2089         46389 return $asm;
374             }
375              
376             sub slurp_template {
377 2048     2048   3169 my($self, $input_layer, $fullpath) = @_;
378              
379 2048 100       3763 if (ref $fullpath eq 'SCALAR') {
380 72         193 return $$fullpath;
381             } else {
382 1976 50   2   59030 open my($source), '<' . $input_layer, $fullpath
  2         10  
  2         2  
  2         10  
383             or $self->_error("LoadError: Cannot open $fullpath for reading: $!");
384 1976         22232 local $/;
385 1976         45273 return scalar <$source>;
386             }
387             }
388              
389             sub _load_source {
390 2022     2022   3067 my($self, $fi) = @_;
391 2022         2779 my $fullpath = $fi->{fullpath};
392 2022         2782 my $cachepath = $fi->{cachepath};
393              
394 2022         2167 $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 2022 100       13655 if(-e $cachepath) {
399 25 50       11209 unlink $cachepath
400             or Carp::carp("Xslate: cannot unlink $cachepath (ignored): $!");
401             }
402              
403 2022         4493 my $source = $self->slurp_template($self->input_layer, $fullpath);
404 2022 100       5805 $source = $self->{pre_process_handler}->($source) if $self->{pre_process_handler};
405 2022         3374 $self->{source}{$fi->{name}} = $source if _SAVE_SRC;
406              
407             my $asm = $self->compile($source,
408             file => $fullpath,
409             name => $fi->{name},
410 2022         5155 );
411              
412 2017 100       5188 if($self->{cache} >= 1) {
413 86         1406 my($volume, $dir) = File::Spec->splitpath($fi->{cachepath});
414 86         654 my $cachedir = File::Spec->catpath($volume, $dir, '');
415 86 100       1458 if(not -e $cachedir) {
416 34         223 require File::Path;
417 34         8990 File::Path::mkpath($cachedir);
418 34 50       201475 if (! -e $cachedir) {
419 0         0 Carp::croak("Xslate: Cannot prepare cache directory $cachepath (ignored): $@");
420             }
421             }
422              
423 86         755 my $tmpfile = sprintf('%s.%d.%d', $cachepath, $$, Scalar::Util::refaddr($self));
424              
425 86 50       6299 if (open my($out), ">:raw", $tmpfile) {
426 86         693 my $mtime = $self->_save_compiled($out, $asm, $fullpath, utf8::is_utf8($source));
427              
428 86 50       7419 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 86 100       224 if (not ref $fullpath) {
435 58         885 my $main_mtime = (stat $fullpath)[_ST_MTIME];
436 58 100 66     348 if (defined($main_mtime) && $main_mtime > $mtime) {
437 48         78 $mtime = $main_mtime;
438             }
439 58         949 utime $mtime, $mtime, $cachepath;
440 58         277 $fi->{cache_mtime} = $mtime;
441             }
442             else {
443 28         365 $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 2017         2350 if(_DUMP_LOAD) {
456             $self->note(" _load_source: cache(mtime=%s)\n",
457             defined $fi->{cache_mtime} ? $fi->{cache_mtime} : 'undef');
458             }
459              
460 2017         7441 return $asm;
461             }
462              
463             # load compiled templates if they are fresh enough
464             sub _load_compiled {
465 2094     2094   3324 my($self, $fi, $threshold) = @_;
466              
467 2094 100       4233 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         10 $threshold = 9**9**9; # force to purge the cache
471             }
472             else {
473 2087   100     9062 $threshold ||= $fi->{cache_mtime};
474             }
475             # see also tx_load_template() in xs/Text-Xslate.xs
476 2094 100 66     5436 if(!( defined($fi->{cache_mtime}) and $self->{cache} >= 1
      100        
477             and $threshold >= $fi->{orig_mtime} )) {
478 2006         2107 $self->note( " _load_compiled: no fresh cache: %s, %s",
479             $threshold || 0, Text::Xslate::Util::p($fi) ) if _DUMP_LOAD;
480 2006         2863 $fi->{cache_mtime} = undef;
481 2006         7783 return undef;
482             }
483              
484 88         128 my $cachepath = $fi->{cachepath};
485 88 50       2609 open my($in), '<:raw', $cachepath
486             or $self->_error("LoadError: Cannot open $cachepath for reading: $!");
487              
488 88         287 my $magic = $self->_magic_token($fi->{fullpath});
489 88         121 my $data;
490 88         1192 read $in, $data, length($magic);
491 88 100       223 if($data ne $magic) {
492 16         257 return undef;
493             }
494             else {
495 72         286 local $/;
496 72         607 $data = <$in>;
497 72         475 close $in;
498             }
499 72         725 my $unpacker = Data::MessagePack::Unpacker->new();
500 72         237 my $offset = $unpacker->execute($data);
501 72         145 my $is_utf8 = $unpacker->data();
502 72         138 $unpacker->reset();
503              
504 72         142 $unpacker->utf8($is_utf8);
505              
506 72         59 my @asm;
507 72 100       276 if($is_utf8) { # TODO: move to XS?
508 61         82 my $seed = "";
509 61         111 utf8::upgrade($seed);
510 61         163 push @asm, ['print_raw_s', $seed, __LINE__, __FILE__];
511             }
512 72         186 while($offset < length($data)) {
513 1273         2568 $offset = $unpacker->execute($data, $offset);
514 1273         1187 my $c = $unpacker->data();
515 1273         1139 $unpacker->reset();
516              
517             # my($name, $arg, $line, $file, $symbol) = @{$c};
518 1273 100       2072 if($c->[0] eq 'depend') {
    100          
519 2         49 my $dep_mtime = (stat $c->[1])[_ST_MTIME];
520 2 50       6 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       4 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       8 utf8::upgrade($c->[1]) if($is_utf8);
535             }
536 1273         1742 push @asm, $c;
537             }
538              
539 72         69 if(_DUMP_LOAD) {
540             $self->note(" _load_compiled: cache(mtime=%s)\n",
541             defined $fi->{cache_mtime} ? $fi->{cache_mtime} : 'undef');
542             }
543              
544 72         472 return \@asm;
545             }
546              
547             sub _save_compiled {
548 86     86   190 my($self, $out, $asm, $fullpath, $is_utf8) = @_;
549 86         581 my $mp = Data::MessagePack->new();
550 86         903 local $\;
551 86         1322 print $out $self->_magic_token($fullpath);
552 86 100       429 print $out $mp->pack($is_utf8 ? 1 : 0);
553              
554 86         127 my $newest_mtime = 0;
555 86         95 foreach my $c(@{$asm}) {
  86         247  
556 1417         2498 print $out $mp->pack($c);
557              
558 1417 100       1985 if ($c->[0] eq 'depend') {
559 11         166 my $dep_mtime = (stat $c->[1])[_ST_MTIME];
560 11 50       34 if ($newest_mtime < $dep_mtime) {
561 11         23 $newest_mtime = $dep_mtime;
562             }
563             }
564             }
565 86         469 return $newest_mtime;
566             }
567              
568             sub _magic_token {
569 174     174   243 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 174   66     901 [sort keys %{ $self->{function} }],
  104   66     2246  
577             ]);
578              
579 174 100       566 if(ref $fullpath) { # ref to content string
580             $fullpath = join ':', ref($fullpath),
581 42         60 $self->_digest(${$fullpath});
  42         126  
582             }
583 174         1519 return sprintf $XSLATE_MAGIC, $fullpath, $self->{serial_opt};
584             }
585              
586             sub _digest {
587 42     42   54 my($self, $content) = @_;
588 42         209 require 'Digest/MD5.pm'; # we don't want to create its namespace
589 42         263 my $md5 = Digest::MD5->new();
590 42         82 utf8::encode($content);
591 42         119 $md5->add($content);
592 42         280 return $md5->hexdigest();
593             }
594              
595             sub _extract_options {
596 682     682   2616 my($self, $opt_ref) = @_;
597 682         2528 my @options;
598 682         2469 foreach my $name(sort keys %{$opt_ref}) {
  682         6676  
599 2734 100       8005 if(exists $self->{$name}) {
600 137         288 push @options, $name => $self->{$name};
601             }
602             }
603 682         9787 return @options;
604             }
605              
606             sub _filter_options_for_magic_token {
607 208     208   240 my($self, @options) = @_;
608 208         165 my @filterd_options;
609 208         421 while (@options) {
610 29         40 my $name = shift @options;
611 29         93 my $value = $self->replace_option_value_for_magic_token($name, shift @options);
612 29         71 push(@filterd_options, $name => $value);
613             }
614 208         540 @filterd_options;
615             }
616              
617              
618              
619             sub _compiler {
620 3462     3462   6203 my($self) = @_;
621 3462         4401 my $compiler = $self->{compiler};
622              
623 3462 100       7421 if(!ref $compiler){
624 237         60236 require Mouse;
625 237         2408104 Mouse::load_class($compiler);
626              
627 237         24448 my $input_layer = $self->input_layer;
628 237         1975 $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         1576 $compiler->define_function(keys %{ $self->{function} });
  237         3890  
639              
640 237         2744 $self->{compiler} = $compiler;
641             }
642              
643 3462         14986 return $compiler;
644             }
645              
646             sub compile {
647 3455     3455   37550 my $self = shift;
648             return $self->_compiler->compile(@_,
649 3455         6486 omit_augment => $self->{omit_augment});
650             }
651              
652             sub _error {
653 10     10   34 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__