File Coverage

blib/lib/Config/Apple/Profile/Payload/Tie/Array.pm
Criterion Covered Total %
statement 70 72 97.2
branch 15 18 83.3
condition n/a
subroutine 20 20 100.0
pod n/a
total 105 110 95.4


line stmt bran cond sub pod time code
1             # This is the code for Config::Apple::Profile::Payload::Tie::Array.
2             # For Copyright, please see the bottom of the file.
3              
4             package Config::Apple::Profile::Payload::Tie::Array;
5              
6 15     15   116 use 5.10.1;
  15         37  
  15         494  
7 15     15   66 use strict;
  15         33  
  15         396  
8 15     15   54 use warnings FATAL => 'all';
  15         17  
  15         634  
9              
10             our $VERSION = '0.87';
11              
12 15     15   64 use Scalar::Util qw(blessed);
  15         21  
  15         712  
13 15     15   6863 use Tie::Array; # Also gives us Tie::StdArray
  15         12578  
  15         8965  
14              
15              
16             =encoding utf8
17              
18             =head1 NAME
19              
20             Config::Apple::Profile::Payload::Tie::Array - Tying class for arrays of things.
21              
22             =head1 DESCRIPTION
23              
24             This class is used to store an array of I. Exactly what I are
25             being stored is specified at the time the tie is made.
26              
27             There are several payload types that contain arrays of things. For example,
28             the root profile has the all-important key C, which is an
29             array of payloads.
30              
31             This class is used by payload classes to represent an array.
32              
33             =cut
34              
35             =head2 "CLASS" METHODS
36              
37             =head3 tie @array, 'Config::Apple::Profile::Payload::Tie::Array', $validator
38              
39             When this class is tied to an array, C will be called, with the class
40             name as the first argument.
41              
42             C<$validator> is a reference to a function that will be able to validate
43             values that are stored to the array. The validator will be passed the value as
44             the only parameter, and an untained value is expected as the return value.
45             If C is returned by the validator, then the value was invalid, and the
46             store attempt will fail.
47              
48             It is suggested that the functions from
49             L be used.
50              
51             If C<$validator> is not a valid coderef then an exception will be thrown.
52              
53             =cut
54              
55             sub TIEARRAY {
56 141     141   216 my ($class, $validator) = @_;
57            
58             # This is what we'll eventually return
59 141         169 my %object;
60            
61             # We'll still have an array, for convenience
62 141         327 $object{array} = [];
63            
64             # We don't accept refs, only scalars
65 141 50       389 if (ref $validator ne 'CODE') {
66 0         0 die "Validator must be a function reference";
67             }
68 141         209 $object{validator} = $validator;
69              
70 141         547 return bless \%object, $class;
71             }
72              
73              
74             =head3 FETCH
75              
76             Works as one would expect with a Perl array. Returns the entry at the specified
77             index. Since methods are in place to prevent storing C, as long as the
78             index is valid at the time of the call, you will get something back.
79              
80             =cut
81              
82             sub FETCH {
83 225     225   55849 my ($self, $index) = @_;
84            
85 225         667 return $self->{array}->[$index];
86             }
87              
88              
89             =head3 STORE
90              
91             Storing items at a specific index is not allowed. This is to help prevent
92             C from appearing in the array. Instead, use C or C.
93              
94             =cut
95              
96             sub STORE {
97 2     2   794 my ($self, $index, $value) = @_;
98 2         19 die "Storing items at specific indexes is not allowed";
99             }
100              
101              
102             =head3 delete
103              
104             Deleting items at a specific index is not allowed. Perl has deprecated this.
105             Instead, use C, C, or C.
106              
107             =cut
108              
109             sub DELETE {
110 2     2   744 my ($self, $index) = @_;
111 2         15 die "Deleting items at specific indexes is not allowed";
112             }
113              
114              
115             =head3 scalar
116              
117             Works as expected, returning the number of items in the array.
118              
119             =cut
120              
121             sub FETCHSIZE {
122 506     506   68266 my ($self) = @_;
123              
124 506         476 return scalar @{$self->{array}};
  506         1890  
125             }
126              
127              
128             =head3 STORESIZE
129              
130             Works almost as expected. Making an array smaller will delete items off of the
131             end of the array. Making the array bigger (that is, presizing) has no effect.
132              
133             =cut
134              
135             sub STORESIZE {
136 2     2   9097 my ($self, $count) = @_;
137            
138 2 100       4 return if ($count >= $self->FETCHSIZE);
139 1         2 $#{$self->{array}} = $count - 1;
  1         7  
140             }
141              
142              
143             =head3 EXTEND
144              
145             If Perl attempts to pre-extend the array, nothing happens.
146              
147             =cut
148              
149             sub EXTEND {
150 1     1   4 my ($self, $count) = @_;
151             }
152              
153              
154             =head3 exists
155              
156             Works as expected for a Perl array: Returns true if the specified index is
157             still valid for the array.
158              
159             =cut
160              
161             sub EXISTS {
162 2     2   796 my ($self, $index) = @_;
163            
164             # We can use the code from Tie::StdArray, instead of rewriting it.
165 2         11 return Tie::StdArray::EXISTS($self->{array}, $index);
166             }
167              
168              
169             =head3 CLEAR
170              
171             Replacing the array with an empty list works to remove all of the entries from
172             the array.
173              
174             =cut
175              
176             sub CLEAR {
177 1     1   20 my ($self) = @_;
178              
179 1         7 $self->{array} = [];
180             }
181              
182              
183             =head3 push
184              
185             Works as expected for a Perl array, with two exceptions:
186              
187             =over 4
188              
189             =item *
190              
191             C is not a valid array item.
192              
193             =item *
194              
195             If this is not an array of objects, then the value will be validated before
196             being added to the array.
197              
198             =back
199              
200             An exception will be thrown if either of the two points above fails.
201              
202             =cut
203              
204             sub PUSH {
205 194     194   20602 my $self = CORE::shift @_;
206            
207             # Run the validation
208 194         388 @_ = $self->_validate(@_);
209            
210             # Let Tie::StdArray do the rest!
211 136         470 return Tie::StdArray::PUSH($self->{array}, @_);
212             }
213              
214              
215             =head3 pop
216              
217             Works as expected for a Perl array.
218              
219             =cut
220              
221             sub POP {
222 75     75   49257 my ($self) = @_;
223 75         243 return Tie::StdArray::POP($self->{array});
224             }
225              
226              
227             =head3 shift
228              
229             Works as expected for a Perl array.
230              
231             =cut
232              
233             sub SHIFT {
234 75     75   48475 my ($self) = @_;
235 75         208 return Tie::StdArray::SHIFT($self->{array});
236             }
237              
238              
239             =head3 unshift
240              
241             Works as expected for a Perl array, with two exceptions:
242              
243             =over 4
244              
245             =item *
246              
247             C is not a valid array item.
248              
249             =item *
250              
251             If this is not an array of objects, then the value will be validated before
252             being added to the array.
253              
254             =back
255              
256             An exception will be thrown if either of the two points above fails.
257             =cut
258              
259             sub UNSHIFT {
260 83     83   20648 my $self = CORE::shift @_;
261            
262             # Run the validation
263 83         188 @_ = $self->_validate(@_);
264            
265             # Let Tie::StdArray do the rest!
266 76         255 return Tie::StdArray::UNSHIFT($self->{array}, @_);
267             }
268              
269              
270             =head3 splice
271              
272             Works as expected for a Perl array, but if you are using C to add
273             entries to the array, take note of these two exceptions:
274              
275             =over 4
276              
277             =item *
278              
279             C is not a valid array item.
280              
281             =item *
282              
283             If this is not an array of objects, then the value will be validated before
284             being added to the array.
285              
286             =back
287              
288             An exception will be thrown if either of the two points above fails.
289              
290             =cut
291              
292             sub SPLICE {
293             # We can't use Tie::Array or Tie::StdArray for this, because it expects
294             # something we can't easily give. We'll have to do it ourselves.
295 6     6   107 my $self = CORE::shift @_;
296            
297             # We'll need the current array size for reference
298 6         9 my $size = $self->FETCHSIZE;
299            
300             # Get the offset from the parameters, or default to 0
301             # If offset is negative, make it relative to the array end
302 6 100       15 my $offset = scalar @_ ? shift @_ : 0;
303 6 100       12 $offset += $size if $offset < 0;
304            
305             # Get the length from the parameters. If length wasn't provided, then
306             # we're grabbing all of the array starting at $offset
307 6 100       8 my $length = scalar @_ ? shift @_ : $size - $offset;
308            
309             # If there are any parameters left, then they are items to insert.
310             # Validate them before continuing.
311 6 50       13 if (scalar @_ >= 0) {
312 6         10 @_ = $self->_validate(@_);
313             }
314            
315             # Do the splice and return.
316 6         7 return splice(@{$self->{array}}, $offset , $length, @_);
  6         44  
317             }
318              
319              
320             =head3 _validate
321              
322             Given a list of items, each one will be validated, and the validated list will
323             be returned.
324              
325             An exception will be thrown if any of the list items is undef, or if any of
326             the list items fails validation, or if the caller is not expecting an array.
327              
328             =cut
329              
330             sub _validate {
331 283     283   323 my $self = CORE::shift @_;
332            
333             # If we are not returning an array, then die now
334 283 50       606 if (!wantarray) {
335 0         0 die "_validate expects to return an array";
336             }
337            
338             # We can't use a foreach loop, because our items might be Readonly,
339             # and the way Perl does aliasing means assigning to the foreach $item
340             # triggers a "modification of a read-only value" error.
341 283         284 my @validated_array;
342            
343             # Go through each item, making sure it is valid
344 283         656 for (my $i = 0; $i < scalar @_; $i++) {
345 314         660 my $item = $_[$i];
346            
347             # Undef is not a valid value
348 314 100       825 if (!defined $item) {
349 6         62 die "Adding undef items is not allowed";
350             }
351            
352             # Call the validation routine
353 308         782 my $validated_item = $self->{validator}->($item);
354            
355             # If $item suddenly became undef, it was invalid
356 308 100       1292 if (!defined $validated_item) {
357 59         572 die "Attempting to insert invalid item";
358             }
359            
360 249         852 $validated_array[$i] = $validated_item;
361             } # Done checking each item
362            
363 218         539 return @validated_array;
364             }
365              
366              
367             =head1 ACKNOWLEDGEMENTS
368              
369             Refer to L for acknowledgements.
370              
371             =head1 AUTHOR
372              
373             A. Karl Kornel, C<< >>
374              
375             =head1 COPYRIGHT AND LICENSE
376              
377             Copyright © 2014 A. Karl Kornel.
378              
379             This program is free software; you can redistribute it and/or modify it
380             under the terms of either: the GNU General Public License as published
381             by the Free Software Foundation; or the Artistic License.
382              
383             See L for more information.
384              
385             =cut
386              
387             1;