File Coverage

blib/lib/Class/MakeMethods/Composite/Hash.pm
Criterion Covered Total %
statement 26 29 89.6
branch n/a
condition n/a
subroutine 10 13 76.9
pod 5 5 100.0
total 41 47 87.2


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Class::MakeMethods::Composite::Hash - Composite hash methods
4              
5             =head1 SYNOPSIS
6              
7             package MyObject;
8             use Class::MakeMethods::Composite::Hash (
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 Composite::Hash suclass of MakeMethods provides a basic constructor and accessors for blessed-hash object instances.
31              
32             =head2 Class::MakeMethods Calling Interface
33              
34             When you C this package, the method declarations you provide
35             as arguments cause subroutines to be generated and installed in
36             your module.
37              
38             You can also omit the arguments to C and instead make methods
39             at runtime by passing the declarations to a subsequent call to
40             C.
41              
42             You may include any number of declarations in each call to C
43             or C. If methods with the same name already exist, earlier
44             calls to C or C win over later ones, but within each
45             call, later declarations superceed earlier ones.
46              
47             You can install methods in a different package by passing C<-TargetClass =E I> as your first arguments to C or C.
48              
49             See L for more details.
50              
51             =head2 Class::MakeMethods::Basic Declaration Syntax
52              
53             The following types of Basic declarations are supported:
54              
55             =over 4
56              
57             =item *
58              
59             I => "I"
60              
61             =item *
62              
63             I => "I I..."
64              
65             =item *
66              
67             I => [ "I", "I", ...]
68              
69             =back
70              
71             See the "METHOD GENERATOR TYPES" section below for a list of the supported values of I.
72              
73             For each method name you provide, a subroutine of the indicated
74             type will be generated and installed under that name in your module.
75              
76             Method names should start with a letter, followed by zero or more
77             letters, numbers, or underscores.
78              
79             =head2 Class::MakeMethods::Composite Declaration Syntax
80              
81             The Composite syntax also provides several ways to optionally
82             associate a hash of additional parameters with a given method
83             name.
84              
85             =over 4
86              
87             =item *
88              
89             I => [ "I" => { I=>I... }, ... ]
90              
91             A hash of parameters to use just for this method name.
92              
93             (Note: to prevent confusion with self-contained definition hashes,
94             described below, parameter hashes following a method name must not
95             contain the key 'name'.)
96              
97             =item *
98              
99             I => [ [ "I", "I", ... ] => { I=>I... } ]
100              
101             Each of these method names gets a copy of the same set of parameters.
102              
103             =item *
104              
105             I => [ { "name"=>"I", I=>I... }, ... ]
106              
107             By including the reserved parameter C, you create a self-contained declaration with that name and any associated hash values.
108              
109             =back
110              
111             Basic declarations, as described above, are given an empty parameter hash.
112              
113             =cut
114              
115             package Class::MakeMethods::Composite::Hash;
116              
117             $VERSION = 1.000;
118 5     5   19535 use strict;
  5         8  
  5         204  
119 5     5   1985 use Class::MakeMethods::Composite '-isasubclass';
  5         13  
  5         54  
120 5     5   33 use Carp;
  5         8  
  5         430  
121              
122             ########################################################################
123              
124             =head1 METHOD GENERATOR TYPES
125              
126             =head2 new - Constructor
127              
128             For each method name passed, returns a subroutine with the following characteristics:
129              
130             =over 4
131              
132             =item *
133              
134             Has a reference to a sample item to copy. This defaults to a reference to an empty hash, but you may override this with the C<'defaults' =E I> method parameter.
135              
136             =item *
137              
138             If called as a class method, makes a new hash and blesses it into that class.
139              
140             =item *
141              
142             If called on a hash-based instance, makes a copy of it and blesses the copy into the same class as the original instance.
143              
144             =item *
145              
146             If passed a list of key-value pairs, appends them to the new hash. These arguments override any copied values, and later arguments with the same name will override earlier ones.
147              
148             =item *
149              
150             Returns the new instance.
151              
152             =back
153              
154             Sample declaration and usage:
155              
156             package MyObject;
157             use Class::MakeMethods::Composite::Hash (
158             new => 'new',
159             );
160             ...
161            
162             # Bare constructor
163             my $empty = MyObject->new();
164            
165             # Constructor with initial values
166             my $obj = MyObject->new( foo => 'Foozle', bar => 'Barbados' );
167            
168             # Copy with overriding value
169             my $copy = $obj->new( bar => 'Bob' );
170              
171             =cut
172              
173             =head2 new --with_values - Constructor
174              
175             For each method name passed, returns a subroutine with the following characteristics:
176              
177             =over 4
178              
179             =item *
180              
181             May be called as a class method, or (equivalently) on any existing object of that class.
182              
183             =item *
184              
185             Creates a hash, blesses it into the class, and returns the new instance.
186              
187             =item *
188              
189             If no arguments are provided, the returned hash will be empty. If passed a single hash-ref argument, copies its contents into the new hash. If called with multiple arguments, treats them as key-value pairs, and copies them into the new hash. (Note that this is a "shallow" copy, not a "deep" clone.)
190              
191             =back
192              
193             =cut
194              
195 5     5   30 use vars qw( %ConstructorFragments );
  5         9  
  5         1993  
196              
197             sub new {
198 8     8 1 79 (shift)->_build_composite( \%ConstructorFragments, @_ );
199             }
200              
201             %ConstructorFragments = (
202             '' => [
203             '+init' => sub {
204             my $method = pop @_;
205             $method->{target_class} ||= $Class::MethodMaker::CONTEXT{TargetClass};
206             $method->{defaults} ||= {};
207             },
208             'do' => sub {
209             my $method = pop @_;
210             my $self = shift @_;
211             my $obj = ref($self) ? bless( { %$self }, ref $self )
212             : bless( { %{$method->{defaults}} }, $self );
213             @_ = %{$_[0]}
214             if ( scalar @_ == 1 and ref $_[0] eq 'HASH' );
215             while ( scalar @_ ) {
216             my $method = shift @_;
217             my $value = shift @_;
218             $obj->$method( $value );
219             }
220             $obj;
221             },
222             ],
223             'with_values' => [
224             'do' => sub {
225             my $method = pop @_;
226             my $self = shift @_;
227             @_ = %{$_[0]}
228             if ( scalar @_ == 1 and ref $_[0] eq 'HASH' );
229             bless( { @_ }, ref($self) || $self );
230             }
231             ],
232             );
233              
234             ########################################################################
235              
236             =head2 scalar - Instance Accessor
237              
238             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
239              
240             =over 4
241              
242             =item *
243              
244             Must be called on a hash-based instance.
245              
246             =item *
247              
248             Has a specific hash key to use to access the related value for each instance.
249             This defaults to the method name, but you may override this with the C<'hash_key' => I> method parameter.
250              
251             =item *
252              
253             If called without any arguments returns the current value.
254              
255             =item *
256              
257             If called with an argument, stores that as the value, and returns it.
258              
259             =item *
260              
261             If called with multiple arguments, stores a reference to a new array with those arguments as contents, and returns that array reference.
262              
263             =back
264              
265             Sample declaration and usage:
266              
267             package MyObject;
268             use Class::MakeMethods::Composite::Hash (
269             scalar => 'foo',
270             );
271             ...
272            
273             # Store value
274             $obj->foo('Foozle');
275            
276             # Retrieve value
277             print $obj->foo;
278              
279             =cut
280              
281 5     5   31 use vars qw( %ScalarFragments );
  5         10  
  5         6244  
282              
283             sub scalar {
284 16     16 1 62 (shift)->_build_composite( \%ScalarFragments, @_ );
285             }
286              
287             %ScalarFragments = (
288             '' => [
289             '+init' => sub {
290             my ($method) = @_;
291             $method->{hash_key} ||= $method->{name};
292             $method->{target_class} ||= $Class::MethodMaker::CONTEXT{TargetClass};
293             },
294             'do' => sub {
295             my $method = pop @_;
296             my $self = shift @_;
297             if ( scalar(@_) == 0 ) {
298             $self->{$method->{hash_key}};
299             } elsif ( scalar(@_) == 1 ) {
300             $self->{$method->{hash_key}} = shift;
301             } else {
302             $self->{$method->{hash_key}} = [@_];
303             }
304             },
305             ],
306             'rw' => [],
307             'p' => [
308             '+pre' => sub {
309             my $method = pop @_;
310             my $self = shift @_;
311             unless ( UNIVERSAL::isa((caller(1))[0], $method->{target_class}) ) {
312             croak "Method $method->{name} is protected";
313             }
314             },
315             ],
316             'pp' => [
317             '+pre' => sub {
318             my $method = pop @_;
319             my $self = shift @_;
320             unless ( (caller(1))[0] eq $method->{target_class} ) {
321             croak "Method $method->{name} is private";
322             }
323             },
324             ],
325             'pw' => [
326             '+pre' => sub {
327             my $method = pop @_;
328             my $self = shift @_;
329             my $args = \@_;
330             unless ( @$args == 0 or UNIVERSAL::isa((caller(1))[0], $method->{target_class}) ) {
331             croak "Method $method->{name} is write-protected";
332             }
333             },
334             ],
335             'ppw' => [
336             '+pre' => sub {
337             my $method = pop @_;
338             my $self = shift @_;
339             my $args = \@_;
340             unless ( @$args == 0 or (caller(1))[0] eq $method->{target_class} ) {
341             croak "Method $method->{name} is write-private";
342             }
343             },
344             ],
345             'r' => [
346             '+pre' => sub {
347             my $method = pop @_;
348             my $self = shift @_;
349             my $args = \@_;
350             @$args = ();
351             },
352             ],
353             'ro' => [
354             '+pre' => sub {
355             my $method = pop @_;
356             my $self = shift @_;
357             my $args = \@_;
358             unless ( @$args == 0 ) {
359             croak("Method $method->{name} is read-only");
360             }
361             },
362             ],
363             'wo' => [
364             '+pre' => sub {
365             my $method = pop @_;
366             my $self = shift @_;
367             my $args = \@_;
368             if ( @$args == 0 ) {
369             croak("Method $method->{name} is write-only");
370             }
371             },
372             ],
373             'return_original' => [
374             '+pre' => sub {
375             my $method = pop @_;
376             my $self = shift @_;
377             my $args = \@_;
378             $method->{scratch}{return_original} = $self->{$method->{hash_key}};
379             },
380             '+post' => sub {
381             my $method = pop @_;
382             my $self = shift @_;
383             my $args = \@_;
384             ${ $method->{result} } = $method->{scratch}{return_original};
385             },
386             ],
387             );
388              
389             ########################################################################
390              
391             =head2 array - Instance Ref Accessor
392              
393             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
394              
395             =over 4
396              
397             =item *
398              
399             Must be called on a hash-based instance.
400              
401             =item *
402              
403             Has a specific hash key to use to access the related value for each instance.
404             This defaults to the method name, but you may override this with the C<'hash_key' => I> method parameter.
405              
406             =item *
407              
408             The value for each instance will be a reference to an array (or undef).
409              
410             =item *
411              
412             If called without any arguments, returns the current array-ref value (or undef).
413              
414              
415             =item *
416              
417             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).
418              
419             =item *
420              
421             If called with a single array ref argument, uses that list to return a slice of the referenced array.
422              
423             =item *
424              
425             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.
426              
427             =item *
428              
429             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.
430              
431             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.
432              
433             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.
434              
435             If both numbers are omitted, or are both undefined, they default to containing the entire value array.
436              
437             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.
438              
439             The method returns the items that removed from the array, if any.
440              
441             =back
442              
443             Sample declaration and usage:
444            
445             package MyObject;
446             use Class::MakeMethods::Composite::Hash (
447             array => 'bar',
448             );
449             ...
450            
451             # Clear and set contents of list
452             print $obj->bar([ 'Spume', 'Frost' ] );
453            
454             # Set values by position
455             $obj->bar(0 => 'Foozle', 1 => 'Bang!');
456            
457             # Positions may be overwritten, and in any order
458             $obj->bar(2 => 'And Mash', 1 => 'Blah!');
459            
460             # Retrieve value by position
461             print $obj->bar(1);
462            
463             # Direct access to referenced array
464             print scalar @{ $obj->bar() };
465              
466             There are also calling conventions for slice and splice operations:
467              
468             # Retrieve slice of values by position
469             print join(', ', $obj->bar( undef, [0, 2] ) );
470            
471             # Insert an item at position in the array
472             $obj->bar([3], 'Potatoes' );
473            
474             # Remove 1 item from position 3 in the array
475             $obj->bar([3, 1], undef );
476            
477             # Set a new value at position 2, and return the old value
478             print $obj->bar([2, 1], 'Froth' );
479              
480             =cut
481              
482 5     5   33 use vars qw( %ArrayFragments );
  5         10  
  5         1708  
