File Coverage

blib/lib/YATT/Lite/Core.pm
Criterion Covered Total %
statement 206 268 76.8
branch 55 110 50.0
condition 37 73 50.6
subroutine 45 55 81.8
pod 0 38 0.0
total 343 544 63.0


line stmt bran cond sub pod time code
1             package YATT::Lite::Core; sub MY () {__PACKAGE__}
2 17     17   112 use strict;
  17         39  
  17         536  
3 17     17   88 use warnings qw(FATAL all NONFATAL misc);
  17         91  
  17         605  
4 17     17   87 use Carp;
  17         37  
  17         1108  
5              
6 17     17   112 use constant DEBUG_REBUILD => $ENV{DEBUG_YATT_REBUILD};
  17         150  
  17         1295  
7              
8 17     17   112 use parent qw(YATT::Lite::VFS);
  17         42  
  17         177  
9 17         132 use YATT::Lite::MFields qw/cf_namespace cf_debug_cgen cf_no_lineinfo cf_check_lineno
10             cf_index_name
11             cf_tmpl_encoding
12             cf_debug_parser
13             cf_parse_while_loading cf_only_parse
14             cf_die_in_error cf_error_handler
15             cf_special_entities
16             cf_lcmsg_sink
17             cf_match_argsroute_first
18              
19             n_compiles
20 17     17   1199 /;
  17         40  
21 17     17   154 use YATT::Lite::Util;
  17         45  
  17         1742  
22 17     17   8432 use YATT::Lite::Constants;
  17         53  
  17         2363  
23 17     17   4611 use YATT::Lite::Entities;
  17         44  
  17         171  
24              
25             # XXX: YATT::Lite に?
26 17     17   105 use YATT::Lite::Breakpoint ();
  17         44  
  17         397  
