File Coverage

blib/lib/JIP/DataPath.pm
Criterion Covered Total %
statement 82 86 95.3
branch 28 34 82.3
condition 21 41 51.2
subroutine 15 15 100.0
pod 8 8 100.0
total 154 184 83.7


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