483              
484             sub array {
485 0     0 1   (shift)->_build_composite( \%ArrayFragments, @_ );
486             }
487              
488             %ArrayFragments = (
489             '' => [
490             '+init' => sub {
491             my ($method) = @_;
492             $method->{hash_key} ||= $_->{name};
493             },
494             'do' => sub {
495             my $method = pop @_;
496             my $self = shift @_;
497             my $args = \@_;
498             if ( scalar(@$args) == 0 ) {
499             if ( $method->{auto_init} and
500             ! defined $self->{$method->{hash_key}} ) {
501             $self->{$method->{hash_key}} = [];
502             }
503             wantarray ? @{ $self->{$method->{hash_key}} } : $self->{$method->{hash_key}};
504             } elsif ( scalar(@_) == 1 and ref $_[0] eq 'ARRAY' ) {
505             $self->{$method->{hash_key}} = [ @{ $_[0] } ];
506             wantarray ? @{ $self->{$method->{hash_key}} } : $self->{$method->{hash_key}};
507             } else {
508             $self->{$method->{hash_key}} ||= [];
509             array_splicer( $self->{$method->{hash_key}}, @$args );
510             }
511             },
512             ],
513             );
514              
515             ########################################################################
516              
517             =head2 hash - Instance Ref Accessor
518              
519             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
520              
521             =over 4
522              
523             =item *
524              
525             Must be called on a hash-based instance.
526              
527             =item *
528              
529             Has a specific hash key to use to access the related value for each instance.
530             This defaults to the method name, but you may override this with the C<'hash_key' => I> method parameter.
531              
532             =item *
533              
534             The value for each instance will be a reference to a hash (or undef).
535              
536             =item *
537              
538             If called without any arguments, returns the contents of the hash in list context, or a hash reference in scalar context (or undef).
539              
540             =item *
541              
542             If called with one non-ref argument, uses that argument as an index to retrieve from the referenced hash, and returns that value (or undef).
543              
544             =item *
545              
546             If called with one array-ref argument, uses the contents of that array to retrieve a slice of the referenced hash.
547              
548             =item *
549              
550             If called with one hash-ref argument, sets the contents of the referenced hash to match that provided.
551              
552             =item *
553              
554             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.
555              
556             =back
557              
558             Sample declaration and usage:
559              
560             package MyObject;
561             use Class::MakeMethods::Composite::Hash (
562             hash => 'baz',
563             );
564             ...
565            
566             # Set values by key
567             $obj->baz('foo' => 'Foozle', 'bar' => 'Bang!');
568            
569             # Values may be overwritten, and in any order
570             $obj->baz('broccoli' => 'Blah!', 'foo' => 'Fiddle');
571            
572             # Retrieve value by key
573             print $obj->baz('foo');
574            
575             # Retrive slice of values by position
576             print join(', ', $obj->baz( ['foo', 'bar'] ) );
577            
578             # Direct access to referenced hash
579             print keys %{ $obj->baz() };
580            
581             # Reset the hash contents to empty
582             @{ $obj->baz() } = ();
583              
584             =cut
585              
586 5     5   32 use vars qw( %HashFragments );
  5         8  
  5         2207  
