File Coverage

blib/lib/YATT/Lite/Partial.pm
Criterion Covered Total %
statement 75 75 100.0
branch 14 16 87.5
condition n/a
subroutine 16 16 100.0
pod n/a
total 105 107 98.1


line stmt bran cond sub pod time code
1             package YATT::Lite::Partial;
2 14     14   790 use strict;
  14         28  
  14         521  
3 14     14   140 use warnings qw(FATAL all NONFATAL misc);
  14         21  
  14         600  
4 14     14   104 use mro 'c3';
  14         1701  
  14         97  
5              
6             sub Meta () {'YATT::Lite::Partial::Meta'}
7              
8             sub import {
9 56     56   159 my $pack = shift;
10 56         119 my $callpack = caller;
11 56         385 $pack->Meta->define_partial_class($callpack, @_);
12             }
13              
14             package
15             YATT::Lite::Partial::Meta; sub Meta () {__PACKAGE__}
16 14     14   1816 use parent qw/YATT::Lite::MFields/;
  14         969  
  14         93  
17 14         63 use YATT::Lite::MFields qw/cf_requires
18 14     14   883 has_entns/;
  14         25  
19 14     14   74 use YATT::Lite::Util qw/globref lexpand try_invoke fields_hash/;
  14         23  
  14         882  
20 14     14   71 use Carp;
  14         109  
  14         13501  
21              
22             sub Base () {'YATT::Lite::Object'};
23              
24             sub define_partial_class {
25 56     56   185 my ($pack, $callpack, @args) = @_;
26              
27 56         279 mro::set_mro($callpack => 'c3');
28             # $pack->add_isa_to($callpack, $pack->Base);
29              
30 56         303 my Meta $meta = $pack->get_meta($callpack);
31 56         211 my $fields = fields_hash(ref $meta);
32 56         95 my (@task, %define);
33 56         171 while (@args) {
34 112         183 my $key = shift @args;
35 112 100       327 if ($key =~ /^-(.*)/) {
36 19 50       132 my $sub = $meta->can("declare_$1")
37             or croak "Unknown Partial decl: $1";
38 19         81 push @task, [$sub, $meta];
39             } else {
40 93         137 my $value = shift @args;
41 93 100       624 if (my $sub = $meta->can("declare_$key")) {
    100          
42 58         235 $define{$key} = $value;
43             } elsif ($fields->{"cf_$key"}) {
44 34         154 $meta->{"cf_$key"} = $value;
45             } else {
46 1         218 croak "Unknown Partial opt: $key";
47             }
48             }
49             }
50              
51             # These should be called in *this* order.
52 55         125 foreach my $key (qw/parent parents fields/) {
53 165 100       542 my $value = delete $define{$key}
54             or next;
55 58         276 $meta->can("declare_$key")->($meta, $value);
56             }
57             # assert(keys(%define) == 0);
58              
59 55         122 foreach my $task (@task) {
60 19         49 my ($sub, @rest) = @$task;
61 19         62 $sub->(@rest);
62             }
63              
64             # my Meta $meta = $pack->define_fields($callpack, @_);
65 55         174 *{globref($callpack, 'import')} = sub {
66 71     71   389 shift;
67 71         168 my $fullclass = caller;
68 71         250 $meta->export_partial_class_to($fullclass, @_);
69 55         275 };
70             }
71              
72             sub declare_fields {
73 54     54   98 (my Meta $meta, my $value) = @_;
74 54         208 $meta->define_fields($meta->{cf_package}, lexpand($value));
75             }
76              
77             *declare_parent = *declare_parents; *declare_parent = *declare_parents;
78             sub declare_parents {
79 4     4   6 (my Meta $meta, my $value) = @_;
80             $meta->add_isa_to($meta->{cf_package}, lexpand($value))
81 4         13 ->define_fields($meta->{cf_package});
82             }
83              
84             sub declare_Entity {
85 9     9   19 (my Meta $meta) = @_;
86 9         835 require YATT::Lite;
87             $meta->{has_entns} = YATT::Lite->define_Entity
88 9         59 ({}, $meta->{cf_package}, try_invoke($meta->{cf_package}, 'EntNS'));
89             }
90              
91             sub declare_CON {
92 9     9   22 (my Meta $meta) = @_;
93 9         53 require YATT::Lite::Entities;
94 9         65 *{globref($meta->{cf_package}, 'CON')} = YATT::Lite::Entities->symbol_CON;
  9         42  
95             }
96              
97             sub declare_SYS {
98 1     1   3 (my Meta $meta) = @_;
99 1         7 require YATT::Lite::Entities;
100 1         6 *{globref($meta->{cf_package}, 'SYS')} = YATT::Lite::Entities->symbol_SYS;
  1         13  
101             }
102              
103             sub export_partial_class_to {
104 71     71   143 (my Meta $partial, my $fullclass) = @_;
105              
106             # print "# partial $partial->{cf_package} is imported to $fullclass\n";
107              
108 71 100       307 if (my @requires = lexpand($partial->{cf_requires})) {
109 40         93 my @missing = grep {not $fullclass->can($_)} @requires;
  87         1190  
110 40 50       143 croak "User class of Partital '$partial->{cf_package}' must implement: "
111             . join(", ", sort @missing) if @missing;
112             }
113              
114             YATT::Lite::MFields->add_isa_to($fullclass, $partial->{cf_package})
115 71         429 ->define_fields($fullclass);
116              
117 71 100       250 if (my $entns = $partial->{has_entns}) {
118             #print "partial $partial->{cf_package} has EntNS $entns, "
119             # , "injected to $fullclass\n";
120             YATT::Lite::MFields->add_isa_to(YATT::Lite->ensure_entns($fullclass)
121 7         40 , $partial->{has_entns});
122             }
123              
124 71         298 my Meta $full = Meta->get_meta($fullclass);
125              
126 71         225 $full->import_fields_from($partial);
127             }
128              
129             1;