File Coverage

blib/lib/Class/MakeMethods/Standard/Array.pm
Criterion Covered Total %
statement 91 115 79.1
branch 31 50 62.0
condition 18 36 50.0
subroutine 15 15 100.0
pod 5 5 100.0
total 160 221 72.4


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Class::MakeMethods::Standard::Array - Methods for Array objects
4              
5             =head1 SYNOPSIS
6              
7             package MyObject;
8             use Class::MakeMethods::Standard::Array (
9             new => 'new',
10             scalar => [ 'foo', 'bar' ],
11             array => 'my_list',
12             hash => 'my_index',
13             );
14             ...
15            
16             my $obj = MyObject->new( foo => 'Foozle' );
17             print $obj->foo();
18            
19             $obj->bar('Barbados');
20             print $obj->bar();
21            
22             $obj->my_list(0 => 'Foozle', 1 => 'Bang!');
23             print $obj->my_list(1);
24            
25             $obj->my_index('broccoli' => 'Blah!', 'foo' => 'Fiddle');
26             print $obj->my_index('foo');
27              
28             =head1 DESCRIPTION
29              
30             The Standard::Array suclass of MakeMethods provides a basic
31             constructor and accessors for blessed-array object instances.
32              
33             =head2 Calling Conventions
34              
35             When you C this package, the method names you provide
36             as arguments cause subroutines to be generated and installed in
37             your module.
38              
39             See L for more information.
40              
41             =head2 Declaration Syntax
42              
43             To declare methods, pass in pairs of a method-type name followed
44             by one or more method names.
45              
46             Valid method-type names for this package are listed in L<"METHOD
47             GENERATOR TYPES">.
48              
49             See L and L for more information.
50              
51             =cut
52              
53             package Class::MakeMethods::Standard::Array;
54              
55             $VERSION = 1.000;
56 2     2   46 use strict;
  2         5  
  2         81  
57 2     2   532 use Class::MakeMethods::Standard '-isasubclass';
  2         3  
  2         20  
58 2     2   642 use Class::MakeMethods::Utility::ArraySplicer 'array_splicer';
  2         5  
  2         15  
