File Coverage

blib/lib/YATT/Lite/Types.pm
Criterion Covered Total %
statement 100 106 94.3
branch 21 32 65.6
condition 9 11 81.8
subroutine 16 16 100.0
pod 0 6 0.0
total 146 171 85.3


line stmt bran cond sub pod time code
1             package YATT::Lite::Types;
2 15     15   2030 use strict;
  15         26  
  15         440  
3 15     15   75 use warnings qw(FATAL all NONFATAL misc);
  15         26  
  15         580  
4 15     15   147 use parent qw(YATT::Lite::Object);
  15         1977  
  15         105  
5 15     15   797 use Carp;
  15         26  
  15         1804  
6             require YATT::Lite::Inc;
7              
8             sub Desc () {'YATT::Lite::Types::TypeDesc'}
9             {
10             package YATT::Lite::Types::TypeDesc; sub Desc () {__PACKAGE__}
11 15     15   970 use parent qw(YATT::Lite::Object);
  15         27  
  15         68  
12             BEGIN {
13 15     15   1312 our %FIELDS = map {$_ => 1}
  165         1442  
14             qw/cf_name cf_ns cf_fields cf_overloads cf_alias cf_base cf_eval
15             fullname
16             cf_no_require
17             cf_constants cf_export_default/
18             }
19             sub pkg {
20 82     82   160 my Desc $self = shift;
21 82         302 join '::', $self->{cf_ns}, $self->{cf_name};
22             }
23             }
24              
25 15         20234 use YATT::Lite::Util qw(globref look_for_globref lexpand ckeval pkg2pm
26             define_const
27 15     15   78 );
  15         34  
