File Coverage

blib/lib/Class/MakeMethods/Basic/Array.pm
Criterion Covered Total %
statement 47 77 61.0
branch 8 22 36.3
condition n/a
subroutine 8 12 66.6
pod 4 4 100.0
total 67 115 58.2


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Class::MakeMethods::Basic::Array - Basic array methods
4              
5             =head1 SYNOPSIS
6              
7             package MyObject;
8             use Class::MakeMethods::Basic::Array (
9             new => 'new',
10             scalar => [ 'foo', 'bar' ],
11             array => 'my_list',
12             hash => 'my_index',
13             );
14             ...
15            
16             # Constructor
17             my $obj = MyObject->new( foo => 'Foozle' );
18            
19             # Scalar Accessor
20             print $obj->foo();
21            
22             $obj->bar('Barbados');
23             print $obj->bar();
24            
25             # Array accessor
26             $obj->my_list(0 => 'Foozle', 1 => 'Bang!');
27             print $obj->my_list(1);
28            
29             # Hash accessor
30             $obj->my_index('broccoli' => 'Blah!', 'foo' => 'Fiddle');
31             print $obj->my_index('foo');
32              
33              
34             =head1 DESCRIPTION
35              
36             The Basic::Array subclass of MakeMethods provides a basic
37             constructor and accessors for blessed-array object instances.
38              
39             =head2 Calling Conventions
40              
41             When you C this package, the method names you provide
42             as arguments cause subroutines to be generated and installed in
43             your module.
44              
45             See L for a summary, or L for full details.
46              
47             =head2 Declaration Syntax
48              
49             To declare methods, pass in pairs of a method-type name followed
50             by one or more method names. Valid method-type names for this
51             package are listed in L<"METHOD GENERATOR TYPES">.
52              
53             See L for more
54             syntax information.
55              
56             =cut
57              
58             package Class::MakeMethods::Basic::Array;
59              
60             $VERSION = 1.000;
61 1     1   11586 use strict;
  1         2  
  1         47  
62 1     1   1101 use Class::MakeMethods '-isasubclass';
  1         3  
  1         8  