587              
588             sub hash {
589 0     0 1   (shift)->_build_composite( \%HashFragments, @_ );
590             }
591              
592             %HashFragments = (
593             '' => [
594             '+init' => sub {
595             my ($method) = @_;
596             $method->{hash_key} ||= $_->{name};
597             },
598             'do' => sub {
599             my $method = pop @_;
600             my $self = shift @_;
601             my $args = \@_;
602             if ( scalar(@$args) == 0 ) {
603             if ( $method->{auto_init} and ! defined $self->{$method->{hash_key}} ) {
604             $self->{$method->{hash_key}} = {};
605             }
606             wantarray ? %{ $self->{$method->{hash_key}} } : $self->{$method->{hash_key}};
607             } elsif ( scalar(@$args) == 1 ) {
608             if ( ref($_[0]) eq 'HASH' ) {
609             %{$self->{$method->{hash_key}}} = %{$_[0]};
610             } elsif ( ref($_[0]) eq 'ARRAY' ) {
611             return @{$self->{$method->{hash_key}}}{ @{$_[0]} }
612             } else {
613             return $self->{$method->{hash_key}}->{ $_[0] }
614             }
615             } elsif ( scalar(@$args) % 2 ) {
616             croak "Odd number of items in assigment to $method->{name}";
617             } else {
618             while ( scalar(@$args) ) {
619             my $key = shift @$args;
620             $self->{$method->{hash_key}}->{ $key} = shift @$args;
621             }
622             wantarray ? %{ $self->{$method->{hash_key}} } : $self->{$method->{hash_key}};
623             }
624             },
625             ],
626             );
627              
628             ########################################################################
629              
630             =head2 object - Instance Ref Accessor
631              
632             For each method name passed, uses a closure to generate a subroutine with the following characteristics:
633              
634             =over 4
635              
636             =item *
637              
638             Must be called on a hash-based instance.
639              
640             =item *
641              
642             Has a specific hash key to use to access the related value for each instance.
643             This defaults to the method name, but you may override this with the C<'hash_key' => I> method parameter.
644              
645             =item *
646              
647             The value for each instance will be a reference to an object (or undef).
648              
649             =item *
650              
651             If called without any arguments returns the current value.
652              
653             =item *
654              
655             If called with an argument, stores that as the value, and returns it,
656              
657             =back
658              
659             Sample declaration and usage:
660              
661             package MyObject;
662             use Class::MakeMethods::Composite::Hash (
663             object => 'foo',
664             );
665             ...
666            
667             # Store value
668             $obj->foo( Foozle->new() );
669            
670             # Retrieve value
671             print $obj->foo;
672              
673             =cut
674              
675 5     5   29 use vars qw( %ObjectFragments );
  5         9  
  5         3606  