28              
29             sub import {
30 43     43   132 my $pack = shift;
31 43         95 my $callpack = caller;
32 43         172 $pack->buildns($callpack, @_)
33             }
34              
35             sub create {
36 43     43 0 76 my $pack = shift;
37 43         69 my $callpack = shift;
38 43         472 my Desc $root = $pack->Desc->new(ns => $callpack);
39 43   100     277 while (@_ >= 2 and not ref $_[0]) {
40 2         16 $root->configure(splice @_, 0, 2);
41             }
42 43 50       254 wantarray ? ($root, $pack->parse_desc($root, @_)) : $root;
43             }
44              
45             sub buildns {
46 43     43 0 170 (my Desc $root, my @desc) = shift->create(@_);
47 43         123 my $debug = $ENV{DEBUG_YATT_TYPES};
48 43         64 my (@script, @task);
49 43         71 my $export_ok = do {
50 43         161 my $sym = globref($$root{cf_ns}, 'EXPORT_OK');
51 43   100     77 *{$sym}{ARRAY} // (*$sym = []);
  43         339  
52             };
53 43 100       647 if (my $sub = $$root{cf_ns}->can('export_ok')) {
54 11         50 push @$export_ok, $sub->($$root{cf_ns});
55             }
56             {
57 43         83 my $sym = globref($$root{cf_ns}, 'export_ok');
  43         159  
58 43 50   11   68 *$sym = sub { @$export_ok } unless *{$sym}{CODE};
  11         51  
  43         433  
59             }
60 43         119 foreach my Desc $obj (@desc) {
61 151         326 push @$export_ok, $obj->{cf_name};
62 151         471 $obj->{fullname} = join '::', $$root{cf_ns}, $obj->{cf_name};
63 151         525 $INC{pkg2pm($obj->{fullname})} = 1; # To make require happy.
64 151         458 push @script, qq|package $obj->{fullname};|;
65 151         246 push @script, q|use YATT::Lite::Inc;|;
66             my $base = $obj->{cf_base} || $root->{cf_base}
67             || safe_invoke($$root{cf_ns}, $obj->{cf_name})
68 151   100     653 || 'YATT::Lite::Object';
69             #
70             # I finally found base::has_fields() is broken
71             # so there is no merit for fields mania to use base.pm over parent.pm.
72             #
73 151         555 push @script, sprintf q|use parent qw(%s);|, $base;
74 151         236 push @script, sprintf q|use YATT::Lite::MFields %s;|, do {
75 151 100       349 if ($obj->{cf_fields}) {
76 118         165 sprintf(q|qw(%s)|, join " ", @{$obj->{cf_fields}});
  118         727  
77             } else {
78             # To avoid generating 'use YATT::Lite::MFields qw()';
79 33         107 '';
80             }
81             };
82             push @script, sprintf q|use overload qw(%s);|
83 151 50       412 , join " ", @{$obj->{cf_overloads}} if $obj->{cf_overloads};
  0         0  
84 151 100       358 push @script, $obj->{cf_eval} if $obj->{cf_eval};
85 151         239 push @script, "\n";
86              
87 151         521 push @task, [\&add_alias, $$root{cf_ns}, $obj->{cf_name}, $obj->{cf_name}];
88 151         618 foreach my $alias (lexpand($obj->{cf_alias})) {
89 35         140 push @task, [\&add_alias, $$root{cf_ns}, $alias, $obj->{cf_name}];
90 35         109 push @$export_ok, $alias;
91             }
92 151         600 foreach my $spec (lexpand($obj->{cf_constants})) {
93 33         185 push @task, [\&add_const, $obj->{fullname}, @$spec];
94             }
95             }
96 43         293 my $script = join(" ", @script, "; 1");
97 43 50       125 print $script, "\n" if $debug;
98 43         173 ckeval($script);
99 43         113 foreach my $task (@task) {
100 219         611 my ($sub, @args) = @$task;
101 219         516 $sub->(@args);
102             }
103 43 100       165 if ($root->{cf_export_default}) {
104 1         2 my $export = do {
105 1         6 my $sym = globref($$root{cf_ns}, 'EXPORT');
106 1   50     4 *{$sym}{ARRAY} // (*$sym = []);
  1         12  
107             };
108 1         5 @$export = @$export_ok;
109             }
110 43         114 foreach my Desc $obj (@desc) {
111 151         466 my $sym = look_for_globref($obj->{fullname}, 'FIELDS');
112 151 50 50     426 if ($sym and my $fields = *{$sym}{HASH}) {
  151 0       555  
113 151 50       43451 print "Fields in type $obj->{fullname}: "
114             , join(" ", sort keys %$fields), "\n" if $debug;
115             } elsif ($obj->{cf_fields}) {
116             croak "Failed to define type fields for '$obj->{fullname}': "
117 0         0 . join(" ", @{$obj->{cf_fields}});
  0         0  
118             }
119             }
120             }
121              
122             sub add_alias {
123 186     186 0 322 my ($pack, $alias, $name) = @_;
124 186         689 add_const($pack, $alias, join('::', $pack, $name));
125             }
126              
127             sub add_const {
128 219     219 0 347 my ($pack, $alias, $const) = @_;
129 219         544 define_const(globref($pack, $alias), $const);
130             }
131              
132             sub safe_invoke {
133 43     43 0 125 my ($obj, $method) = splice @_, 0, 2;
134 43 50       642 my $sub = $obj->can($method)
135             or return;
136 0         0 $sub->($obj, @_);
137             }
138              
139             sub parse_desc {
140 194     194 0 403 (my $pack, my Desc $parent) = splice @_, 0, 2;
141 194         247 my (@desc);
142 194         531 while (@_) {
143 371 50       1290 unless (defined (my $item = shift)) {
    100          
    50          
144 0         0 croak "Undefined type desc!";
145             } elsif (ref $item) {
146 151 100       507 my @base = (base => $parent->pkg) if $parent->{cf_name};
147             push @desc, my Desc $sub = $pack->Desc->new
148 151         890 (name => shift @$item, ns => $parent->{cf_ns}, @base);
149 151         562 push @desc, $pack->parse_desc($sub, @$item);
150             } elsif (@_) {
151 220         650 $item =~ s/^-//;
152 220         682 $parent->configure($item, shift);
153             } else {
154 0         0 croak "Missing parameter for type desc $item";
155             }
156             }
157 194         682 @desc;
158             }
159              
160             1;
161              
162             __END__