63              
64             ########################################################################
65              
66             =head2 About Positional Accessors
67              
68             Each accessor method claims the next available spot in the array
69             to store its value in.
70              
71             The mapping between method names and array positions is stored in
72             a hash named %FIELDS in the target package. When the first positional
73             accessor is defined for a package, its %FIELDS are initialized by
74             searching its inheritance tree.
75              
76             B: Subclassing packages that use positional accessors is
77             somewhat fragile, since you may end up with two distinct methods
78             assigned to the same position. Specific cases to avoid are:
79              
80             =over 4
81              
82             =item *
83              
84             If you inherit from more than one class with positional accessors,
85             the positions used by the two sets of methods will overlap.
86              
87             =item *
88              
89             If your superclass adds additional positional accessors after you
90             declare your first, they will overlap yours.
91              
92             =back
93              
94             =cut
95              
96             sub _array_index {
97 3     3   5 my $class = shift;
98 3         3 my $name = shift;
99 1     1   7 no strict;
  1         3  
  1         1159  
100 3         9 local $^W = 0;
101 3 100       3 if ( ! scalar %{$class . "::FIELDS"} ) {
  3         97  
102 2         3 my @classes = @{$class . "::ISA"};
  2         9  
103 2         2 my @fields;
104 2         6 while ( @classes ) {
105 1         2 my $superclass = shift @classes;
106 1 50       1 if ( scalar %{$superclass . "::FIELDS"} ) {
  1         5  
107 1         2 push @fields, %{$superclass . "::FIELDS"};
  1         6  
108             } else {
109 0         0 unshift @classes, @{$superclass . "::ISA"}
  0         0  
110             }
111             }
112 2         4 %{$class . "::FIELDS"} = @fields
  2         8  
113             }
114 3         22 my $field_hash = \%{$class . "::FIELDS"};
  3         8  
115 3 50       23 $field_hash->{$name} or $field_hash->{$name} = scalar keys %$field_hash
116             }
117              
118             ########################################################################
119              
120             =head1 METHOD GENERATOR TYPES
121              
122             =head2 new - Constructor
123              
124             For each method name passed, returns a subroutine with the following characteristics:
125              
126             =over 4
127              
128             =item *
129              
130             If called as a class method, makes a new array and blesses it into that class.
131              
132             =item *
133              
134             If called on an array-based instance, makes a copy of it and blesses the copy into the same class as the original instance.
135              
136             =item *
137              
138             If passed a list of method-value pairs, calls each named method with the associated value as an argument.
139              
140             =item *
141              
142             Returns the new instance.
143              
144             =back
145              
146             Sample declaration and usage:
147              
148             package MyObject;
149             use Class::MakeMethods::Basic::Array (
150             new => 'new',
151             );
152             ...
153            
154             # Bare constructor
155             my $empty = MyObject->new();
156            
157             # Constructor with initial sequence of method calls
158             my $obj = MyObject->new( foo => 'Foozle', bar => 'Barbados' );
159            
160             # Copy with overriding sequence of method calls
161             my $copy = $obj->new( bar => 'Bob' );
162              
163             =cut
164              
165             sub new {
166 1     1 1 2 my $class = shift;
167 1         2 map {
168 1         2 my $name = $_;
169             $name => sub {
170 4     4   1138 my $callee = shift;
171 4 100       22 my $self = ref($callee) ? bless( [@$callee], ref($callee) )
172             : bless( [], $callee );
173 4         23 while ( scalar @_ ) {
174 6         7 my $method = shift;
175 6         22 $self->$method( shift );
176             }
177 4         21 return $self;
178             }
179 1         9 } @_;
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.
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::Basic::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 4 my $class = shift;
226 3         5 map {
227 2         2 my $name = $_;
228 3         14 my $index = _array_index( $class->_context('TargetClass'), $name );
229             $name => sub {
230 21     21   50 my $self = shift;
231 21 100       44 if ( scalar @_ ) {
232 8         37 $self->[$index] = shift;
233             } else {
234 13         51 $self->[$index];
235             }
236             }
237 3         20 } @_;
238             }
239              
240             ########################################################################
241              
242             =head2 array - Instance Ref Accessor
243              
244             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
245              
246             =over 4
247              
248             =item *
249              
250             Must be called on an array-based instance.
251              
252             =item *
253              
254             Determines the array position associated with the method name, and uses that as an index into each instance to access the related value.
255              
256             =item *
257              
258             The value for each instance will be a reference to an array (or undef).
259              
260             =item *
261              
262             If called without any arguments, returns the current array-ref value (or undef).
263              
264             =item *
265              
266             If called with one argument, uses that argument as an index to retrieve from the referenced array, and returns that value (or undef). If the single argument is an array ref, then a slice of the referenced array is returned.
267              
268             =item *
269              
270             If called with a list of index-value pairs, 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.
271              
272             =back
273              
274             Sample declaration and usage:
275              
276             package MyObject;
277             use Class::MakeMethods::Basic::Array (
278             array => 'bar',
279             );
280             ...
281            
282             # Set values by position
283             $obj->bar(0 => 'Foozle', 1 => 'Bang!');
284            
285             # Positions may be overwritten, and in any order
286             $obj->bar(2 => 'And Mash', 1 => 'Blah!');
287            
288             # Retrieve value by position
289             print $obj->bar(1);
290            
291             # Retrieve slice of values by position
292             print join(', ', $obj->bar( [0, 2] ) );
293            
294             # Direct access to referenced array
295             print scalar @{ $obj->bar() };
296            
297             # Reset the array contents to empty
298             @{ $obj->bar() } = ();
299              
300             =cut
301              
302             sub array {
303 0     0 1   my $class = shift;
304 0           map {
305 0           my $name = $_;
306 0           my $index = _array_index( $class->_context('TargetClass'), $name );
307             $name => sub {
308 0     0     my $self = shift;
309 0 0         if ( scalar(@_) == 0 ) {
    0          
    0          
310 0           return $self->[$index];
311             } elsif ( scalar(@_) == 1 ) {
312 0           return $self->[$index]->[ shift() ];
313             } elsif ( scalar(@_) % 2 ) {
314 0           Carp::croak "Odd number of items in assigment to $name";
315             } else {
316 0           while ( scalar(@_) ) {
317 0           my $k = shift();
318 0           $self->[$index]->[ $k ] = shift();
319             }
320 0           return $self->[$index];
321             }
322             }
323 0           } @_;
324             }
325              
326             ########################################################################
327              
328             =head2 hash - Instance Ref Accessor
329              
330             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
331              
332             =over 4
333              
334             =item *
335              
336             Must be called on an array-based instance.
337              
338             =item *
339              
340             Determines the array position associated with the method name, and uses that as an index into each instance to access the related value.
341              
342             =item *
343              
344             The value for each instance will be a reference to a hash (or undef).
345              
346             =item *
347              
348             If called without any arguments, returns the current hash-ref value (or undef).
349              
350             =item *
351              
352             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.
353              
354             =item *
355              
356             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 current hash-ref value.
357              
358             =back
359              
360             Sample declaration and usage:
361              
362             package MyObject;
363             use Class::MakeMethods::Basic::Array (
364             hash => 'baz',
365             );
366             ...
367            
368             # Set values by key
369             $obj->baz('foo' => 'Foozle', 'bar' => 'Bang!');
370            
371             # Values may be overwritten, and in any order
372             $obj->baz('broccoli' => 'Blah!', 'foo' => 'Fiddle');
373            
374             # Retrieve value by key
375             print $obj->baz('foo');
376            
377             # Retrieve slice of values by position
378             print join(', ', $obj->baz( ['foo', 'bar'] ) );
379            
380             # Direct access to referenced hash
381             print keys %{ $obj->baz() };
382            
383             # Reset the hash contents to empty
384             @{ $obj->baz() } = ();
385              
386             =cut
387              
388             sub hash {
389 0     0 1   my $class = shift;
390 0           map {
391 0           my $name = $_;
392 0           my $index = _array_index( $class->_context('TargetClass'), $name );
393             $name => sub {
394 0     0     my $self = shift;
395 0 0         if ( scalar(@_) == 0 ) {
    0          
    0          
396 0           return $self->[$index];
397             } elsif ( scalar(@_) == 1 ) {
398 0           return $self->[$index]->{ shift() };
399             } elsif ( scalar(@_) % 2 ) {
400 0           Carp::croak "Odd number of items in assigment to $name";
401             } else {
402 0           while ( scalar(@_) ) {
403 0           my $k = shift();
404 0           $self->[$index]->{ $k } = shift();
405             }
406 0           return $self->[$index];
407             }
408             }
409 0           } @_;
410             }
411              
412             ########################################################################
413              
414             =head1 SEE ALSO
415              
416             See L for general information about this distribution.
417              
418             See L for more about this family of subclasses.
419              
420             =cut
421              
422             1;