File Coverage

blib/lib/YATT/Lite.pm
Criterion Covered Total %
statement 249 338 73.6
branch 57 106 53.7
condition 21 51 41.1
subroutine 61 76 80.2
pod 5 48 10.4
total 393 619 63.4


line stmt bran cond sub pod time code
1             package YATT::Lite; sub MY () {__PACKAGE__}
2 19     19   8581 use strict;
  19         51  
  19         632  
3 19     19   105 use warnings qw(FATAL all NONFATAL misc);
  19         39  
  19         670  
4 19     19   347 use 5.010; no if $] >= 5.017011, warnings => "experimental";
  19     19   76  
  19         319  
  19         4715  
  19         159  
5              
6 19     19   1433 use Carp qw(carp croak confess);
  19         49  
  19         1338  
7             our $VERSION = '0.101_001';
8 19     19   290 use mro 'c3';
  19         4885  
  19         128  
9              
10 19     19   640 use Scalar::Util qw/weaken/;
  19         43  
  19         889  
11 19     19   112 use List::MoreUtils qw/uniq/;
  19         49  
  19         478  
12              
13             #
14             # YATT Internalへの Facade. YATT の初期化パラメータの保持者でもある。
15             #
16 19     19   14751 use parent qw/YATT::Lite::Object File::Spec/;
  19         2271  
  19         127  
17 19         125 use YATT::Lite::MFields qw/YATT
18             cf_dir
19             cf_vfs cf_base
20             cf_factory
21             cf_header_charset
22             cf_output_encoding
23             cf_tmpl_encoding
24             cf_index_name
25             cf_ext_public
26             cf_ext_private
27             cf_app_ns
28             entns
29             cgen_class
30              
31             cf_app_name
32             cf_debug_cgen cf_debug_parser cf_namespace cf_only_parse
33             cf_special_entities cf_no_lineinfo cf_check_lineno
34             cf_rc_script
35             cf_tmpl_cache
36             cf_dont_map_args
37             cf_dont_debug_param
38             cf_info
39             cf_lcmsg_sink
40             cf_always_refresh_deps
41             cf_no_mro_c3
42              
43             cf_default_lang
44              
45             cf_entns2vfs_item
46             cf_import
47             cf_match_argsroute_first
48 19     19   4069 /;
  19         49  
49              
50 19     19   207 use constant DEBUG => $ENV{DEBUG_YATT_LITE};
  19         43  
  19         1799  
51              
52             MY->cf_mkaccessors(qw/app_name/);
53              
54             # Entities を多重継承する理由は import も継承したいから。
55             # XXX: やっぱり、 YATT::Lite には固有の import を用意すべきではないか?
56             # yatt_default や cgen_perl を定義するための。
57 19     19   5087 use YATT::Lite::Entities -as_base, qw(*YATT *CON *SYS);
  19         46  
  19         161  
58              
59             # For error, raise, DONE. This is inserted to ISA too.
60 19     19   4477 use YATT::Lite::Partial::ErrorReporter;
  19         50  
  19         157  
61              
62 19     19   4256 use YATT::Lite::Partial::AppPath;
  19         46  
  19         100  
63              
64 19         35314 use YATT::Lite::Util qw/globref lexpand extname ckrequire terse_dump escape
65             set_inc ostream try_invoke list_isa symtab
66             look_for_globref
67             subname ckeval ckrequire
68             secure_text_plain
69             define_const
70 19     19   132 /;
  19         51  
