File Coverage

blib/lib/Catmandu/Fix/Bind/visitor.pm
Criterion Covered Total %
statement 39 45 86.6
branch 10 16 62.5
condition n/a
subroutine 7 8 87.5
pod 0 4 0.0
total 56 73 76.7


line stmt bran cond sub pod time code
1             package Catmandu::Fix::Bind::visitor;
2              
3 1     1   1158 use Catmandu::Sane;
  1         3  
  1         9  
4              
5             our $VERSION = '1.2020';
6              
7 1     1   8 use Moo;
  1         2  
  1         6  
8 1     1   400 use Catmandu::Util;
  1         3  
  1         50  
9 1     1   8 use namespace::clean;
  1         4  
  1         31  
10              
11             with 'Catmandu::Fix::Bind', 'Catmandu::Fix::Bind::Group';
12              
13             has path => (is => 'ro');
14              
15             sub unit {
16 18     18 0 40 my ($self, $data) = @_;
17              
18 18 50       61 if (defined $self->path) {
19 0         0 return Catmandu::Util::data_at($self->path, $data);
20             }
21             else {
22 18         298 return $data;
23             }
24             }
25              
26             sub bind {
27             my ($self, $mvar, $func) = @_;
28              
29             if (Catmandu::Util::is_array_ref($mvar)) {
30             return $self->bind_array($mvar, $func, '');
31             }
32             elsif (Catmandu::Util::is_hash_ref($mvar)) {
33             return $self->bind_hash($mvar, $func, '');
34             }
35             else {
36             return $self->bind_hash($mvar, $func, '');
37             }
38             }
39              
40             sub bind_scalar {
41 0     0 0 0 my ($self, $mvar, $func, $parent) = @_;
42              
43 0         0 return $func->({'key' => $parent, 'scalar' => $mvar})->{'scalar'};
44             }
45              
46             sub bind_array {
47 1     1 0 4 my ($self, $mvar, $func, $parent) = @_;
48              
49 1         20 my $result = $func->({'key' => $parent, 'array' => $mvar});
50              
51 1         3 my $new_var = [];
52              
53 1         6 for (my $i = 0; $i < @$mvar; $i++) {
54 2         8 my $item = $mvar->[$i];
55 2 50       11 if (Catmandu::Util::is_array_ref($item)) {
    50          
56 0         0 my ($newkey, $newvalue) = $self->bind_array($item, $func, $i);
57 0         0 $mvar->[$i] = $newvalue;
58             }
59             elsif (Catmandu::Util::is_hash_ref($item)) {
60 2         7 my ($newkey, $newvalue) = $self->bind_hash($item, $func, $i);
61 2         8 $mvar->[$i] = $newvalue;
62             }
63             else {
64             $mvar->[$i]
65 0         0 = $func->({'key' => $i, 'scalar' => $item})->{'scalar'};
66             }
67             }
68              
69 1         5 return ($result->{key}, $result->{array});
70             }
71              
72             sub bind_hash {
73 25     25 0 50 my ($self, $mvar, $func, $parent) = @_;
74              
75 25         455 my $result = $func->({'key' => $parent, 'hash' => $mvar});
76              
77 25         87 for my $key (keys %$mvar) {
78 53         96 my $item = $mvar->{$key};
79              
80 53 100       150 if (Catmandu::Util::is_array_ref($item)) {
    100          
81              
82             # Keys can update themselves
83 1         5 my ($newkey, $newvalue) = $self->bind_array($item, $func, $key);
84 1         3 $mvar->{$newkey} = $newvalue;
85 1 50       5 delete $mvar->{$key} if ($newkey ne $key);
86             }
87             elsif (Catmandu::Util::is_hash_ref($item)) {
88              
89             # Keys can update themselves
90 5         15 my ($newkey, $newvalue) = $self->bind_hash($item, $func, $key);
91 5         10 $mvar->{$newkey} = $newvalue;
92 5 50       14 delete $mvar->{$key} if ($newkey ne $key);
93             }
94             else {
95             # Keys can update themselves
96 47         850 my $result = $func->({'key' => $key, 'scalar' => $item});
97 47         109 $mvar->{$result->{'key'}} = $result->{'scalar'};
98 47 50       160 delete $mvar->{$key} if ($result->{'key'} ne $key);
99             }
100             }
101              
102 25         93 return ($result->{key}, $result->{hash});
103             }
104              
105             1;
106              
107             __END__
108              
109             =pod
110              
111             =head1 NAME
112              
113             Catmandu::Fix::Bind::visitor - a binder that computes Fix-es for every element in record
114              
115             =head1 SYNOPSIS
116              
117             # If data is like:
118              
119             numbers:
120             - one
121             - two
122             - three
123             person:
124             name: jennie
125             age: 44
126             color:
127             - green
128             - purple
129             - brown
130             - more:
131             foo: bar
132              
133             do visitor()
134             upcase(scalar) # upcase every scalar value in the record
135             end
136              
137             # will produce
138              
139             numbers:
140             - ONE
141             - TWO
142             - THREE
143             person:
144             name: JENNIE
145             age: 44
146             color:
147             - GREEN
148             - PURPLE
149             - BROWN
150             - more:
151             foo: BAR
152              
153             do visitor()
154             # upcase all the 'name' fields in the record
155             if all_match(key,name)
156             upcase(scalar)
157             end
158             end
159              
160             do visitor()
161             # upcase all the field names in the record
162             upcase(key)
163             end
164              
165             =head1 DESCRIPTION
166              
167             The visitor binder will iterate over all the elements in a record and perform fixes on them.
168              
169             Special node names are available to process every visited element:
170              
171             =over 4
172              
173             =item scalar
174              
175             Process a Fix on every scalar value. E.g.
176              
177             upcase(scalar)
178             replace_all(scalar,'$','tested')
179              
180             =item array
181              
182             Process a Fix on every array value. E.g.
183              
184             sort_field(array)
185              
186             Values need to be put in the 'array' field to be available for fixes. The scope of
187             the array is limited to the array visited.
188              
189             =item hash
190              
191             Process a Fix on every hash value. E.g.
192              
193             copy_field(hash.age,hash.age2)
194              
195             Values need to be put in the 'hash' field to be available for fixes. The scope of
196             the hash is limited to the hash visited.
197              
198             =item key
199              
200             Provides access to the key on which the scalar,array or hash value is found. Eg.
201              
202             # Upcase all 'name' fields in the record
203             if all_match(key,name)
204             upcase(scalar)
205             end
206              
207             =back
208              
209             =head1 CONFIGURATION
210              
211             =head2 path
212              
213             A path in the data to visit:
214              
215             # Visit any field
216             do visitor()
217             ...
218             end
219              
220             # Visit only the fields at my.deep.field
221             do visitor(path: my.deep.field)
222             ...
223             end
224              
225             =head1 SEE ALSO
226              
227             L<Catmandu::Fix::Bind>
228              
229             =cut