59              
60             ########################################################################
61              
62             =head2 Positional Accessors and %FIELDS
63              
64             Each accessor method is assigned the next available array index at
65             which to store its value.
66              
67             The mapping between method names and array positions is stored in
68             a hash named %FIELDS in the declaring package. When a package
69             declares its first positional accessor, its %FIELDS are initialized
70             by searching its inheritance tree.
71              
72             B: Subclassing packages that use positional accessors is
73             somewhat fragile, since you may end up with two distinct methods assigned to the same position. Specific cases to avoid are:
74              
75             =over 4
76              
77             =item *
78              
79             If you inherit from more than one class with positional accessors,
80             the positions used by the two sets of methods will overlap.
81              
82             =item *
83              
84             If your superclass adds additional positional accessors after you
85             declare your first, they will overlap yours.
86              
87             =back
88              
89             =cut
90              
91             sub _array_index {
92 8     8   10 my $class = shift;
93 8         9 my $name = shift;
94 2     2   8 no strict;
  2         2  
  2         2377  
95 8         27 local $^W = 0;
96 8 100       10 if ( ! scalar %{$class . "::FIELDS"} ) {
  8         47  
97 2         2 my @classes = @{$class . "::ISA"};
  2         12  
98 2         2 my @fields;
99 2         13 while ( @classes ) {
100 0         0 my $superclass = shift @classes;
101 0 0       0 if ( scalar %{$superclass . "::FIELDS"} ) {
  0         0  
102 0         0 push @fields, %{$superclass . "::FIELDS"};
  0         0  
103             } else {
104 0         0 unshift @classes, @{$superclass . "::ISA"}
  0         0  
105             }
106             }
107 2         4 %{$class . "::FIELDS"} = @fields
  2         8  
108             }
109 8         11 my $field_hash = \%{$class . "::FIELDS"};
  8         55  
110 8 50       79 $field_hash->{$name} or $field_hash->{$name} = scalar keys %$field_hash
111             }
112              
113             ########################################################################
114              
115             =head1 METHOD GENERATOR TYPES
116              
117             =head2 new - Constructor
118              
119             For each method name passed, returns a subroutine with the following characteristics:
120              
121             =over 4
122              
123             =item *
124              
125             Has a reference to a sample item to copy. This defaults to a reference to an empty array, but you may override this with the C<'defaults' => I> method parameter.
126              
127             =item *
128              
129             If called as a class method, makes a new array containing values from the sample item, and blesses it into that class.
130              
131             =item *
132              
133             If called on an array-based instance, makes a copy of it and blesses the copy into the same class as the original instance.
134              
135             =item *
136              
137             If passed a list of method-value pairs, calls each named method with the associated value as an argument.
138              
139             =item *
140              
141             Returns the new instance.
142              
143             =back
144              
145             Sample declaration and usage:
146              
147             package MyObject;
148             use Class::MakeMethods::Standard::Array (
149             new => 'new',
150             );
151             ...
152            
153             # Bare constructor
154             my $empty = MyObject->new();
155            
156             # Constructor with initial sequence of method calls
157             my $obj = MyObject->new( foo => 'Foozle', bar => 'Barbados' );
158            
159             # Copy with overriding sequence of method calls
160             my $copy = $obj->new( bar => 'Bob' );
161              
162             =cut
163              
164             sub new {
165 2     2 1 5 my $class = shift;
166 2         5 map {
167 2         17 my $name = $_->{name};
168 2   50     11 my $defaults = $_->{defaults} || [];
169             $name => sub {
170 2     2   799 my $callee = shift;
171 2 50       11 my $self = ref($callee) ? bless( [@$callee], ref($callee) )
172             : bless( [@$defaults], $callee );
173 2         9 while ( scalar @_ ) {
174 0         0 my $method = shift;
175 0         0 $self->$method( shift );
176             }
177 2         6 return $self;
178             }
179 2         18 } $class->_get_declarations(@_)
180             }
181              
182             ########################################################################
183              
184             =head2 scalar - Instance Accessor
185              
186             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
187              
188             =over 4
189              
190             =item *
191              
192             Must be called on an array-based instance.
193              
194             =item *
195              
196             Determines the array position associated with the method name, and uses that as an index into each instance to access the related value. This defaults to the next available slot in %FIELDS, but you may override this with the C<'array_index' => I> method parameter, or by pre-filling the contents of %FIELDS.
197              
198             =item *
199              
200             If called without any arguments returns the current value (or undef).
201              
202             =item *
203              
204             If called with an argument, stores that as the value, and returns it,
205              
206             =back
207              
208             Sample declaration and usage:
209              
210             package MyObject;
211             use Class::MakeMethods::Standard::Array (
212             scalar => 'foo',
213             );
214             ...
215            
216             # Store value
217             $obj->foo('Foozle');
218            
219             # Retrieve value
220             print $obj->foo;
221              
222             =cut
223              
224             sub scalar {
225 2     2 1 3 my $class = shift;
226 2         4 map {
227 2         10 my $name = $_->{name};
228 2   33     21 my $index = $_->{array_index} ||
229             _array_index( $class->_context('TargetClass'), $name );
230             $name => sub {
231 4     4   14 my $self = shift;
232 4 100       11 if ( scalar @_ ) {
233 2         18 $self->[$index] = shift;
234             } else {
235 2         9 $self->[$index];
236             }
237             }
238 2         14 } $class->_get_declarations(@_)
239             }
240              
241             ########################################################################
242              
243             =head2 array - Instance Ref Accessor
244              
245             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
246              
247             =over 4
248              
249             =item *
250              
251             Must be called on an array-based instance.
252              
253             =item *
254              
255             Determines the array position associated with the method name, and uses that as an index into each instance to access the related value. This defaults to the next available slot in %FIELDS, but you may override this with the C<'array_index' => I> method parameter, or by pre-filling the contents of %FIELDS.
256              
257             =item *
258              
259             The value for each instance will be a reference to an array (or undef).
260              
261             =item *
262              
263             If called without any arguments, returns the current array-ref value (or undef).
264              
265             =item *
266              
267             If called with a single non-ref argument, uses that argument as an index to retrieve from the referenced array, and returns that value (or undef).
268              
269             =item *
270              
271             If called with a single array ref argument, uses that list to return a slice of the referenced array.
272              
273             =item *
274              
275             If called with a list of argument pairs, each with a non-ref index and an associated value, stores the value at the given index in the referenced array. If the instance's value was previously undefined, a new array is autovivified. The current value in each position will be overwritten, and later arguments with the same index will override earlier ones. Returns the current array-ref value.
276              
277             =item *
278              
279             If called with a list of argument pairs, each with the first item being a reference to an array of up to two numbers, loops over each pair and uses those numbers to splice the value array.
280              
281             The first controlling number is the position at which the splice will begin. Zero will start before the first item in the list. Negative numbers count backwards from the end of the array.
282              
283             The second number is the number of items to be removed from the list. If it is omitted, or undefined, or zero, no items are removed. If it is a positive integer, that many items will be returned.
284              
285             If both numbers are omitted, or are both undefined, they default to containing the entire value array.
286              
287             If the second argument is undef, no values will be inserted; if it is a non-reference value, that one value will be inserted; if it is an array-ref, its values will be copied.
288              
289             The method returns the items that removed from the array, if any.
290              
291             =back
292              
293             Sample declaration and usage:
294            
295             package MyObject;
296             use Class::MakeMethods::Standard::Array (
297             array => 'bar',
298             );
299             ...
300            
301             # Clear and set contents of list
302             print $obj->bar([ 'Spume', 'Frost' ] );
303            
304             # Set values by position
305             $obj->bar(0 => 'Foozle', 1 => 'Bang!');
306            
307             # Positions may be overwritten, and in any order
308             $obj->bar(2 => 'And Mash', 1 => 'Blah!');
309            
310             # Retrieve value by position
311             print $obj->bar(1);
312            
313             # Direct access to referenced array
314             print scalar @{ $obj->bar() };
315              
316             There are also calling conventions for slice and splice operations:
317              
318             # Retrieve slice of values by position
319             print join(', ', $obj->bar( undef, [0, 2] ) );
320            
321             # Insert an item at position in the array
322             $obj->bar([3], 'Potatoes' );
323            
324             # Remove 1 item from position 3 in the array
325             $obj->bar([3, 1], undef );
326            
327             # Set a new value at position 2, and return the old value
328             print $obj->bar([2, 1], 'Froth' );
329              
330             =cut
331              
332             sub array {
333 2     2 1 4 my $class = shift;
334 2         4 map {
335 2         9 my $name = $_->{name};
336 2   33     14 my $index = $_->{array_index} ||
337             _array_index( $class->_context('TargetClass'), $name );
338 2         5 my $init = $_->{auto_init};
339             $name => sub {
340 6     6   21 my $self = shift;
341 6 100 66     33 if ( scalar(@_) == 0 ) {
    50          
342 2 100 66     12 if ( $init and ! defined $self->[$index] ) {
343 1         3 $self->[$index] = [];
344             }
345 0         0 ( ! $self->[$index] ) ? () :
346 2 50       16 ( wantarray ) ? @{ $self->[$index] } :
    50          
347             $self->[$index]
348             } elsif ( scalar(@_) == 1 and ref $_[0] eq 'ARRAY' ) {
349 0         0 $self->[$index] = [ @{ $_[0] } ];
  0         0  
350 0         0 ( ! $self->[$index] ) ? () :
351 0 0       0 ( wantarray ) ? @{ $self->[$index] } :
    0          
352             $self->[$index]
353             } else {
354 4   100     22 $self->[$index] ||= [];
355 4         14 array_splicer( $self->[$index], @_ );
356             }
357             }
358 2         13 } $class->_get_declarations(@_)
359             }
360              
361             ########################################################################
362              
363             =head2 hash - Instance Ref Accessor
364              
365             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
366              
367             =over 4
368              
369             =item *
370              
371             Must be called on an array-based instance.
372              
373             =item *
374              
375             Determines the array position associated with the method name, and uses that as an index into each instance to access the related value. This defaults to the next available slot in %FIELDS, but you may override this with the C<'array_index' => I> method parameter, or by pre-filling the contents of %FIELDS.
376              
377              
378             =item *
379              
380             The value for each instance will be a reference to a hash (or undef).
381              
382             =item *
383              
384             If called without any arguments, returns the contents of the hash in list context, or a hash reference in scalar context (or undef).
385              
386             =item *
387              
388             If called with one argument, uses that argument as an index to retrieve from the referenced hash, and returns that value (or undef). If the single argument is an array ref, then a slice of the referenced hash is returned.
389              
390             =item *
391              
392             If called with a list of key-value pairs, stores the value under the given key in the referenced hash. If the instance's value was previously undefined, a new hash is autovivified. The current value under each key will be overwritten, and later arguments with the same key will override earlier ones. Returns the contents of the hash in list context, or a hash reference in scalar context.
393              
394             =back
395              
396             Sample declaration and usage:
397              
398             package MyObject;
399             use Class::MakeMethods::Standard::Array (
400             hash => 'baz',
401             );
402             ...
403            
404             # Set values by key
405             $obj->baz('foo' => 'Foozle', 'bar' => 'Bang!');
406            
407             # Values may be overwritten, and in any order
408             $obj->baz('broccoli' => 'Blah!', 'foo' => 'Fiddle');
409            
410             # Retrieve value by key
411             print $obj->baz('foo');
412            
413             # Retrive slice of values by position
414             print join(', ', $obj->baz( ['foo', 'bar'] ) );
415            
416             # Direct access to referenced hash
417             print keys %{ $obj->baz() };
418            
419             # Reset the hash contents to empty
420             @{ $obj->baz() } = ();
421              
422             =cut
423              
424             sub hash {
425 2     2 1 4 my $class = shift;
426 2         6 map {
427 2         8 my $name = $_->{name};
428 2   33     16 my $index = $_->{array_index} ||
429             _array_index( $class->_context('TargetClass'), $name );
430 2         6 my $init = $_->{auto_init};
431             $name => sub {
432 6     6   24 my $self = shift;
433 6 100       22 if ( scalar(@_) == 0 ) {
    100          
    50          
434 2 100 66     13 if ( $init and ! defined $self->[$index] ) {
435 1         2 $self->[$index] = {};
436             }
437 0         0 ( ! $self->[$index] ) ? () :
438 2 50       21 ( wantarray ) ? %{ $self->[$index] } :
    50          
439             $self->[$index]
440             } elsif ( scalar(@_) == 1 ) {
441 2 50       10 if ( ref($_[0]) eq 'HASH' ) {
    50          
442 0         0 my $hash = shift;
443 0         0 $self->[$index] = { %$hash };
444             } elsif ( ref($_[0]) eq 'ARRAY' ) {
445 0         0 return @{$self->[$index]}{ @{$_[0]} }
  0         0  
  0         0  
446             } else {
447 2         8 return $self->[$index]->{ $_[0] }
448             }
449             } elsif ( scalar(@_) % 2 ) {
450 0         0 Carp::croak "Odd number of items in assigment to $name";
451             } else {
452 2         7 while ( scalar(@_) ) {
453 2         4 my $key = shift();
454 2         13 $self->[$index]->{ $key } = shift();
455             }
456 2 50       11 ( wantarray ) ? %{ $self->[$index] } :
  0         0  
457             $self->[$index]
458             }
459             }
460 2         16 } $class->_get_declarations(@_)
461             }
462              
463             ########################################################################
464              
465             =head2 object - Instance Ref Accessor
466              
467             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
468              
469             =over 4
470              
471             =item *
472              
473             Must be called on an array-based instance.
474              
475             =item *
476              
477             Determines the array position associated with the method name, and uses that as an index into each instance to access the related value. This defaults to the next available slot in %FIELDS, but you may override this with the C<'array_index' => I> method parameter, or by pre-filling the contents of %FIELDS.
478              
479             =item *
480              
481             The value for each instance will be a reference to an object (or undef).
482              
483             =item *
484              
485             If called without any arguments returns the current value.
486              
487             =item *
488              
489             If called with an argument, stores that as the value, and returns it,
490              
491             =back
492              
493             Sample declaration and usage:
494              
495             package MyObject;
496             use Class::MakeMethods::Standard::Hash (
497             object => 'foo',
498             );
499             ...
500            
501             # Store value
502             $obj->foo( Foozle->new() );
503            
504             # Retrieve value
505             print $obj->foo;
506              
507             =cut
508              
509             sub object {
510 2     2 1 5 my $class = shift;
511 2         5 map {
512 2         9 my $name = $_->{name};
513 2   33     18 my $index = $_->{array_index} ||
514             _array_index( $class->_context('TargetClass'), $name );
515 2         7 my $class = $_->{class};
516 2         5 my $init = $_->{auto_init};
517 2 50 33     15 if ( $init and ! $class ) {
518 0         0 Carp::croak("Use of auto_init requires value for class parameter")
519             }
520 2   50     27 my $new_method = $_->{new_method} || 'new';
521             $name => sub {
522 5     5   28 my $self = shift;
523 5 100       18 if ( scalar @_ ) {
524 1         2 my $value = shift;
525 1 50 33     9 if ( $class and ! UNIVERSAL::isa( $value, $class ) ) {
526 0         0 Carp::croak "Wrong argument type ('$value') in assigment to $name";
527             }
528 1         5 $self->[$index] = $value;
529             } else {
530 4 100 66     24 if ( $init and ! defined $self->[$index] ) {
531 1         7 $self->[$index] = $class->$new_method();
532             } else {
533 3         13 $self->[$index];
534             }
535             }
536             }
537 2         30 } $class->_get_declarations(@_)
538             }
539              
540             ########################################################################
541              
542             =head1 SEE ALSO
543              
544             See L for general information about this distribution.
545              
546             See L for more about this family of subclasses.
547              
548             See L for equivalent functionality
549             based on blessed hashes. If your module will be extensively
550             subclassed, consider switching to Standard::Hash to avoid the
551             subclassing concerns described above.
552              
553             =cut
554              
555             1;