71              
72             sub Facade () {__PACKAGE__}
73 6     6 0 37 sub default_app_ns {'MyApp'}
74 69     69 0 157 sub default_trans {'YATT::Lite::Core'}
75 4     4 0 32 sub default_export {(shift->SUPER::default_export, qw(Entity *SYS *CON))}
76 0     0 0 0 sub default_index_name { '' }
77 21     21 0 90 sub default_ext_public {'yatt'}
78 21     21 0 92 sub default_ext_private {'ytmpl'}
79              
80             sub with_system {
81 215     215 0 669 (my MY $self, local $SYS, my $method) = splice @_, 0, 3;
82 215         1169 $self->$method(@_);
83             }
84              
85             sub after_new {
86 88     88 1 204 (my MY $self) = @_;
87 88         422 $self->SUPER::after_new;
88 88   100     347 $self->{cf_index_name} //= "";
89 88   66     313 $self->{cf_ext_public} //= $self->default_ext_public;
90 88   66     317 $self->{cf_ext_private} //= $self->default_ext_private;
91             }
92              
93             sub _after_after_new {
94 88     88   198 (my MY $self) = @_;
95 88         412 weaken($self->{cf_factory});
96             }
97              
98             # XXX: kludge!
99             sub find_neighbor_yatt {
100 38     38 0 78 (my MY $self, my ($dir)) = @_;
101 38         137 $self->{cf_factory}->load_yatt($dir);
102             }
103             sub find_neighbor_vfs {
104 37     37 0 78 (my MY $self, my ($dir)) = @_;
105 37         120 $self->find_neighbor_yatt($dir)->get_trans;
106             }
107             sub find_neighbor {
108 33     33 0 77 (my MY $self, my ($dir)) = @_;
109 33         111 $self->find_neighbor_vfs($dir)->root;
110             }
111              
112             #
113             # list all configs (named $name). (base first, then local one)
114             # (useful to avoid config repeation)
115             #
116             sub cget_all {
117 2     2 0 1935 (my MY $self, my $name) = @_;
118             (map($_->cget_all($name)
119             , $self->list_base_obj)
120 2         9 , lexpand($self->{"cf_$name"}));
121             }
122              
123             sub list_base_obj {
124 2     2 0 4 (my MY $self) = @_;
125             map {
126 2         8 $self->find_neighbor_yatt($self->app_path_normalize($_))
  1         7  
127             } $self->list_base_dir;
128             }
129              
130             sub list_base_dir {
131 2     2 0 5 (my MY $self) = @_;
132              
133 2   33     8 my $base = $self->{cf_base} // do {
134 2         7 my %vfs = lexpand($self->{cf_vfs});
135             [map {
136             #
137             # Each element of $vfs{base} is either ARRAY (of vfs spec)
138             # or YATT::Lite::VFS::Dir object (instantiated from spec).
139             #
140 1 50       4 if (ref $_ eq 'ARRAY') {
141 1         3 my %vfs_base = @$_;
142 1         7 $vfs_base{dir};
143             } else {
144 0         0 $_->{cf_path};
145             }
146 2         7 } lexpand($vfs{base})];
147             };
148              
149 2         6 lexpand($base);
150             }
151              
152             #========================================
153             # file extension based handler dispatching.
154             #========================================
155              
156             sub handle {
157 178     178 0 507 (my MY $self, my ($ext, $con, $file)) = @_;
158 178         455 local ($YATT, $CON) = ($self, $con);
159 178         780 $con->configure(yatt => $self);
160 178 50       677 if (my $enc = $self->{cf_output_encoding}) {
161 178         537 $con->configure(encoding => $enc);
162             }
163              
164 178 50       593 unless (defined $file) {
165 0         0 confess "\n\nFilename for DirHandler->handle() is undef!"
166             ." in $self->{cf_app_ns}.\n";
167             }
168              
169 178         958 my $sub = $YATT->find_handler($ext, $file, $CON);
170 178         603 $sub->($YATT, $CON, $file);
171              
172 156         12306 try_invoke($CON, 'flush_headers');
173              
174 156         2459 $CON;
175             }
176              
177             sub render {
178 15     15 1 53 my MY $self = shift;
179 15         28 my $buffer; {
180 15 50       25 my $con = $SYS
  15         78  
181             ? $SYS->make_connection(undef, buffer => \$buffer, yatt => $self)
182             : ostream(\$buffer);
183 15         117 $self->render_into($con, @_);
184             }
185 15         121 $buffer;
186             }
187              
188             sub render_into {
189 55     55 1 157 local ($YATT, $CON) = splice @_, 0, 2;
190 55         188 $YATT->open_trans->render_into($CON, @_);
191 55         213 try_invoke($CON, 'flush_headers');
192             }
193              
194             sub find_handler {
195 148     148 1 421 (my MY $self, my ($ext, $file, $con)) = @_;
196 148   0     425 $ext //= $self->cut_ext($file) || $self->{cf_ext_public};
      33        
197 148 100       652 $ext = "yatt" if $ext eq $self->{cf_ext_public};
198 148 50       1194 my $sub = $self->can("_handle_$ext")
199             or die "Unsupported file type: $ext";
200 148         466 $sub;
201             }
202              
203             #----------------------------------------
204              
205             # 直接呼ぶことは禁止。∵ $YATT, $CON を設定するのは handle の役目だから。
206             sub _handle_yatt {
207 142     142   312 (my MY $self, my ($con, $file)) = @_;
208              
209 142         560 my ($part, $sub, $pkg, $args)
210             = $self->prepare_part_handler($con, $file);
211              
212 141         585 $sub->($pkg, $con, @$args);
213              
214 140         544 $con;
215             }
216              
217             sub _handle_ytmpl {
218 0     0   0 (my MY $self, my ($con, $file)) = @_;
219             # XXX: http result code:
220 0         0 print $con "Forbidden filetype: $file";
221             }
222              
223             #----------------------------------------
224              
225             sub prepare_part_handler {
226 0     0 0 0 (my MY $self, my ($con, $file)) = @_;
227              
228 0         0 my $trans = $self->open_trans;
229              
230 0         0 my $mapped = [$file, my ($type, $item) = $self->parse_request_sigil($con)];
231 0 0 0     0 if (not $self->{cf_dont_debug_param}
232             and -e ".htdebug_param") {
233 0         0 $self->dump($mapped, [map {[$_ => $con->param($_)]} $con->param]);
  0         0  
234             }
235              
236             # XXX: public に限定するのはどこで? ここで?それとも find_自体?
237 0         0 my ($part, $sub, $pkg) = $trans->find_part_handler($mapped);
238 0 0       0 unless ($part->public) {
239             # XXX: refresh する手もあるだろう。
240 0         0 croak $self->error(q|Forbidden request %s|, terse_dump($mapped));
241             }
242              
243 0         0 my @args; @args = $part->reorder_cgi_params($con)
244 0 0 0     0 unless $self->{cf_dont_map_args} || $part->isa($trans->Action);
245              
246 0         0 ($part, $sub, $pkg, \@args);
247             }
248              
249             sub parse_request_sigil {
250 142     142 0 336 (my MY $self, my ($con)) = @_;
251 142         278 my ($subpage, $action);
252             # XXX: url_param
253 142         634 foreach my $name (grep {defined} $con->param()) {
  6         65  
254 6 100       33 my ($sigil, $word) = $name =~ /^([~!])(\1|\w*)$/
255             or next;
256             # If $name in ('~~', '!!'), use value.
257 3 50       14 my $new = $word eq $sigil ? $con->param($name) : $word;
258             # else use $word from ~$word.
259             # Note: $word may eq ''. This is for render_/action_.
260 3         26 given ($sigil) {
261 3         8 when ('~') {
262 1 50       4 if (defined $subpage) {
263 0         0 $self->error("Duplicate subpage request! %s vs %s"
264             , $subpage, $new);
265             }
266 1         3 $subpage = $new;
267             }
268 2         5 when ('!') {
269 2 50       7 if (defined $action) {
270 0         0 $self->error("Duplicate action! %s vs %s"
271             , $action, $new);
272             }
273 2         8 $action = $new;
274             }
275 0         0 default {
276 0         0 croak "Really?";
277             }
278             }
279             }
280 142 50 66     762 if (defined $subpage and defined $action) {
    100          
    100          
281             # XXX: Reserved for future use.
282 0         0 $self->error("Can't use subpage and action at one time: %s vs %s"
283             , $subpage, $action);
284             } elsif (defined $subpage) {
285 1         4 (page => $subpage);
286             } elsif (defined $action) {
287 2         7 (action => $action);
288             } else {
289 139         458 ();
290             }
291             }
292              
293             sub cut_ext {
294 178     178 0 490 my ($self, $fn) = @_;
295 178 50       537 croak "Undefined filename!" unless defined $fn;
296 178 50       1376 return undef unless $fn =~ s/\.(\w+$)//;
297 178         1090 $1;
298             }
299              
300             #========================================
301             # hook
302             #========================================
303       218 0   sub finalize_connection {}
304              
305             #========================================
306             # Output encoding. Used in scripts/yatt*
307             #========================================
308             sub fconfigure_encoding {
309 0     0 0 0 my MY $self = shift;
310 0 0       0 return unless $self->{cf_output_encoding};
311 0         0 my $enc = "encoding($self->{cf_output_encoding})";
312 0         0 require PerlIO;
313 0         0 foreach my $fh (@_) {
314 0 0       0 next if grep {$_ eq $enc} PerlIO::get_layers($fh);
  0         0  
315 0         0 binmode($fh, ":$enc");
316             }
317 0         0 $self;
318             }
319              
320             #========================================
321             # Delayed loading of YATT::Lite::Core
322             #========================================
323              
324             *open_vfs = *open_trans; *open_vfs = *open_trans;
325             sub open_trans {
326 197     197 0 478 (my MY $self) = @_;
327 197         617 my $trans = $self->get_trans;
328 197         1045 $trans->reset_refresh_mark;
329 197         942 $trans;
330             }
331              
332             *get_vfs = *get_trans; *get_vfs = *get_trans;
333             sub get_trans {
334 635     635 0 1458 (my MY $self) = @_;
335 635 100       3782 $self->{YATT} || $self->build_trans($self->{cf_tmpl_cache});
336             }
337              
338             sub build_trans {
339 69     69 0 235 (my MY $self, my ($vfscache, $vfsspec, @rest)) = @_;
340 69         324 my $class = $self->default_trans;
341 69         324 ckrequire($class);
342              
343 69 50       152 my @vfsspec = @{$vfsspec || $self->{cf_vfs}};
  69         547  
344 69 50       245 push @vfsspec, base => $self->{cf_base} if $self->{cf_base};
345              
346             $self->{YATT} = $class->new
347             (\@vfsspec
348             , facade => $self
349             , cache => $vfscache
350             , entns2vfs_item => $self->{cf_entns2vfs_item}
351             , entns => $self->{entns}
352             , @rest
353 69         522 , $self->cf_delegate_defined($self->_cf_delegates));
354             }
355              
356             sub _cf_delegates {
357 70     70   780 qw(namespace
358             base
359             die_in_error
360             tmpl_encoding
361             debug_cgen
362             debug_parser
363             special_entities
364             no_lineinfo
365             check_lineno
366             index_name
367             ext_public
368             ext_private
369             rc_script
370             lcmsg_sink
371             only_parse
372             always_refresh_deps
373             no_mro_c3
374             import
375             match_argsroute_first
376             )
377             }
378              
379             sub _before_after_new {
380 88     88   215 (my MY $self) = @_;
381 88   33     334 $self->{cf_app_ns} //= $self->default_app_ns;
382 88         425 $self->{entns} = $self->ensure_entns($self->{cf_app_ns});
383             }
384              
385             #========================================
386             # Code generator class
387             #========================================
388              
389             sub root_CGEN_perl () { 'YATT::Lite::CGen::Perl' }
390             *CGEN_perl = *root_CGEN_perl; *CGEN_perl = *root_CGEN_perl;
391             sub ensure_cgen_for {
392 52     52 0 177 my ($mypack, $type, $app_ns) = @_;
393 52         248 $mypack->ensure_supplns("CGEN_$type" => $app_ns);
394             }
395              
396             sub get_cgen_class {
397 210     210 0 575 (my MY $self, my $type) = @_;
398 210         508 my $name = "CGEN_$type";
399 210 50       1397 my $sub = $self->can("root_$name")
400             or croak "Unknown cgen class: $type";
401             $self->{cgen_class}{$type}
402 210   66     1394 ||= $self->ensure_cgen_for($type, $self->{cf_app_ns});
403             }
404              
405             sub is_default_cgen_ready {
406 11     11 0 28 (my MY $self) = @_;
407 11         64 $self->{cgen_class}{perl};
408             }
409              
410             #========================================
411             # Entity
412             #========================================
413              
414 47     47 0 165 sub root_EntNS { 'YATT::Lite::Entities' }
415              
416             # ${app_ns}::EntNS を作り、(YATT::Lite::Entities へ至る)継承関係を設定する。
417             # $app_ns に EntNS constant を追加する。
418             # 複数回呼ばれた場合、既に定義済みの entns を返す
419              
420             sub should_use_mro_c3 {
421 678     678 0 1381 (my MY $self_or_pack) = @_;
422 678 100       1492 if (ref $self_or_pack) {
423             not $self_or_pack->{cf_no_mro_c3}
424 300         1042 } else {
425 378         1786 mro::get_mro($self_or_pack) eq 'c3';
426             }
427             }
428              
429             #========================================
430              
431             # These ns-related methods (ensure_...) are called as Class Methods.
432             # This means you can't touch instance fields.
433              
434             # Old interface.
435             # ensure_entns($app_ns, @base_entns)
436             # returns EntNS for $app_ns with correct inheritance settings.
437             #
438             sub ensure_entns {
439 433     433 0 1133 my ($mypack, $app_ns, @base_entns) = @_;
440 433         1890 my $entns = $mypack->ensure_supplns(EntNS => $app_ns, \@base_entns
441             , undef, +{no_fields => 1});
442 433         1536 $entns;
443             }
444              
445             # New interface.
446             # ensure_supplns($kind, $app_ns, [@base_suppls], [@base_mains], {%opts})
447             # returns ${app_ns}::${kind} with correct inheritance.
448             #
449             # [@base_suppls] gives base supplemental classes for this supplns.
450             # [@base_mains] gives (not supplemental but) main classes for this.
451             #
452             # If both base_suppls and base_mains is empty, base_mains is derived
453             # from current @ISA of $app_ns.
454             #
455             sub ensure_supplns {
456 575     575 0 1447 my ($mypack, $kind, $app_ns, $base_suppls, $base_mains, $opts) = @_;
457              
458 575         1571 my $supplns = join("::", $app_ns, $kind);
459              
460 19     19   177 my $sym = do {no strict 'refs'; \*{$supplns}};
  19         41  
  19         18767  
  575         940  
  575         812  
  575         2157  
461 575 100       992 if (*{$sym}{CODE}) {
  575         1609  
462             # croak "$kind for $app_ns is already defined!";
463 279         855 return $supplns;
464             }
465              
466 296         480 my $app_ns_filename = do {
467 296         3282 my $sub = $app_ns->can("filename");
468 296 100 100     1109 $sub ? ("(For path '".($sub->() // '')."')") : "";
469             };
470              
471 296         496 print STDERR "# First ensure_supplns $kind for $app_ns $app_ns_filename: "
472             , terse_dump($base_suppls, $base_mains, $opts), "\n" if DEBUG;
473              
474 296 50 66     998 if (not $base_suppls and not $base_mains) {
475 86         336 my @isa = list_isa($app_ns);
476 86         185 print STDERR "# app_ns $app_ns isa: "
477             , terse_dump(@isa), "\n" if DEBUG;
478              
479 86 50       339 $base_mains = $mypack->should_use_mro_c3
480             ? [reverse @isa] : \@isa;
481             }
482              
483             my @baseclass = (lexpand($base_suppls), map {
484 296         1043 $mypack->ensure_supplns($kind => $_, undef, undef, $opts);
  90         451  
485             } lexpand($base_mains));
486              
487 296 100       985 if ($mypack->should_use_mro_c3) {
488 294         493 print STDERR "# $kind - Set mro c3 for $supplns $app_ns_filename since $mypack uses c3\n" if DEBUG;
489 294         2196 mro::set_mro($supplns, 'c3')
490             } else {
491 2         5 print STDERR "# $kind - Keep mro dfs for $supplns $app_ns_filename since $mypack uses dfs\n" if DEBUG;
492             }
493              
494             # $app_ns が %FIELDS 定義を持たない時(ex YLObjectでもPartialでもない)に限り、
495             # YATT::Lite への継承を設定する
496 296 100       1422 unless (YATT::Lite::MFields->has_fields($app_ns)) {
497             # XXX: $mypack への継承にすると、あちこち動かなくなるぜ?なんで?
498 21         39 print STDERR "# app_ns - Add ISA for '$app_ns' with fields: ",MY,"\n"
499             if DEBUG;
500 21         107 YATT::Lite::MFields->add_isa_to($app_ns, MY)->define_fields($app_ns);
501             }
502              
503 296 50       717 unless (grep {$_->can($kind)} @baseclass) {
  255         2726  
504 296   66     1014 my $base = try_invoke($app_ns, $kind) // $mypack->can("root_$kind")->();
505 296         1072 ckrequire($base);
506 296         533 print STDERR "# $kind - Set default base for $supplns <- ($base)\n" if DEBUG;
507 296 100       937 if ($mypack->should_use_mro_c3) {
508 294         754 push @baseclass, $base;
509             } else {
510 2         5 unshift @baseclass, $base;
511             }
512             }
513              
514 296         535 do {
515 296         1374 my @cls = uniq @baseclass;
516 296         4535 print STDERR "# $kind - Add ISA for $supplns <- (@cls)\n" if DEBUG;
517 296         1193 YATT::Lite::MFields->add_isa_to($supplns, @cls);
518             };
519 296 100       927 if (not $opts->{no_fields}) {
520 86         328 YATT::Lite::MFields->define_fields($supplns);
521             }
522              
523 296         1182 set_inc($supplns, 1);
524              
525             # $kind() を足すのは最後にしないと、再帰継承に陥る
526 296 0       482 unless (my $code = *{$sym}{CODE}) {
  296 50       843  
527 296         925 define_const($sym, $supplns);
528 0         0 } elsif ((my $old = $code->()) ne $supplns) {
529 0         0 croak "Can't add $kind() to '$app_ns'. Already has $kind as $old!";
530             } else {
531             # ok.
532             }
533 296         1210 $supplns
534             }
535              
536             sub list_entns {
537 42     42 0 141 my ($pack, $inspected) = @_;
538             map {
539 42 100       215 defined(symtab($_)->{'EntNS'}) ? join("::", $_, 'EntNS') : ()
  103         308  
540             } list_isa($inspected)
541             }
542              
543             # use YATT::Lite qw(Entity); で呼ばれ、
544             # $callpack に Entity 登録関数を加える.
545             sub define_Entity {
546 142     142 0 429 my ($myPack, $opts, $callpack, @base) = @_;
547              
548             # Entity を追加する先は、 $callpack が Object 系か、 stateless 系かで変化する
549             # Object 系の場合は、 ::EntNS を作ってそちらに加え, 同時に YATT() も定義する
550 142         395 my $is_objclass = is_objclass($callpack);
551 142 100       567 my $destns = $is_objclass
552             ? $myPack->ensure_entns($callpack, @base)
553             : $callpack;
554              
555             # 既にあるなら何もしない。... バグの温床にならないことを祈る。
556 142         442 my $ent = globref($callpack, 'Entity');
557 142 100       292 unless (*{$ent}{CODE}) {
  142         420  
558             *$ent = sub {
559 355     355   748 my ($name, $sub) = @_;
560 355         848 my $longname = join "::", $destns, "entity_$name";
561 355         1146 subname($longname, $sub);
562 355         501 print STDERR "defining entity_$name in $destns\n" if DEBUG;
563 355         598 *{globref($destns, "entity_$name")} = $sub;
  355         991  
564 141         678 };
565             }
566              
567 142 100       444 if ($is_objclass) {
568 138         277 *{globref($destns, 'YATT')} = *YATT;
  138         371  
569              
570 138 100       1110 unless ($callpack->can("entity")) {
571 27         126 *{globref($callpack, "entity")} = $myPack->can('entity');
  27         86  
572             }
573             }
574              
575 142         2731 return $destns;
576             }
577              
578             #
579             # Note about 'Action' registration mechanism in .htyattrc.pl
580             #
581             # First, *globref() = $action is not enough. Because...
582             #
583             # There are 2 places to hold actions.
584             # 1. $YATT->{Action} <= comes from *.ydo
585             # 2. $vfs_folder->{Item} <= comes from !yatt:action in templates
586             #
587             # Action in .htyattrc.pl is, special case of 2.
588             # Since 2. is managed by yatt vfs, it must be wrapped by Action object
589             # so that $vfs->find_part_handler works well.
590             #
591             #
592             # This is bit complicated because .htyattrc.pl is loaded *BEFORE* $YATT
593             # is instantiated. This means "Action => name, $handler" can not touch $YATT
594             # at that time. So, I need to delay actual registration until $YATT is created.
595             #
596             # To achieve this, $handler is registered first in %Actions of caller,
597             # then installed into actual vfs.
598             #
599             # Also note: loading of .htyattrc.pl is handled by Factory.
600             #
601             sub ACTION_DICT_SYM () {'Actions'}
602             sub define_Action {
603 0     0 0 0 my ($myPack, $opts, $callpack) = @_;
604              
605 0         0 *{globref($callpack, ACTION_DICT_SYM)} = my $action_dict = +{};
  0         0  
606              
607 0         0 *{globref($callpack, 'Action')} = sub {
608 0     0   0 my ($name, $sub) = @_;
609 0         0 my @caller = my ($callpack, $filename, $lineno) = caller;
610 0 0       0 if (defined (my $old = $action_dict->{$name})) {
611 0         0 croak "Duplicate definition of Action '$name'! previously"
612             ." at $old->[1][1] line $old->[1][2]\n new at $filename line $lineno\n";
613             }
614 0         0 $action_dict->{$name} = [$sub, \@caller];
615 0         0 };
616             }
617              
618             sub setup_rc_actions {
619 4     4 0 9 (my $self) = @_;
620 4 50       11 my $glob = look_for_globref($self, ACTION_DICT_SYM)
621             or return;
622 0         0 my $dict = *{$glob}{HASH};
  0         0  
623              
624 0         0 my $vfs = $self->get_vfs;
625 0         0 foreach my $name (keys %$dict) {
626 0         0 $vfs->add_root_action_handler($name, @{$dict->{$name}});
  0         0  
627             }
628             }
629              
630             # ここで言う Object系とは、
631             # YATT::Lite::Object を継承してるか、
632             # 又は既に %FIELDS が定義されている class
633             # のこと
634             sub is_objclass {
635 142     142 0 322 my ($class) = @_;
636 142 100       709 return 1 if UNIVERSAL::isa($class, 'YATT::Lite::Object');
637 18 100       72 my $sym = look_for_globref($class, 'FIELDS')
638             or return 0;
639 14         34 *{$sym}{HASH};
  14         37  
640             }
641              
642             sub entity {
643 0     0 1 0 (my MY $yatt, my $name) = splice @_, 0, 2;
644 0         0 my $this = $yatt->EntNS;
645 0         0 $this->can("entity_$name")->($this, @_);
646             }
647              
648             BEGIN {
649 19     19   128 MY->define_Entity(undef, MY);
650             }
651              
652             #========================================
653             # Locale gettext support.
654             #========================================
655              
656             sub use_encoded_config {
657 0     0 0 0 (my MY $self) = @_;
658             $self->{cf_tmpl_encoding}
659 0         0 }
660              
661 19     19   9177 use YATT::Lite::Partial::Gettext;
  19         52  
  19         110  
662              
663             # Extract (and cache, for later merging) l10n msgs from filelist.
664             # By default, it merges $filelist into existing locale_cache.
665             # To get fresh list, explicitly pass $msglist=[].
666             #
667             sub lang_extract_lcmsg {
668 2     2 0 8 (my MY $self, my ($lang, $filelist, $msglist, $msgdict)) = @_;
669              
670 2 0 33     10 if (not $msglist and not $msgdict) {
671 0         0 ($msglist, $msgdict) = $self->lang_msgcat($lang)
672             }
673              
674 2         7 $self->get_trans->extract_lcmsg($filelist, $msglist, $msgdict);
675             }
676              
677 0     0 0 0 sub default_default_lang { 'en' }
678             sub default_lang {
679 0     0 0 0 (my MY $self) = @_;
680 0 0       0 $self->{cf_default_lang} || $self->default_default_lang;
681             }
682              
683             #========================================
684             # Delegation to the core(Translator, which is useless for non-templating.)
685             #========================================
686             foreach
687             (qw/find_part
688             find_part_from_entns
689             find_file
690             find_product
691             find_renderer
692             find_part_handler
693             ensure_parsed
694              
695             list_items
696              
697             add_to
698             /
699             ) {
700             my $meth = $_;
701             *{globref(MY, $meth)} = subname(join("::", MY, $meth)
702 394     394   24233 , sub { shift->get_trans->$meth(@_) });
703             }
704              
705             sub dump {
706 0     0 0 0 my MY $self = shift;
707             # XXX: charset...
708             die [200, [$self->secure_text_plain]
709 0         0 , [map {terse_dump($_)."\n"} @_]];
  0         0  
710             }
711              
712             #========================================
713             # Builtin Entities.
714             #========================================
715              
716             sub YATT::Lite::EntNS::entity_template {
717 3     3 0 106 my ($this, $pkg) = @_;
718 3   33     16 $YATT->get_trans->find_template_from_package($pkg // $this);
719             };
720              
721             sub YATT::Lite::EntNS::entity_stash {
722 0     0 0   my $this = shift;
723 0           my $prop = $CON->prop;
724 0   0       my $stash = $prop->{stash} //= {};
725 0 0         unless (@_) {
    0          
    0          
    0          
726 0           $stash
727 0           } elsif (@_ > 1) {
728 0           %$stash = @_;
729 0           } elsif (not defined $_[0]) {
730 0           carp "Undefined argument for :stash()";
731 0           } elsif (ref $_[0]) {
732 0           $prop->{stash} = $_[0]
733             } else {
734 0           $stash->{$_[0]};
735             }
736             };
737              
738             sub YATT::Lite::EntNS::entity_mkhidden {
739 0     0 0   my ($this) = shift;
740             \ join "\n", map {
741 0           my $name = $_;
  0            
742             map {
743 0           my $v = $_;
  0            
744 0 0         if (ref $v eq 'HASH') {
    0          
745             map {
746 0           _hidden_input(escape($name."[$_]"), $v->{$_});
  0            
747             } keys %$v;
748             } elsif (ref $v eq 'ARRAY') {
749             map {
750 0           _hidden_input(escape($name."[]"), $_);
  0            
751             } @$v;
752             } else {
753 0           _hidden_input(escape($name), $v);
754             }
755             } $CON->multi_param($name);
756             } @_;
757             };
758              
759             sub _hidden_input {
760 0     0     sprintf(qq||
761             , $_[0], escape($_[1]));
762             }
763              
764             sub YATT::Lite::EntNS::entity_file_rootname {
765 0     0 0   my ($this, $fn) = @_;
766 0   0       $fn //= $CON->file();
767 0           $fn =~ s/\.\w+$//;
768 0           $fn;
769             };
770              
771             #----------------------------------------
772 19     19   160 use YATT::Lite::Breakpoint ();
  19         47  
  19         678  
773             YATT::Lite::Breakpoint::break_load_facade();
774              
775             1;