File Coverage

blib/lib/Config/Apple/Profile/Payload/Tie/Array.pm
Criterion Covered Total %
statement 81 88 92.0
branch 27 36 75.0
condition 1 3 33.3
subroutine 22 22 100.0
pod n/a
total 131 149 87.9


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