File Coverage

blib/lib/Data/Annotation/Overlay.pm
Criterion Covered Total %
statement 48 88 54.5
branch 6 20 30.0
condition 2 12 16.6
subroutine 11 15 73.3
pod 7 7 100.0
total 74 142 52.1


line stmt bran cond sub pod time code
1             package Data::Annotation::Overlay;
2 3     3   57 use v5.24;
  3         11  
3 3     3   15 use utf8;
  3         6  
  3         39  
4 3     3   754 use Moo;
  3         10655  
  3         15  
5 3     3   2658 use experimental qw< signatures >;
  3         6  
  3         36  
6 3     3   1213 use Ouch qw< :trytiny_var >;
  3         8221  
  3         24  
7 3     3   421 use Scalar::Util qw< blessed >;
  3         5  
  3         189  
8 3     3   29 use Data::Annotation::Traverse qw< :all >;
  3         5  
  3         474  
9 3     3   685 use namespace::clean;
  3         21268  
  3         23  
10              
11             has under => (is => 'ro', required => 1);
12             has over => (is => 'ro', default => sub { return {} });
13             has traverse_methods => (is => 'ro', default => 1);
14             has strict_blessed => (is => 'ro', default => 0);
15             has method_over_key => (is => 'ro', default => 1);
16             has value_if_missing => (is => 'ro', predicate => 1);
17             has value_if_undef => (is => 'ro', predicate => 1);
18             has cache_existing => (is => 'ro', default => 1);
19              
20 0     0 1 0 sub delete ($self, $path) { $self->set($path, MISSING) }
  0         0  
  0         0  
  0         0  
  0         0  
21              
22 11     11 1 20 sub get ($self, $path) {
  11         16  
  11         17  
  11         16  
23 11 50       32 ouch 400, 'cannot get an undefined path' unless defined($path);
24 11         35 my $crumbs = crumble($path);
25 11         32 my $kpath = kpath($crumbs);
26              
27             # retrieve item, first look in the overlay, then go down
28 11         22 my $retval;
29 11         69 my $over = $self->over;
30 11         27 my $under = $self->under;
31 11         23 my $under_class = blessed($under);
32 11 50 33     49 if (exists($over->{$kpath})) {
    50          
33 0         0 $retval = $over->{$kpath};
34             }
35             elsif (blessed($under) && $under->isa(__PACKAGE__)) {
36 0         0 $retval = $under->get($path); # get from previous layer in stack
37             }
38             else {
39 11         36 $retval = traverse_plain($under, $crumbs, $self->traversal_options);
40 11 50       56 $over->{$kpath} = $retval if $self->cache_existing;
41             }
42              
43 11         31 return $self->return_value_for($retval);
44             }
45              
46             # use traversal options and return value massaging
47 0     0 1 0 sub get_external ($self, $path, $data) {
  0         0  
  0         0  
  0         0  
  0         0  
48 0 0       0 ouch 400, 'cannot get an undefined path' unless defined($path);
49 0         0 my $crumbs = crumble($path);
50 0         0 my $retval = traverse_plain($data, $crumbs, $self->traversal_options);
51 0         0 return $self->return_value_for($retval);
52             }
53              
54 0     0 1 0 sub merged ($self) {
  0         0  
  0         0  
55 0         0 my %over;
56 0         0 my $cursor = $self;
57 0         0 my $any_layer_does_caching = 0;
58 0         0 while ('necessary') {
59 0   0     0 $any_layer_does_caching ||= $cursor->cache_existing;
60 0         0 %over = ($cursor->over->%*, %over);
61 0         0 my $under = $cursor->under;
62 0 0 0     0 last unless blessed($under) && $under->isa(__PACKAGE__);
63 0         0 $cursor = $under;
64             }
65             # now $cursor points to the bottom of the stack
66 0         0 return $self->new(
67             under => $cursor->under,
68             over => \%over,
69             traverse_methods => $cursor->traverse_methods,
70             strict_blessed => $cursor->strict_blessed,
71             method_over_key => $cursor->method_over_key,
72             value_if_missing => $self->value_if_missing,
73             value_if_undef => $self->value_if_undef,
74             cache_existing => $any_layer_does_caching,
75             );
76             }
77              
78 11     11 1 20 sub return_value_for ($self, $retval) {
  11         18  
  11         18  
  11         18  
79 11 50       26 if (means_missing($retval)) {
80 0 0       0 return unless $self->has_value_if_missing;
81 0         0 return $self->value_if_missing;
82             }
83 11 50 33     70 return $retval if defined($retval) || (! $self->has_value_if_undef);
84 0         0 return $self->value_if_undef;
85             }
86              
87 0     0 1 0 sub set ($self, $path, $value) {
  0         0  
  0         0  
  0         0  
  0         0  
88 0 0       0 ouch 400, 'cannot set an undefined path' unless defined($path);
89 0         0 $self->over->{kpath($path)} = $value;
90 0         0 return $self;
91             }
92              
93 11     11 1 45 sub traversal_options ($self) {
  11         21  
  11         15  
94             return (
95 11         66 traverse_methods => $self->traverse_methods,
96             strict_blessed => $self->strict_blessed,
97             method_over_key => $self->method_over_key,
98             );
99             }
100              
101             1;