676              
677             sub object {
678 0     0 1   (shift)->_build_composite( \%ObjectFragments, @_ );
679             }
680              
681             %ObjectFragments = (
682             '' => [
683             '+init' => sub {
684             my ($method) = @_;
685             $method->{hash_key} ||= $_->{name};
686             },
687             'do' => sub {
688             my $method = pop @_;
689             my $self = shift;
690             if ( scalar @_ ) {
691             my $value = shift;
692             if ( $method->{class} and ! UNIVERSAL::isa( $value, $method->{class} ) ) {
693             croak "Wrong argument type ('$value') in assigment to $method->{name}";
694             }
695             $self->{$method->{hash_key}} = $value;
696             } else {
697             if ( $method->{auto_init} and ! defined $self->{$method->{hash_key}} ) {
698             my $class = $method->{class}
699             or die "Can't auto_init without a class";
700             my $new_method = $method->{new_method} || 'new';
701             $self->{$method->{hash_key}} = $class->$new_method();
702             }
703             $self->{$method->{hash_key}};
704             }
705             },
706             ],
707             );
708              
709             ########################################################################
710              
711             =head1 SEE ALSO
712              
713             See L for general information about this distribution.
714              
715             See L for more about this family of subclasses.
716              
717             =cut
718              
719             1;