File Coverage

blib/lib/YATT/Lite/Types.pm
Criterion Covered Total %
statement 101 108 93.5
branch 22 32 68.7
condition 9 11 81.8
subroutine 16 16 100.0
pod 0 6 0.0
total 148 173 85.5


line stmt bran cond sub pod time code
1             package YATT::Lite::Types;
2 23     23   1713 use strict;
  23         54  
  23         710  
3 23     23   115 use warnings qw(FATAL all NONFATAL misc);
  23         45  
  23         1889  
4 23     23   260 use parent qw(YATT::Lite::Object);
  23         2467  
  23         199  
5 23     23   1347 use Carp;
  23         51  
  23         2275  
6             require YATT::Lite::Inc;
7              
8             sub Desc () {'YATT::Lite::Types::TypeDesc'}
9             {
10             package YATT::Lite::Types::TypeDesc; sub Desc () {__PACKAGE__}
11 23     23   134 use parent qw(YATT::Lite::Object);
  23         50  
  23         104  
12             BEGIN {
13 23     23   1826 our %FIELDS = map {$_ => 1}
  253         1957  
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 128     128   221 my Desc $self = shift;
21 128         444 join '::', $self->{cf_ns}, $self->{cf_name};
22             }
23             }
24              
25 23         21733 use YATT::Lite::Util qw(globref look_for_globref lexpand ckeval pkg2pm
26             define_const
27 23     23   151 );
  23         46  
28              
29             sub import {
30 71     71   204 my $pack = shift;
31 71         185 my $callpack = caller;
32 71         413 $pack->buildns($callpack, @_)
33             }
34              
35             sub create {
36 71     71 0 142 my $pack = shift;
37 71         142 my $callpack = shift;
38 71         743 my Desc $root = $pack->Desc->new(ns => $callpack);
39 71   100     473 while (@_ >= 2 and not ref $_[0]) {
40 2         8 $root->configure(splice @_, 0, 2);
41             }
42 71 50       505 wantarray ? ($root, $pack->parse_desc($root, @_)) : $root;
43             }
44              
45             sub buildns {
46 71     71 0 311 (my Desc $root, my @desc) = shift->create(@_);
47 71         228 my $debug = $ENV{DEBUG_YATT_TYPES};
48 71         154 my (@script, @task);
49 71         148 my $export_ok = do {
50 71         246 my $sym = globref($$root{cf_ns}, 'EXPORT_OK');
51 71   100     165 *{$sym}{ARRAY} // (*$sym = []);
  71         583  
52             };
53 71 100       958 if (my $sub = $$root{cf_ns}->can('export_ok')) {
54 19         96 push @$export_ok, $sub->($$root{cf_ns});
55             }
56             {
57 71         158 my $sym = globref($$root{cf_ns}, 'export_ok');
  71         254  
58 71 50   19   151 *$sym = sub { @$export_ok } unless *{$sym}{CODE};
  19         92  
  71         522  
59             }
60 71         203 foreach my Desc $obj (@desc) {
61 239         546 push @$export_ok, $obj->{cf_name};
62 239         702 $obj->{fullname} = join '::', $$root{cf_ns}, $obj->{cf_name};
63 239         750 $INC{pkg2pm($obj->{fullname})} = 1; # To make require happy.
64 239         690 push @script, qq|package $obj->{fullname};|;
65 239         493 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 239   100     994 || '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 239         1019 push @script, sprintf q|use parent qw(%s);|, $base;
74 239         467 push @script, sprintf q|use YATT::Lite::MFields %s;|, do {
75 239 100       581 if ($obj->{cf_fields}) {
76 188         312 sprintf(q|qw(%s)|, join " ", @{$obj->{cf_fields}});
  188         894  
77             } else {
78             # To avoid generating 'use YATT::Lite::MFields qw()';
79 51         157 '';
80             }
81             };
82             push @script, sprintf q|use overload qw(%s);|
83 239 50       692 , join " ", @{$obj->{cf_overloads}} if $obj->{cf_overloads};
  0         0  
84 239 100       580 push @script, $obj->{cf_eval} if $obj->{cf_eval};
85 239         413 push @script, "\n";
86              
87 239         793 push @task, [\&add_alias, $$root{cf_ns}, $obj->{cf_name}, $obj->{cf_name}];
88 239         842 foreach my $alias (lexpand($obj->{cf_alias})) {
89 53         179 push @task, [\&add_alias, $$root{cf_ns}, $alias, $obj->{cf_name}];
90 53         131 push @$export_ok, $alias;
91             }
92 239         755 foreach my $spec (lexpand($obj->{cf_constants})) {
93 86         332 push @task, [\&add_const, $obj->{fullname}, @$spec];
94             }
95             }
96 71         402 my $script = join(" ", @script, "; 1");
97 71 50       231 print $script, "\n" if $debug;
98 71         296 ckeval($script);
99 71         304 foreach my $task (@task) {
100 378         971 my ($sub, @args) = @$task;
101 378         787 $sub->(@args);
102             }
103 71 100       300 if ($root->{cf_export_default}) {
104 1         3 my $export = do {
105 1         4 my $sym = globref($$root{cf_ns}, 'EXPORT');
106 1   50     3 *{$sym}{ARRAY} // (*$sym = []);
  1         9  
107             };
108 1         5 @$export = @$export_ok;
109             }
110 71         186 foreach my Desc $obj (@desc) {
111 239         899 my $sym = look_for_globref($obj->{fullname}, 'FIELDS');
112 239 50 50     718 if ($sym and my $fields = *{$sym}{HASH}) {
  239 0       839  
113 239 50       52581 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 292     292 0 590 my ($pack, $alias, $name) = @_;
124 292         920 add_const($pack, $alias, join('::', $pack, $name));
125             }
126              
127             sub add_const {
128 378     378 0 722 my ($pack, $alias, $const) = @_;
129 378         944 define_const(globref($pack, $alias), $const);
130             }
131              
132             sub safe_invoke {
133 73     73 0 240 my ($obj, $method) = splice @_, 0, 2;
134 73 100       913 my $sub = $obj->can($method)
135             or return;
136 4         22 $sub->($obj, @_);
137             }
138              
139             sub parse_desc {
140 310     310 0 872 (my $pack, my Desc $parent) = splice @_, 0, 2;
141 310         500 my (@desc);
142 310         968 while (@_) {
143 618 50       2055 unless (defined (my $item = shift)) {
    100          
    50          
144 0         0 croak "Undefined type desc!";
145 0         0 } elsif (ref $item) {
146 239 100       778 my @base = (base => $parent->pkg) if $parent->{cf_name};
147             push @desc, my Desc $sub = $pack->Desc->new
148 239         1131 (name => shift @$item, ns => $parent->{cf_ns}, @base);
149 239         905 push @desc, $pack->parse_desc($sub, @$item);
150 0         0 } elsif (@_) {
151 379         1336 $item =~ s/^-//;
152 379         1166 $parent->configure($item, shift);
153             } else {
154 0         0 croak "Missing parameter for type desc $item";
155             }
156             }
157 310         1033 @desc;
158             }
159              
160             1;
161              
162             __END__