27              
28             #========================================
29             # 以下、 package YATT::Lite のための、内部クラス
30             #========================================
31             {
32 17     17   85 use YATT::Lite::VFS qw(Folder Item);
  17         33  
  17         2467  
33             use YATT::Lite::Types
34 17         542 ([Part => -base => MY->Item
35             , -fields => [qw(toks arg_dict arg_order
36             cf_namespace cf_kind cf_folder cf_data
37             cf_implicit cf_suppressed
38             cf_startln cf_bodyln cf_endln
39             cf_startpos cf_bodypos cf_bodylen
40             cf_subpattern
41             )]
42             , -constants => [[public => 0]]
43             , [Widget => -fields => [qw(tree var_dict has_required_arg)]
44             , [Page => (), -constants => [[public => 1]]]]
45             , [Action => (), -constants => [[public => 1]]]
46             , [Data => ()]]
47              
48             , [Template => -base => MY->File
49             , -alias => 'vfs_file'
50             , -constants => [[can_generate_code => 1]]
51             , -fields => [qw(product parse_ok cf_mtime cf_utf8 cf_age
52             cf_usage cf_constants
53             cf_ignore_trailing_newlines
54             cf_subroutes
55             )]]
56              
57             , [ParsingState => -fields => [qw(startln endln
58             startpos curpos
59             cf_path
60             )]]
61 17     17   115 );
  17         32  
62              
63             sub YATT::Lite::Core::Part::public_name {
64 0     0 0 0 (my Part $part) = @_;
65 0         0 $part->{cf_name};
66             }
67             sub YATT::Lite::Core::Action::public_name {
68 0     0 0 0 (my Action $action) = @_;
69 0         0 substr($action->{cf_name}, 3);
70             }
71 0     0 0 0 sub YATT::Lite::Core::Part::method_name {...}
72             sub YATT::Lite::Core::Widget::method_name {
73 73     73 0 161 (my Widget $widget) = @_;
74 73         1011 "render_$widget->{cf_name}";
75             }
76             sub YATT::Lite::Core::Action::method_name {
77 1     1 0 4 (my Action $action) = @_;
78 1         11 $action->{cf_name};
79             }
80              
81             sub YATT::Lite::Core::Part::configure_folder {
82 395     395 0 927 (my Part $part, my Folder $folder) = @_;
83 395         2234 Scalar::Util::weaken($part->{cf_folder} = $folder);
84             # die "Can't weaken!" unless Scalar::Util::isweak($part->{cf_folder});
85             }
86              
87             # sub YATT::Lite::Core::Part::source {
88             # (my Part $part) = @_;
89             # join "", map {ref $_ ? "\n" x $$_[0] : $_} @{$part->{source}};
90             # }
91             sub YATT::Lite::Core::Template::source_length {
92 0     0 0 0 (my Template $self) = @_;
93 0         0 length $self->{cf_string};
94             }
95             sub YATT::Lite::Core::Template::list_parts {
96 234     234 0 551 (my Template $self, my $type) = @_;
97 234 50       659 return @{$self->{partlist}} unless defined $type;
  0         0  
98 234         397 grep { UNIVERSAL::isa($_, $type) } @{$self->{partlist}}
  385         2204  
  234         614  
99             }
100             sub YATT::Lite::Core::Template::node_source {
101 9     9 0 2145 (my Template $tmpl, my $node) = @_;
102 9 50       33 unless (ref $node eq 'ARRAY') {
103 0         0 confess "Node is not an ARRAY";
104             }
105 9         25 $tmpl->source_region($node->[NODE_BEGIN], $node->[NODE_END]);
106             }
107             sub YATT::Lite::Core::Template::node_body_source {
108 71     71 0 176 (my Template $tmpl, my $node) = @_;
109 71 50       227 unless (ref $node eq 'ARRAY') {
110 0         0 confess "Node is not an ARRAY";
111             }
112 71         215 $tmpl->source_region($node->[NODE_BODY_BEGIN], $node->[NODE_BODY_END]);
113             }
114             sub YATT::Lite::Core::Template::source_region {
115 84     84 0 10240 (my Template $tmpl, my ($begin, $end)) = @_;
116 84         390 $tmpl->source_substr($begin, $end - $begin);
117             }
118             sub YATT::Lite::Core::Template::source_substr {
119 2124     2124 0 3789 (my Template $tmpl, my ($offset, $len)) = @_;
120 2124 50       3867 unless (defined $len) {
121 0         0 substr $tmpl->{cf_string}, $offset;
122             } else {
123 2124 50       4377 return undef if $len < 0;
124 2124         6774 substr $tmpl->{cf_string}, $offset, $len;
125             }
126             }
127              
128             sub YATT::Lite::Core::Part::reorder_hash_params {
129 0     0 0 0 (my Widget $widget, my ($orig_params)) = @_;
130 0         0 my $params = +{%$orig_params};
131 0         0 my @params;
132 0 0       0 foreach my $name (map($_ ? @$_ : (), $widget->{arg_order})) {
133 0         0 push @params, delete $params->{$name};
134             }
135 0 0       0 if (keys %$params) {
136 0         0 die "Unknown args for $widget->{cf_name}: " . join(", ", keys %$params)
137             . "\n";
138             }
139 0 0       0 wantarray ? @params : \@params;
140             }
141              
142             sub YATT::Lite::Core::Part::reorder_cgi_params {
143 139     139 0 397 (my Widget $widget, my ($cgi, $list)) = @_;
144 139   100     548 $list ||= [];
145 139         646 foreach my $name ($cgi->param) {
146 2 100       29 next unless $name =~ /^[a-z]\w*$/i;
147 1 50       12 my $wname = $widget->{cf_name} ? " for widget '$widget->{cf_name}'" : "";
148 1 50       7 my $argdecl = $widget->{arg_dict}{$name}
149             or die "Unknown args$wname: $name\n";
150 1         5 my @value = $cgi->multi_param($name);
151 1 50       14 $list->[$argdecl->argno] = $argdecl->type->[0] eq 'list'
152             ? \@value : $value[0];
153             }
154 139         525 @$list;
155             }
156             }
157             #========================================
158             sub configure_rc_script {
159 1     1 0 3 (my MY $vfs, my $script) = @_;
160 1         3 my Folder $f = $vfs->{root};
161             my $pkg = $f->{cf_entns}
162 1 50       5 or die $vfs->error("package name is not specified for configure rc_script");
163             # print STDERR "#### $pkg \n";
164             # XXX: base は設定済みだったはずだけど...
165 1         7 ckeval(qq{package $pkg; use strict; use YATT::Lite; $script});
166             }
167             #========================================
168              
169             # Template alias さえ拡張すれば済むように。
170             # 逆に言うと、 vfs_file だけを定義して Template を定義しなかった場合, 継承が働かなくなった。
171             sub create_file {
172 72     72 0 228 (my MY $vfs, my $spec) = splice @_, 0, 2;
173 72         560 $vfs->Template->new(path => $spec, @_);
174             }
175              
176             #
177             # called from
178             #
179             sub declare_base {
180 7     7 0 23 (my MY $vfs, my ParsingState $state, my Template $tmpl, my ($ns, @args)) = @_;
181              
182 7 50       20 unless (@args) {
183 0         0 $vfs->synerror($state, q{No base arg});
184             }
185              
186 7   50     38 my $base = $tmpl->{cf_base} //= [];
187 7 50       19 if (@$base) {
188 0         0 $vfs->synerror($state, "Duplicate base decl! was=%s, new=%s"
189             , terse_dump($base), terse_dump(\@args));
190             }
191              
192 7         17 foreach my $att (@args) {
193 7         32 my $type = $vfs->node_type($att);
194              
195 7 50       19 $type == TYPE_ATT_TEXT
196             or $vfs->synerror($state, q{Not implemented base decl type: %s}, $att);
197              
198 7 50       26 nonempty(my $fn = $vfs->node_value($att))
199             or $vfs->synerror($state, q{base spec is empty!});
200              
201 7 100       22 if ($vfs->{on_memory}) {
202 2 50       16 my $o = $vfs->find_file($fn)
203             or $vfs->synerror($state, q{No such base path: %s}, $fn);
204 2         10 push @$base, $o;
205             } else {
206 5 50       21 defined(my $realfn = $vfs->resolve_path_from($tmpl, $fn))
207             or $vfs->synerror($state, q{Can't find object path for: %s}, $fn);
208              
209 5 50       88 -e $realfn
210             or $vfs->synerror($state, q{No such base path: %s}, $realfn);
211              
212 5         22 push @$base, $vfs->find_neighbor_type(undef, $realfn);
213             }
214             }
215             }
216              
217             sub synerror {
218 0     0 0 0 (my MY $vfs, my ParsingState $state, my ($fmt, @opts)) = @_;
219 0         0 my $opts = {depth => 2};
220 0 0       0 $opts->{tmpl_file} = $state->{cf_path} if $state->{cf_path};
221 0 0       0 $opts->{tmpl_line} = $state->{startln} if $state->{startln};
222 0         0 die $vfs->error($opts, $fmt, @opts);
223             }
224              
225             #========================================
226             {
227             sub Parser {
228             # local $@;
229             # my $err = catch {
230 449     449 0 5989 require YATT::Lite::LRXML;
231             # };
232             # unless ($err =~ /^Can't locate loadable object for module main::Tie::Hash::NamedCapture/) {
233             # die $err || $@ || "(unknown reason)";
234             # }
235 449         2504 'YATT::Lite::LRXML'
236             }
237 0     0 0 0 sub cgen_perl { 'YATT::Lite::CGen::Perl' }
238             sub stat_mtime {
239 254     254 0 549 my ($fn) = @_;
240 254 50       4224 -e $fn or return;
241 254         3040 (stat($fn))[9];
242             }
243             sub get_parser {
244 449     449 0 910 my MY $self = shift;
245             # $self->{parser} ||=
246             $self->Parser->new
247             (vfs => $self, $self->cf_delegate
248             (qw(namespace special_entities
249             match_argsroute_first
250             )
251             , [debug_parser => 'debug']
252             , [tmpl_encoding => 'encoding']
253             )
254 449 50       1217 , $self->{cf_parse_while_loading} ? (all => 1) : ()
255             , @_);
256             }
257             sub ensure_parsed {
258 2     2 0 7 (my MY $self, my Widget $widget) = @_;
259 2         8 $self->get_parser->parse_body($widget->{cf_folder});
260             # $self->get_parser->parse_widget($widget)
261 2         21 @{$widget->{tree}};
  2         8  
262             }
263             sub render {
264 0     0 0 0 my MY $self = shift;
265 0 0       0 open my $fh, '>', \ (my $str = "") or die "Can't open capture buffer!: $!";
266 0         0 $self->render_into($fh, @_);
267 0         0 close $fh;
268 0         0 $str;
269             }
270             sub render_into {
271 55     55 0 147 (my MY $self, my ($fh, $namerec, $args, @opts)) = @_;
272 55         167 my ($part, $sub, $pkg) = $self->find_part_handler($namerec);
273 55 50       210 unless ($part->public) {
274             # XXX: refresh する手もあるだろう。
275 0         0 croak $self->error(q|Forbidden request '%s'|, terse_dump($namerec));
276             }
277              
278 55         89 my @args = do {
279 55 50 66     270 unless (defined $args and $part->isa(MY->Widget)) {
    100          
280 45         91 ();
281 0         0 } elsif (ref $args eq 'ARRAY') {
282 10         34 @$args
283             } else {
284             # $args can be a Hash::MultiValue and other HASH compatible obj.
285 0         0 $part->reorder_hash_params($args);
286             }
287             };
288              
289 55 50       148 if (@opts) {
290 0         0 $self->cf_let(\@opts, $sub, $pkg, $fh, @args);
291             } else {
292 55         186 $sub->($pkg, $fh, @args);
293             }
294             }
295              
296             # root から見える part (と、その template)を取り出す。
297             sub get_part {
298 0     0 0 0 (my MY $self, my $name, my %opts) = @_;
299 0         0 my $ignore_error = delete $opts{ignore_error};
300 0         0 my Template $tmpl;
301             my Part $part;
302 0 0       0 if (UNIVERSAL::isa($self->{root}, Template)) {
303 0         0 $tmpl = $self->{root};
304 0         0 $part = $self->find_part($name);
305             } else {
306 0 0 0     0 $tmpl = $self->find_file($name)
      0        
307             or ($ignore_error and return)
308             or croak "No such template file: $name";
309 0         0 $part = $tmpl->{Item}{''};
310             }
311             # XXX: それとも、 $part から $tmpl が引けるようにするか? weaken して...
312 0 0       0 wantarray ? ($part, $tmpl) : $part;
313             }
314              
315             sub find_part_handler {
316 136     136 0 418 (my MY $self, my $nameSpec, my %opts) = @_;
317 136         297 my $ignore_error = delete $opts{ignore_error};
318 136 100       494 my ($partName, $kind, $pureName, @rest)
319             = ref $nameSpec ? @$nameSpec : $nameSpec;
320              
321 136   100     444 $partName ||= $self->{cf_index_name};
322 136   100     709 $kind //= 'page';
323 136   100     658 $pureName //= '';
324              
325 136         740 my ($itemKey, $method) = $self->can("_itemKey_$kind")->($self, $pureName);
326              
327 136         308 (my Template $tmpl, my Part $part);
328              
329 136 100       1303 if (UNIVERSAL::isa($self->{root}, Template)) {
330             # Special case.
331 1         2 $tmpl = $self->{root};
332              
333 1 0 0     6 $part = $tmpl->{Item}{$partName}
      33        
334             or ($ignore_error and return)
335             or croak "No such item in template: $partName";
336              
337 1         4 $method = "render_$partName";
338              
339             } else {
340             # General container case.
341 135 0 50     607 $tmpl = $self->find_file($partName)
      66        
342             or ($ignore_error and return)
343             or croak "No such template file: $partName";
344 124 50 66     622 $part = $tmpl->{Item}{$itemKey} || $self->find_part_from($tmpl, $itemKey)
      50        
      66        
345             or ($ignore_error and return)
346             or croak "No such $kind in file $partName: $pureName";
347             }
348              
349              
350 123 0 0     494 my $pkg = $self->find_product(perl => $tmpl)
      33        
351             or ($ignore_error and return)
352             or croak "Can't compile template file: $partName";
353              
354 123 0 0     1916 my $sub = $pkg->can($method)
      33        
355             or ($ignore_error and return)
356             or croak "Can't extract $method from file: $partName";
357              
358 123         712 ($part, $sub, $pkg, @rest);
359             }
360              
361 133     133   263 sub _itemKey_page { shift; ($_[0], "render_$_[0]") }
  133         451  
362 3     3   8 sub _itemKey_action { shift; ("do_$_[0]") x 2; }
  3         13  
363              
364             #
365             # Action name => sub {}
366             #
367             sub add_root_action_handler {
368 0     0 0 0 (my MY $self, my ($name, $sub, $callinfo)) = @_;
369 0         0 my Folder $root = $self->{root};
370              
371 0         0 my ($callpack, $filename, $lineno) = @$callinfo;
372              
373             # XXX: This means do_$A.yatt will conflict with "Action $A" in .htyattrc.pl
374 0         0 my $action_name = "do_$name";
375              
376 0         0 *{globref($root->{cf_entns}, $action_name)} = $sub;
  0         0  
377              
378 0         0 $root->{Item}{$action_name}
379             = $self->Action->new(name => $action_name, kind => 'action'
380             , folder => $root
381             , startln => $lineno
382             );
383              
384             }
385              
386             sub find_renderer {
387 12     12 0 24 my MY $self = shift;
388 12 100       45 my ($part, $sub, $pkg) = $self->find_part_handler(@_)
389             or return;
390 1 50       8 wantarray ? ($sub, $pkg) : $sub;
391             }
392              
393             # DirHandler INST 固有 CGEN_perl の生成
394             sub get_cgen_class {
395 210     210 0 527 (my MY $self, my $type) = @_;
396 210         1359 $self->{cf_facade}->get_cgen_class($type);
397             }
398              
399             # XXX: Action only コンパイルは?
400             sub find_product {
401 382     382 0 1223 (my MY $self, my $spec, my Template $tmpl, my %opts) = @_;
402 382 50       1150 my ($type, $kind) = ref $spec ? @$spec : $spec;
403             # local $YATT = $self;
404 382 100       1237 unless ($tmpl->{product}{$type}) {
405 210         686 my $cg_class = $self->get_cgen_class($type);
406             my $cgen = $cg_class->new
407             (vfs => $self
408             , $self->cf_delegate(qw(no_lineinfo check_lineno only_parse
409             lcmsg_sink))
410             , parser => $self->get_parser
411             , sink => $opts{sink} || sub {
412 201     201   885 my ($info, @script) = @_;
413 201 50       708 if (not $self->{cf_debug_cgen}) {
414             } else {
415 0         0 my Template $real = $info->{folder};
416 0         0 print STDERR "# compiling $type code of $real->{cf_path}\n";
417 0         0 if ($self->{cf_debug_cgen} >= 2) {
418 0         0 print STDERR "#--BEGIN--\n";
419 0         0 print STDERR @script, "\n";
420 0         0 print STDERR "#--END--\n\n"
421             }
422             }
423             #
424 201         428 $self->{n_compiles}++;
425              
426 201         881 ckeval(@script);
427 210   50     913 });
428             # 二重生成防止のため、代入自体は ensure_generated の中で行う。
429 210         1643 $cgen->ensure_generated($spec => $tmpl);
430             };
431 355         2460 $tmpl->{product}{$type};
432             }
433              
434             #
435             # extract_lcmsg
436             # - filelist is a list(or scalar) of filename or item name(no ext).
437             # - msgdict is used to share same msgid.
438             # - msglist is used to keep msg order.
439             #
440             # XXX: find_product and extract_lcmsg is exclusive.
441             sub extract_lcmsg {
442 2     2 0 6 (my MY $self, my ($filelist, $msglist, $msgdict)) = @_;
443 2         11 require Locale::PO;
444 2   50     6 $msglist //= [];
445 2   50     12 $msgdict //= {};
446             local $self->{cf_lcmsg_sink} = sub {
447 3     3   12 $self->define_lcmsg_in($msglist, $msgdict, @_);
448 2         11 };
449 2         5 my $type = 'perl';
450 2         9 foreach my $name (lexpand($filelist)) {
451 2 50       8 my Template $tmpl = $self->find_file($name)
452             or croak "No such template: $name";
453 2         8 $self->find_product($type => $tmpl);
454             }
455             # XXX: not wantarray
456 2         15 @$msglist;
457             }
458              
459              
460             sub define_lcmsg_in {
461 3     3 0 9 (my MY $self, my ($list, $dict, $place, $msgid, $other_msgs, $args)) = @_;
462 3 50       10 if (my $obj = $dict->{$msgid}) {
463 0         0 $obj->reference(join " ", grep {defined $_} $obj->reference, $place);
  0         0  
464             } else {
465 3         8 my @o = (-msgid => $msgid);
466 3 100 66     14 if ($other_msgs and $other_msgs->[0]) {
467 1         7 push @o, -msgid_plural => $other_msgs->[0]
468             , -msgstr_n => {0 => '', 1 => ''};
469             } else {
470 2         5 push @o, -msgstr => '';
471             }
472 3         17 push @$list, my $po = $dict->{$msgid} = Locale::PO->new(@o);
473 3         255 $po->add_flag('perl-format');
474 3         64 $po->reference($place);
475             }
476             }
477              
478             sub YATT::Lite::Core::Template::after_create {
479 230     230 0 599 (my Template $tmpl, my MY $self) = @_;
480             # XXX: ここでは SUPER が使えない。
481 230         1256 $tmpl->YATT::Lite::VFS::File::after_create($self);
482             ($tmpl->{cf_name}) = $tmpl->{cf_path} =~ m{(\w+)\.\w+$}
483             or $self->error("Can't extract part name from '%s'", [$tmpl->{cf_path}])
484 227 50 0     1136 if not defined $tmpl->{cf_name} and defined $tmpl->{cf_path};
      66        
485             }
486             sub YATT::Lite::Core::Template::reset {
487 7     7 0 20 (my Template $tmpl) = @_;
488 7         70 $tmpl->YATT::Lite::VFS::File::reset;
489 7         21 undef $tmpl->{product};
490 7         15 undef $tmpl->{parse_ok};
491 7         23 undef $tmpl->{cf_subroutes};
492             # delpkg($tmpl->{cf_package}); # No way to avoid redef error.
493             }
494             sub YATT::Lite::Core::Template::refresh {
495 416     416 0 969 (my Template $tmpl, my MY $self) = @_;
496              
497 416         994 my $old_product = $tmpl->{product};
498              
499 416 100 66     1657 if ($tmpl->{cf_path}) {
    100          
500 254         459 printf STDERR "template_refresh(%s)\n", $tmpl->{cf_path} if DEBUG_REBUILD;
501 254         788 my $mtime = stat_mtime($tmpl->{cf_path});
502 254 50 66     1630 unless (defined $mtime) {
503 0         0 printf STDERR " => deleted\n" if DEBUG_REBUILD;
504 0         0 return; # XXX: ファイルが消された
505             } elsif (defined $tmpl->{cf_mtime} and $tmpl->{cf_mtime} >= $mtime) {
506             if (DEBUG_REBUILD) {
507             printf STDERR " => use cached. mtime(was=$tmpl->{cf_mtime}"
508             .", now=$mtime) for tmpl=$tmpl\n";
509             }
510             $self->refresh_deps_for($tmpl) if $self->{cf_always_refresh_deps};
511             return; # timestamp は、キャッシュと同じかむしろ古い
512             }
513 79         170 if (DEBUG_REBUILD) {
514             printf STDERR " => found update. mtime($mtime) for tmpl=$tmpl\n";
515             }
516 79         173 $tmpl->{cf_mtime} = $mtime;
517 79         248 my $parser = $self->get_parser;
518             # decl のみ parse.
519             # XXX: $tmpl->{cf_package} の指すパッケージをこの段階で map {undef $_}
520             # すべきではないか?
521 79         440 $parser->load_file_into($tmpl, $tmpl->{cf_path});
522             } elsif ($tmpl->{cf_string} and not $tmpl->{cf_mtime}) {
523             # To avoid recompilation, use mtime to express generated time.
524             # Not so good.
525 158         445 $tmpl->{cf_mtime} = time;
526              
527 158         461 my $parser = $self->get_parser;
528             $parser->load_string_into($tmpl, $tmpl->{cf_string}
529 158         818 , scheme => "data", path => $tmpl->{cf_name});
530             } else {
531 4         11 return;
532             }
533              
534             # $tmpl->YATT::Lite::VFS::Folder::vivify_base_descs($self);
535              
536             # If there was products, rebuild it too.
537 234 100       901 foreach my $type ($old_product ? keys %$old_product : ()) {
538 7         42 $self->find_product($type => $tmpl);
539             }
540              
541 234         589 $tmpl;
542             }
543             sub YATT::Lite::Core::Widget::fixup {
544 389     389 0 869 (my Widget $widget, my Template $tmpl, my $parser) = @_;
545 389         661 foreach my $argName (@{$widget->{arg_order}}) {
  389         956  
546             $widget->{has_required_arg} = 1
547 277 100       940 if $widget->{arg_dict}{$argName}->is_required;
548             }
549 389   66     1621 $widget->{arg_dict}{body} ||= do {
550             # lineno も入れるべきかも。 $widget->{cf_bodyln} あたり.
551             my $var = $parser->mkvar_at(undef, code => 'body'
552 376   50     710 , scalar @{$widget->{arg_order} ||= []});
  376         1607  
553 376         688 push @{$widget->{arg_order}}, 'body';
  376         889  
554 376         1414 $var;
555             };
556             }
557              
558             sub YATT::Lite::Core::Template::match_subroutes {
559 75     75 0 163 my Template $tmpl = shift;
560 75 100       238 return unless $tmpl->{cf_subroutes};
561 74         347 $tmpl->{cf_subroutes}->match($_[0]);
562             }
563             }
564              
565 17     17   177 use YATT::Lite::Breakpoint ();
  17         43  
  17         1052  
566             YATT::Lite::Breakpoint::break_load_core();
567              
568             1;