File Coverage

blib/lib/Config/Registry.pm
Criterion Covered Total %
statement 76 78 97.4
branch 17 24 70.8
condition 6 11 54.5
subroutine 17 18 94.4
pod 4 11 36.3
total 120 142 84.5


line stmt bran cond sub pod time code
1             package Config::Registry;
2             our $VERSION = '0.02';
3 3     3   228096 use strictures 2;
  3         29  
  3         129  
4              
5 3     3   613 use Carp qw( croak );
  3         5  
  3         177  
6 3     3   1394 use MRO::Compat;
  3         5280  
  3         88  
7              
8 3     3   517 use Moo;
  3         11233  
  3         22  
9 3     3   3571 use namespace::clean;
  3         33258  
  3         21  
10              
11             around BUILDARGS => sub{
12             my $orig = shift;
13             my $class = shift;
14              
15             my $args = $class->$orig( @_ );
16             $args = $class->merge_documents( $class->document(), $args );
17             $args = $class->render_document( $args );
18              
19             return $args;
20             };
21              
22             sub BUILD {
23 1     1 0 64 my ($self) = @_;
24              
25 1         3 my $class = ref $self;
26 1 50       2 croak "$class must be published before an instance may be built"
27             if !$class->_get_class_data('is_published');
28              
29 1         8 return;
30             }
31              
32             my %DATA;
33              
34             sub _set_class_data {
35 6     6   14 my ($class, $key, $value) = @_;
36 6   100     45 my $data = $DATA{$class} ||= {};
37 6         14 $data->{$key} = $value;
38 6         11 return;
39             }
40              
41             sub _get_class_data {
42 20     20   39 my ($class, $key) = @_;
43              
44 20         57 my $isas = mro::get_linear_isa( $class );
45              
46 20         43 foreach my $isa (@$isas) {
47 49         67 my $data = $DATA{ $isa };
48 49 100       104 next if !$data;
49 17 100       44 next if !exists $data->{$key};
50 9         29 return $data->{$key};
51             }
52              
53 11         46 return undef;
54             }
55              
56             sub merge_schemas {
57 1     1 0 2 my $class = shift;
58 1         4 return $class->merge( @_ );
59             }
60              
61             sub merge_documents {
62 7     7 0 14 my $class = shift;
63 7         22 return $class->merge( @_ );
64             }
65              
66             sub merge {
67 13     13 0 127 my ($class, $l, $r) = @_;
68              
69 13 100       49 return $r if ref($l) ne 'HASH';
70 10 50       34 return $r if ref($r) ne 'HASH';
71              
72 10         55 $r = { %$r };
73              
74 10         32 foreach my $key (keys %$l) {
75 9 100       29 next if !exists $r->{$key};
76 4         19 $r->{$key} = $class->merge( $l->{$key}, $r->{$key} );
77             }
78              
79 10         59 return { %$l, %$r };
80             }
81              
82             sub render_schema {
83 1     1 0 2 my $class = shift;
84 1         4 return $class->render( @_ );
85             }
86              
87             sub render_document {
88 3     3 0 5 my $class = shift;
89 3         7 return $class->render( @_ );
90             }
91              
92             sub render {
93 4     4 0 6 shift;
94 4         8 return shift;
95             }
96              
97             my %REGISTRIES;
98              
99             sub fetch {
100 0     0 1 0 my ($class) = @_;
101 0   0     0 return $REGISTRIES{ $class } ||= $class->new();
102             }
103              
104             sub schema {
105 1     1 1 9315 my ($class, $extra) = @_;
106              
107 1   50     12 my $schema = $class->_get_class_data('schema') || {};
108 1 50       4 return $schema if !$extra;
109              
110 1 50       2 croak "Cannot change the registry schema after publishing $class"
111             if $class->_get_class_data('is_published');
112              
113 1         5 $schema = $class->merge_schemas( $schema, $extra );
114 1         6 $class->_set_class_data( schema => $schema );
115              
116 1         3 return $schema;
117             }
118              
119             sub document {
120 11     11 1 551 my ($class, $extra) = @_;
121              
122 11   100     36 my $document = $class->_get_class_data('document') || {};
123 11 100       59 return $document if !$extra;
124              
125 4 50       17 croak "Cannot change the registry document after publishing $class"
126             if $class->_get_class_data('is_published');
127              
128 4         19 $document = $class->merge_documents( $document, $extra );
129 4         19 $class->_set_class_data( document => $document );
130              
131 4         28 return $document;
132             }
133              
134             sub publish {
135 1     1 1 8 my ($class) = @_;
136              
137 1 50       3 croak "$class, or an ancestor class of, has already been published"
138             if $class->_get_class_data('is_published');
139              
140 1   50     2 my $schema = $class->_get_class_data('schema') || {};
141              
142 1         5 $schema = $class->render_schema( $schema );
143              
144 1         3 foreach my $key (keys %$schema) {
145 1         2 my $spec = $schema->{$key};
146 1 50       4 $spec = { isa=>$spec } if ref($spec) ne 'HASH';
147              
148 1         5 $spec = {
149             is => 'ro',
150             required => 1,
151             %$spec,
152             };
153              
154             # This is what the has() function does in Moo.pm.
155 1         7 Moo->_constructor_maker_for( $class )
156             ->register_attribute_specs( $key, $spec );
157 1         20206 Moo->_accessor_maker_for( $class )
158             ->generate_method( $class, $key, $spec );
159 1         469 Moo->_maybe_reset_handlemoose( $class );
160             }
161              
162 1         8 $class->_set_class_data( is_published => 1 );
163              
164 1         2 return;
165             }
166              
167             1;
168             __END__