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 20     20   760 use strict;
  20         43  
  20         566  
3 20     20   98 use warnings qw(FATAL all NONFATAL misc);
  20         43  
  20         619  
4 20     20   193 use mro 'c3';
  20         980  
  20         119  
5              
6             sub Meta () {'YATT::Lite::Partial::Meta'}
7              
8             sub import {
9 79     79   246 my $pack = shift;
10 79         205 my $callpack = caller;
11 79         545 $pack->Meta->define_partial_class($callpack, @_);
12             }
13              
14             package
15             YATT::Lite::Partial::Meta; sub Meta () {__PACKAGE__}
16 20     20   2091 use parent qw/YATT::Lite::MFields/;
  20         625  
  20         196  
17 20         98 use YATT::Lite::MFields qw/cf_requires
18 20     20   1522 has_entns/;
  20         62  
19 20     20   135 use YATT::Lite::Util qw/globref lexpand try_invoke fields_hash/;
  20         46  
  20         1091  
20 20     20   115 use Carp;
  20         61  
  20         14160  
21              
22             sub Base () {'YATT::Lite::Object'};
23              
24             sub define_partial_class {
25 79     79   306 my ($pack, $callpack, @args) = @_;
26              
27 79         449 mro::set_mro($callpack => 'c3');
28             # $pack->add_isa_to($callpack, $pack->Base);
29              
30 79         425 my Meta $meta = $pack->get_meta($callpack);
31 79         273 my $fields = fields_hash(ref $meta);
32 79         193 my (@task, %define);
33 79         248 while (@args) {
34 162         370 my $key = shift @args;
35 162 100       501 if ($key =~ /^-(.*)/) {
36 29 50       180 my $sub = $meta->can("declare_$1")
37             or croak "Unknown Partial decl: $1";
38 29         112 push @task, [$sub, $meta];
39             } else {
40 133         237 my $value = shift @args;
41 133 100       793 if (my $sub = $meta->can("declare_$key")) {
    100          
42 81         351 $define{$key} = $value;
43             } elsif ($fields->{"cf_$key"}) {
44 51         234 $meta->{"cf_$key"} = $value;
45             } else {
46 1         189 croak "Unknown Partial opt: $key";
47             }
48             }
49             }
50              
51             # These should be called in *this* order.
52 78         195 foreach my $key (qw/parent parents fields/) {
53 234 100       634 my $value = delete $define{$key}
54             or next;
55 81         457 $meta->can("declare_$key")->($meta, $value);
56             }
57             # assert(keys(%define) == 0);
58              
59 78         192 foreach my $task (@task) {
60 29         85 my ($sub, @rest) = @$task;
61 29         101 $sub->(@rest);
62             }
63              
64             # my Meta $meta = $pack->define_fields($callpack, @_);
65 78         254 *{globref($callpack, 'import')} = sub {
66 106     106   524 shift;
67 106         297 my $fullclass = caller;
68 106         386 $meta->export_partial_class_to($fullclass, @_);
69 78         393 };
70             }
71              
72             sub declare_fields {
73 77     77   188 (my Meta $meta, my $value) = @_;
74 77         309 $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         12 ->define_fields($meta->{cf_package});
82             }
83              
84             sub declare_Entity {
85 14     14   39 (my Meta $meta) = @_;
86 14         681 require YATT::Lite;
87             $meta->{has_entns} = YATT::Lite->define_Entity
88 14         83 ({}, $meta->{cf_package}, try_invoke($meta->{cf_package}, 'EntNS'));
89             }
90              
91             sub declare_CON {
92 14     14   40 (my Meta $meta) = @_;
93 14         75 require YATT::Lite::Entities;
94 14         82 *{globref($meta->{cf_package}, 'CON')} = YATT::Lite::Entities->symbol_CON;
  14         61  
95             }
96              
97             sub declare_SYS {
98 1     1   2 (my Meta $meta) = @_;
99 1         4 require YATT::Lite::Entities;
100 1         4 *{globref($meta->{cf_package}, 'SYS')} = YATT::Lite::Entities->symbol_SYS;
  1         5  
101             }
102              
103             sub export_partial_class_to {
104 106     106   288 (my Meta $partial, my $fullclass) = @_;
105              
106             # print "# partial $partial->{cf_package} is imported to $fullclass\n";
107              
108 106 100       470 if (my @requires = lexpand($partial->{cf_requires})) {
109 63         163 my @missing = grep {not $fullclass->can($_)} @requires;
  138         1714  
110 63 50       240 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 106         569 ->define_fields($fullclass);
116              
117 106 100       369 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 12         63 , $partial->{has_entns});
122             }
123              
124 106         425 my Meta $full = Meta->get_meta($fullclass);
125              
126 106         308 $full->import_fields_from($partial);
127             }
128              
129             1;