File Coverage

blib/lib/JIP/DataPath.pm
Criterion Covered Total %
statement 88 92 95.6
branch 34 40 85.0
condition 21 41 51.2
subroutine 17 17 100.0
pod 10 10 100.0
total 170 200 85.0


line stmt bran cond sub pod time code
1             package JIP::DataPath;
2              
3 1     1   89345 use strict;
  1         4  
  1         30  
4 1     1   6 use warnings;
  1         2  
  1         29  
5              
6 1     1   5 use Carp qw(croak);
  1         2  
  1         61  
7 1     1   6 use Exporter qw(import);
  1         2  
  1         37  
8 1     1   5 use English qw(-no_match_vars);
  1         2  
  1         5  
9              
10             our $VERSION = '0.044';
11              
12             our @EXPORT_OK = qw(path);
13              
14             sub path {
15 4     4 1 2989 my ($document) = @ARG;
16              
17 4         10 return __PACKAGE__->new( document => $document );
18             }
19              
20             sub default_value {
21 13     13 1 63 return __PACKAGE__ . '::default_value';
22             }
23              
24             sub is_default_value {
25 9     9 1 4676 my ( $self, $value ) = @ARG;
26              
27 9 100       28 return 0 if !defined $value;
28 8 100       28 return 0 if ref $value;
29 4 100       11 return 0 if $value ne $self->default_value();
30              
31 1         4 return 1;
32             }
33              
34             sub document {
35 67     67 1 7695 my ($self) = @ARG;
36              
37 67         195 return $self->{document};
38             }
39              
40             sub new {
41 21     21 1 62158 my ( $class, %param ) = @ARG;
42              
43             # Mandatory params
44 21 100       64 if ( !exists $param{document} ) {
45 1         174 croak 'Mandatory argument "document" is missing';
46             }
47              
48             return bless(
49             {
50             document => $param{document},
51             },
52 20         86 $class,
53             );
54             }
55              
56             sub get {
57 27     27 1 910 my ( $self, $path_parts, $default_value ) = @ARG;
58              
59 27 100       37 if ( @{$path_parts} == 0 ) {
  27         67  
60 7         14 return $self->document();
61             }
62              
63 20         50 my ( $contains, $context ) = $self->_accessor($path_parts);
64              
65 20 100       66 return $default_value if !$contains;
66              
67 10   50     25 my $last_part = $path_parts->[-1] // q{};
68 10   50     32 my $type = ref $context // q{};
69              
70 10 100 66     59 if ( $type eq 'HASH' && length $last_part ) {
    50 33        
71 8         50 return $context->{$last_part};
72             }
73             elsif ( $type eq 'ARRAY' && $last_part =~ m{^\d+$}x ) {
74 2         13 return $context->[$last_part];
75             }
76              
77 0         0 return $default_value;
78             } ## end sub get
79              
80             sub get_new {
81 5     5 1 20 my ( $self, $path_parts, $default_value ) = @ARG;
82              
83 5 100       8 if ( @{$path_parts} == 0 ) {
  5         16  
84 2         5 return path( $self->document() );
85             }
86              
87 3         8 my ( $contains, $context ) = $self->_accessor($path_parts);
88              
89 3 100       16 return $default_value if !$contains;
90              
91 1   50     6 my $last_part = $path_parts->[-1] // q{};
92 1   50     5 my $type = ref $context // q{};
93              
94 1 50 33     7 if ( $type eq 'HASH' && length $last_part ) {
    0 0        
95 1         3 return path( $context->{$last_part} );
96             }
97             elsif ( $type eq 'ARRAY' && $last_part =~ m{^\d+$}x ) {
98 0         0 return path( $context->[$last_part] );
99             }
100              
101 0         0 return $default_value;
102             } ## end sub get_new
103              
104             sub contains {
105 9     9 1 30 my ( $self, @xargs ) = @ARG;
106              
107 9         24 my ($contains) = $self->_accessor(@xargs);
108              
109 9         69 return $contains;
110             }
111              
112             sub set {
113 9     9 1 3240 my ( $self, $path_parts, $value ) = @ARG;
114              
115 9 100       13 if ( @{$path_parts} == 0 ) {
  9         25  
116 4         12 $self->_set_document($value);
117 4         18 return 1;
118             }
119              
120 5         14 my ( $contains, $context ) = $self->_accessor($path_parts);
121              
122 5 50       12 return 0 if !$contains;
123              
124 5   50     13 my $last_part = $path_parts->[-1] // q{};
125 5   50     14 my $type = ref $context // q{};
126              
127 5 100 66     30 if ( $type eq 'HASH' && length $last_part ) {
    50 33        
128 4         6 $context->{$last_part} = $value;
129 4         14 return 1;
130             }
131             elsif ( $type eq 'ARRAY' && $last_part =~ m{^\d+$}x ) {
132 1         4 $context->[$last_part] = $value;
133 1         5 return 1;
134             }
135              
136 0         0 return 0;
137             } ## end sub set
138              
139             sub perform {
140 5     5 1 8353 my ( $self, $method, $path_parts, @xargs ) = @ARG;
141              
142 5         32 return $self->$method( $path_parts, @xargs );
143             }
144              
145             sub _set_document {
146 4     4   11 my ( $self, $document ) = @ARG;
147              
148 4         5 $self->{document} = $document;
149              
150 4         9 return;
151             }
152              
153             sub _accessor {
154 46     46   8634 my ( $self, $path_parts ) = @ARG;
155              
156 46         92 my $context = $self->document();
157 46         70 my $last_index = $#{$path_parts};
  46         84  
158              
159 46         163 foreach my $part_index ( 0 .. $last_index ) {
160 80         112 my $part = $path_parts->[$part_index];
161 80   50     172 my $type = ref $context // q{};
162 80         118 my $last = $part_index == $last_index;
163              
164 80 100 100     356 if ( $type eq 'HASH' && exists $context->{$part} ) {
    100 66        
      66        
165 49 100       135 return ( 1, $context ) if $last;
166              
167 29         58 $context = $context->{$part};
168             }
169 15         52 elsif ( $type eq 'ARRAY' && $part =~ m{^\d+$}x && @{$context} > $part ) {
170 15 100       43 return ( 1, $context ) if $last;
171              
172 8         19 $context = $context->[$part];
173             }
174             else {
175 16         44 return ( 0, undef );
176             }
177             }
178              
179 3         9 return ( 1, $context );
180             } ## end sub _accessor
181              
182             1;
183              
184             __END__