File Coverage

blib/lib/Class/Accessor/Classy.pm
Criterion Covered Total %
statement 296 347 85.3
branch 70 110 63.6
condition 18 33 54.5
subroutine 47 55 85.4
pod 18 18 100.0
total 449 563 79.7


line stmt bran cond sub pod time code
1             package Class::Accessor::Classy;
2             $VERSION = v0.9.1;
3              
4 7     7   224920 use warnings;
  7         21  
  7         252  
5 7     7   43 use strict;
  7         13  
  7         251  
6 7     7   51 use Carp;
  7         14  
  7         1507  
7              
8             =head1 NAME
9              
10             Class::Accessor::Classy - accessors with minimal inheritance
11              
12             =head1 SYNOPSIS
13              
14             package YourPackage;
15              
16             use Class::Accessor::Classy;
17             with qw(new); # with a new() method
18             ro qw(foo); # read-only
19             rw qw(bar); # read-write
20             rs baz => \ (my $set_baz); # read-only, plus a secret writer
21              
22             # alternatively:
23             my $set_bip = rs 'bip';
24              
25             ro_c suitcase => 'red'; # read-only class data
26             rw_c hat => 'black'; # read-write class data
27             rs_c socks => \ (my $set_socks) => undef;
28              
29             # alternative secret writer syntax
30             my $set_shoes = rs_c shoes => undef;
31              
32             # also class read-only:
33             constant seven => 7;
34             constant eight => this->seven + 1;
35             no Class::Accessor::Classy;
36             # ^-- removes all of the syntax bits from your namespace
37              
38             package whatever;
39              
40             YourPackage->set_hat(undef);
41             my $obj = YourPackage->new(foo => 4, bar => 2);
42             # NOTE I'm thinking of deprecating the get_foo() usage
43             warn "foo ", $obj->foo;
44             YourPackage->$set_socks("tube");
45              
46             =head1 About
47              
48             This module provides an extremely small-footprint accessor/mutator
49             declaration scheme for fast and convenient object attribute setup. It
50             is intended as a simple and speedy mechanism for preventing hash-key
51             typos rather than a full-blown object system with type checking and so
52             on.
53              
54             The accessor methods appear as a hidden parent class of your package and
55             generally try to stay out of the way. The accessors and mutators
56             generated are of the form C and C, respectively.
57              
58             =head1 Frontend
59              
60             Unlike other class-modifying code, this is not designed to be inherited
61             from. Instead, you simply use it and get an invisible subclass
62             containing your accessors. If you use the 'no' syntax (to call
63             unimport), you are left with a squeaky-clean namespace.
64              
65             After 'use' and before 'no', the following pieces of syntax are
66             available.
67              
68             =head2 with
69              
70             Add a 'standard' method to your class.
71              
72             =over
73              
74             =item new
75              
76             =back
77              
78             =head2 ro
79              
80             Read-only properties (accessors only.)
81              
82             ro qw(foo bar baz);
83              
84             =head2 rw
85              
86             Define read-write (accessor + mutator) properties.
87              
88             rw qw(foo bar baz);
89              
90             =head2 lv
91              
92             Properties with lvalue accessors.
93              
94             lv qw(thing deal stuff);
95              
96             =head2 ri
97              
98             Immutable properties. Once set, further calls to the mutator throw
99             errors.
100              
101             ri qw(foo bar baz);
102              
103             =head2 rs
104              
105             Read-only properties with a secret mutator.
106              
107             rs foo => \(my $set_foo);
108              
109             =head2 lo
110              
111             Read-only list properties. These are stored as an array-ref, but the
112             accessor returns a list.
113              
114             lo qw(foo bar baz);
115              
116             =head2 lw
117              
118             Read-write list properties. The mutator takes a list.
119              
120             lw 'foo';
121              
122             This defaults to create foo()|get_foo(), set_foo(), and add_foo()
123             methods. Other features are possible here, but currently experimental.
124              
125             =head2 ls
126              
127             List property with a secret mutator.
128              
129             ls foo => \(my $set_foo);
130              
131             =head2 this
132              
133             A shortcut for your classname. Useful for e.g. defining one constant in
134             terms of another.
135              
136             this->some_class_method;
137              
138             =head2 getter
139              
140             Define a custom getter.
141              
142             =head2 setter
143              
144             Define a custom setter.
145              
146             =head2 constant
147              
148             A class constant.
149              
150             constant foo => 7;
151              
152             =head2 ro_c
153              
154             Read-only class method.
155              
156             =head2 rw_c
157              
158             A read-write class method, with a default.
159              
160             rw_c foo => 9;
161              
162             =head2 rs_c
163              
164             A class method with a secret setter.
165              
166             rs_c bar => \(my $set_bar) => 12;
167              
168             =head2 in
169              
170             Specify the destination package. You need to set this before defining
171             anything else (but it is usually best to just not set it.)
172              
173             in 'why_be_so_secretive';
174              
175             =head2 aka
176              
177             Add an alias for an existing method.
178              
179             aka have_method => 'want_method', 'and_also_want';
180              
181             =cut
182              
183             =head1 Utilities
184              
185             This introspection stuff is unreliable -- don't use it.
186              
187             =head2 find_accessors
188              
189             @attribs = Class::Accessor::Classy->find_accessors($class);
190              
191             =cut
192              
193             sub find_accessors {
194 0     0 1 0 my $package = shift;
195 0         0 my ($class) = @_;
196              
197             # TODO just cache them rather than introspect?
198              
199 0         0 my @classes = $package->find_subclasses($class);
200 0         0 my @acc;
201 0         0 foreach my $c (@classes) {
202 7     7   53 no strict 'refs';
  7         14  
  7         2036  
203 0         0 push(@acc, keys(%{$c . '::'}));
  0         0  
204             }
205 0         0 my %skip = map({$_ => 1} qw(new import)); # XXX no introspecting!?
  0         0  
206 0         0 my %got;
207             return(
208 0 0 0     0 grep({
    0 0        
209 0         0 ($_ !~ m/^[gs]et_/) and (lc($_) ne 'isa') and
210             ($got{$_} ? 0 : ($got{$_} = 1)) and
211             (! $skip{$_})
212             } @acc)
213             );
214             } # end subroutine find_accessors definition
215             ########################################################################
216              
217             =head2 find_subclasses
218              
219             @classlist = Class::Accessor::Classy->find_subclasses($class);
220              
221             =cut
222              
223             sub find_subclasses {
224 0     0 1 0 my $package = shift;
225 0         0 my ($class) = @_;
226              
227 0         0 my $get_isa;
228             $get_isa = sub {
229 0     0   0 my ($p) = @_;
230 7     7   39 my @isa = eval {no strict 'refs'; @{$p . '::ISA'}};
  7         13  
  7         13550  
  0         0  
  0         0  
  0         0  
231 0 0       0 $@ and die;
232 0         0 return($p, map({$get_isa->($_)} @isa));
  0         0  
233 0         0 };
234 0         0 return(grep({$_ =~ m/::--accessors$/} $get_isa->($class)));
  0         0  
235             } # end subroutine find_subclasses definition
236             ########################################################################
237              
238             =head1 Subclassable
239              
240             Customized subclasses may override these methods to create a new kind of
241             accessor generator.
242              
243             =over
244              
245             =item NOTE
246              
247             You do not subclass Class::Accessor::Classy to construct your objects.
248              
249             If you are just creating MyObject, you are not inheriting any of these
250             methods.
251              
252             The rest of this documentation only pertains to you if you are trying to
253             create something like Class::Accessor::Classy::MyWay.
254              
255             =back
256              
257             =over
258              
259             =item notation:
260              
261             Read these as: $CAC = 'Class::Accessor::Classy'; (or whatever subclass
262             you're creating.)
263              
264             =back
265              
266             =head2 exports
267              
268             my %exports = $CAC->exports;
269              
270             =cut
271              
272             sub exports {
273 26     26 1 4645 my $package = shift; # allows us to be subclassed :-)
274 26     37   103 my $CP = sub {$package->create_package(class => $_[0])};
  37         178  
275             my %exports = (
276             with => sub (@) {
277 7     7   4541 $package->make_standards($CP->(caller), @_);
278             },
279             this => sub () {
280 0     0   0 (caller)[0];
281             },
282             getter => sub (&) {
283 1     1   14 my ($subref) = @_;
284 1         3 $package->install_sub($CP->(caller), '--get', $subref,
285             'custom getter'
286             );
287             },
288             setter => sub (&) {
289 1     1   8 my ($subref) = @_;
290 1         5 $package->install_sub($CP->(caller), '--set', $subref,
291             'custom setter'
292             );
293             },
294             constant => sub ($$) { # same as class_ro
295 0     0   0 $package->make_class_data('ro', $CP->(caller), @_);
296             },
297             ro_c => sub {
298 3     3   20 $package->make_class_data('ro', $CP->(caller), @_);
299             },
300             rw_c => sub {
301 3     3   17 $package->make_class_data('rw', $CP->(caller), @_);
302             },
303             rs_c => sub {
304 3     3   549 my @list = @_;
305 3         5 my @pairs;
306             my @refs;
307 3 100 100     20 if((ref($list[1]) || '') eq 'SCALAR') {
308 1 50       6 croak("number of elements in argument list") if(@list % 3);
309 1         9 @pairs = map({[$list[$_*3], $list[$_*3+2]]} 0..($#list / 3));
  1         11  
310 1         5 @refs = map({$list[$_*3+1]} 0..($#list / 3));
  1         4  
311             }
312             else {
313 2         6 @pairs = map({[$list[$_*2], $list[$_*2+1]]} 0..($#list / 2));
  3         12  
314             }
315 3         6 my @names;
316 3         10 my $class = $CP->(caller);
317 3         7 foreach my $pair (@pairs) {
318 4         13 push(@names,
319             $package->make_class_data('rs', $class, @$pair)
320             );
321             }
322 3 100       8 if(@refs) {
323 1         4 ${$refs[$_]} = $names[$_] for(0..$#names);
  1         4  
324             }
325             else {
326 2 50       8 @names == @pairs or die "oops";
327             }
328 3 100       18 (@names > 1) or return($names[0]);
329 1         6 return(@names);
330             },
331             in => sub ($) {
332             # put them in this package
333 0     0   0 my ($in) = @_;
334 0         0 my $caller = caller;
335 0         0 my $class = $package->create_package(
336             class => $caller,
337             in => $in,
338             );
339             },
340             ro => sub (@) {
341 6     6   3357 my (@list) = @_;
342 6         31 my $class = $CP->(caller);
343 6         29 $package->make_getters($class, @list);
344 6         24 $package->make_aliases($class, @list);
345             },
346             rw => sub (@) {
347 4     4   24 my (@list) = @_;
348 4         16 my $class = $CP->(caller);
349 4         14 $package->make_getters($class, @list);
350 4         13 $package->make_aliases($class, @list);
351 4         16 $package->make_setters($class, @list);
352             },
353             lv => sub (@) {
354 1     1   8 my (@list) = @_;
355 1         3 my $class = $CP->(caller);
356 1         5 $package->make_lv_getters($class, @list);
357 1         6 $package->make_aliases($class, @list);
358             },
359             ri => sub (@) {
360 1     1   8 my (@list) = @_;
361 1         5 my $class = $CP->(caller);
362 1         4 $package->make_getters($class, @list);
363 1         3 $package->make_aliases($class, @list);
364 1         5 $package->make_immutable($class, @list);
365             },
366             rs => sub (@) {
367 3     3   2397 my (@list) = @_;
368             # decide if we got passed refs or should return a list
369 3         5 my @items;
370             my @refs;
371 3 100 100     17 if((ref($list[1]) || '') eq 'SCALAR') {
372 1 50       5 croak("odd number of elements in argument list") if(@list % 2);
373 1         5 @items = map({$list[$_*2]} 0..($#list / 2));
  1         4  
374 1         4 @refs = map({$list[$_*2+1]} 0..($#list / 2));
  1         3  
375             }
376             else {
377 2         4 @items = @list;
378             }
379 3         13 my $class = $CP->(caller);
380 3         11 $package->make_getters($class, @items);
381 3         11 $package->make_aliases($class, @items);
382 3         11 my @names = $package->make_secrets($class, @items);
383 3 50       14 (@names == @items) or die "oops";
384 3 100       9 if(@refs) {
385 1         4 ${$refs[$_]} = $names[$_] for(0..$#names);
  1         4  
386             }
387 3 100       14 (@names > 1) or return($names[0]);
388 1         5 return(@names);
389             },
390             lo => sub {
391 1     1   6 my (@list) = @_;
392 1         4 my $class = $CP->(caller);
393 1         3 foreach my $item (@list) {
394 1         5 $package->make_array_method(
395             class => $class,
396             item => $item,
397             functions => [qw(get)],
398             );
399             }
400             },
401             lw => sub { # no list here
402 1     1   5 my ($item, @args) = @_;
403 1         2 my @f = @args;
404             #@f and croak("not yet");
405 1         4 $package->make_array_method(
406             class => $CP->(caller),
407             item => $item,
408             functions => [qw(get set add), @f],
409             );
410             },
411             ls => sub {
412 2     2   27 my ($item, @args) = @_;
413 2 50 50     30 my $setref = shift(@args) if((ref($args[0])||'') eq 'SCALAR');
414              
415 2         5 my @f;
416             my @r;
417 2 100 100     13 if((ref($args[1]) || '') eq 'SCALAR') {
418 1 50       5 croak("odd number of elements in argument list") if(@args % 2);
419 1         6 @f = map({$args[$_*2]} 0..($#args / 2));
  1         6  
420 1         4 @r = map({$args[$_*2+1]} 0..($#args / 2));
  1         4  
421             }
422             else {
423 1         3 @f = @args;
424             }
425 2         9 my @ans = $package->make_array_method(
426             class => $CP->(caller),
427             item => $item,
428             functions => [qw(get set), @f],
429             secret => 1,
430             );
431              
432 2 50       8 $$setref = shift(@ans) if($setref);
433 2 100       7 if(@r) {
434 1         5 ${$r[$_]} = $ans[$_] for(0..$#ans);
  1         4  
435             }
436 2         7 return(@ans);
437             },
438             aka => sub (@) {
439 0     0   0 my ($from, @to) = @_;
440 0         0 my $class = $CP->(caller);
441 0         0 $package->make_aka($class, $from, @to);
442             },
443 26         3455 );
444             } # end subroutine exports definition
445             ########################################################################
446              
447             =head2 import
448              
449             $CAC->import;
450              
451             =cut
452              
453             sub import {
454 14     14   26987 my $package = shift;
455              
456 14         33 my $caller = caller();
457             # we should never export to main
458 14 100       265 croak 'cannot have accessors on the main package' if($caller eq 'main');
459 13         50 my %exports = $package->exports;
460 13         178 foreach my $name (keys(%exports)) {
461 7     7   80 no strict 'refs';
  7         39  
  7         937  
462             #no warnings 'redefine';
463             #my $ugh = *{$caller . '::' . $name} if defined(&{$caller . '::' . $name});
464             #warn "ugh $name ", $ugh if($ugh);
465 234         299 *{$caller . '::' . $name} = $exports{$name};
  234         2149  
466             }
467             } # end subroutine import definition
468             ########################################################################
469              
470             =head2 unimport
471              
472             $CAC->unimport;
473              
474             =cut
475              
476             sub unimport {
477 12     12   7726 my $package = shift;
478              
479 12         26 my $caller = caller();
480 12         38 my %exports = $package->exports;
481             #carp "unimport $caller";
482 12         90 foreach my $name (keys(%exports)) {
483 7     7   144 no strict 'refs';
  7         14  
  7         1483  
484 216 50       410 if(defined(&{$caller . '::' . $name})) {
  216         808  
485 216         377 delete(${$caller . '::'}{$name});
  216         17982  
486             }
487             }
488             } # end subroutine unimport definition
489             ########################################################################
490              
491              
492              
493             =head2 create_package
494              
495             Creates and returns the package in which the accessors will live. Also
496             pushes the created accessor package into the caller's @ISA.
497              
498             If it already exists, simply returns the cached value.
499              
500             my $package = $CAC->create_package(
501             class => $caller,
502             in => $package, # optional
503             );
504              
505             =cut
506              
507             {
508             my %package_map;
509             sub create_package {
510 37     37 1 58 my $this_package = shift;
511 37 50       116 (@_ % 2) and croak("odd number of elements in argument list");
512 37         143 my (%options) = @_;
513              
514 37 50       194 my $class = $options{class} or croak('no class?');
515 37 100       91 if(exists($package_map{$class})) {
516             # check for attempt to change package (not allowed)
517 26 50       59 if(exists($options{in})) {
518 0 0       0 ($package_map{$class} eq $options{in}) or die;
519             }
520 26         101 return($package_map{$class});
521             }
522              
523             # use a package that can't be stepped on unless they ask for one
524 11   33     99 my $package = $options{in} || $class . '::--accessors';
525 11         27 $package_map{$class} = $package;
526              
527 7     7   38 my $class_isa = do { no strict 'refs'; \@{"${class}::ISA"}; };
  7         11  
  7         1803  
  11         15  
  11         13  
  11         85  
528 0         0 push(@$class_isa, $package)
529 11 50       144 unless(grep({$_ eq $package} @$class_isa));
530 11         57 return($package);
531             } # end subroutine create_package definition
532             } # and closure
533             ########################################################################
534              
535             =head2 install_sub
536              
537             $CAC->install_sub($class, $name, $subref, $note);
538              
539             =cut
540              
541             sub install_sub {
542 98     98 1 122 my $package = shift;
543 98         161 my ($class, $name, $subref, $note) = @_;
544 98         167 my $fullname = $class . '::' . $name;
545 98 50       105 if(defined(&{$fullname})) {
  98         624  
546             # play nice with Module::Refresh and such?
547 0         0 my $lvl = 1;
548 0         0 while(defined(my $p = caller($lvl++))) {
549 0 0       0 if($p eq 'Module::Refresh') { $lvl = 0; last; }
  0         0  
  0         0  
550             }
551 0 0       0 $lvl and croak("$fullname is already defined");
552             }
553             {
554 7     7   55 no strict 'refs';
  7         23  
  7         17971  
  98         110  
555 98         109 *{$fullname} = $subref;
  98         541  
556             }
557 98 50       365 $package->annotate($class, $name, $note) if($note);
558 98         284 return($fullname);
559             } # end subroutine install_sub definition
560             ########################################################################
561              
562             =head2 annotate
563              
564             $CAC->annotate($class, $name, $note);
565              
566             =cut
567              
568             {
569             my %notes;
570             sub annotate {
571 99     99 1 131 my $package = shift;
572 99         144 my ($class, $name, $note) = @_;
573 99   100     272 $notes{$class} ||= {};
574 99         413 $notes{$class}{$name} = $note;
575             } # end subroutine annotate definition
576             ########################################################################
577              
578             =head2 get_notes
579              
580             my %notes = $CAC->get_notes;
581              
582             =cut
583              
584             sub get_notes {
585 1     1 1 3 my $package = shift;
586 1         5 return(%notes);
587             } # end subroutine get_notes definition
588             } # and closure
589             ########################################################################
590              
591             =head2 make_standards
592              
593             $CAC->make_standards($class, @list);
594              
595             =cut
596              
597             {
598             my %standards = (
599             'new' => sub {
600 14     14   19458 my $class = shift;
601 14 100       482 croak('odd number of elements in argument list') if(@_ % 2);
602 12         47 my $self = {@_};
603 9         71 bless($self, $class);
604 9         26 return($self);
605             }
606             );
607             sub make_standards {
608 7     7 1 13 my $package = shift;
609 7         17 my ($class, @list) = @_;
610 7 50       21 @list or croak("no list?");
611 7         16 foreach my $item (@list) {
612 7 50       27 my $subref = $standards{$item} or
613             croak("no standard method for '$item'");
614 7         30 $package->install_sub($class, $item, $subref, 'stock');
615             }
616             } # end subroutine make_standards definition
617             } # end closure
618             ########################################################################
619              
620             =head2 _getter
621              
622             Returns a compiled getter subref corresponding to whether or not the
623             class has a '--get' method.
624              
625             $CAC->_getter($class, $item);
626              
627             =cut
628              
629             sub _getter {
630 25     25   30 my $package = shift;
631 25         37 my ($class, $item, $opt) = @_;
632              
633 25         32 my $and = '';
634 25 100 66     70 if($opt and my $attr = $opt->{attrs}) {
635 1         3 $and = ' () ' . $attr;
636             }
637              
638 25 100       235 if($class->can('--get')) {
639 2         10 return $package->do_eval(
640             "sub$and {\$_[0]->\$\{\\'--get'\}('$item')}",
641             $item
642             );
643             }
644             else {
645 23         102 return $package->do_eval("sub$and {\$_[0]->{'$item'}}", $item);
646             }
647             } # end subroutine _getter definition
648             ########################################################################
649              
650             =head2 make_getters
651              
652             $CAC->make_getters($class, @list);
653              
654             =cut
655              
656             sub make_getters {
657 14     14 1 21 my $package = shift;
658 14         26 my ($class, @list) = @_;
659 14         23 foreach my $item (@list) {
660 24         61 my $subref = $package->_getter($class, $item);
661 24         89 $package->install_sub($class, $item, $subref, 'getter');
662             }
663             } # end subroutine make_getters definition
664             ########################################################################
665              
666             =head2 make_lv_getters
667              
668             $CAC->make_lv_getters($class, @list);
669              
670             =cut
671              
672             sub make_lv_getters {
673 1     1 1 3 my $package = shift;
674 1         2 my ($class, @list) = @_;
675              
676 1         1166 require attributes;
677 1         1698 foreach my $item (@list) {
678 1         13 my $subref = $package->_getter($class, $item, {attrs => ':lvalue'});
679 1         6 $package->install_sub($class, $item, $subref, 'getter');
680             }
681             } # end subroutine make_lv_getters definition
682             ########################################################################
683              
684             =head2 _setter
685              
686             Returns a compiled setter subref corresponding to whether or not the
687             class has a '--set' method.
688              
689             $CAC->_setter($class, $item);
690              
691             =cut
692              
693             sub _setter {
694 13     13   16 my $package = shift;
695 13         25 my ($class, $item, %args) = @_;
696              
697 13   100     49 my $before = $args{before} || '';
698              
699 13 100       75 if($class->can('--set')) {
700 1         5 return $package->do_eval(
701             'sub {my $self = shift; ' . $before .
702             q($self->${\'--set'}) . "('$item',\$_[0])}",
703             $item
704             );
705             }
706             else {
707 12         50 return $package->do_eval(
708             'sub {my $self = shift; ' . $before .
709             '$self'."->{'$item'} = \$_[0]}",
710             $item
711             );
712             }
713             } # end subroutine _setter definition
714             ########################################################################
715              
716             =head2 make_setters
717              
718             $CAC->make_setters($class, @list);
719              
720             =cut
721              
722             sub make_setters {
723 4     4 1 7 my $package = shift;
724 4         9 my ($class, @list) = @_;
725 4         7 foreach my $item (@list) {
726 8         21 my $subref = $package->_setter($class, $item);
727 8         32 $package->install_sub($class, 'set_' . $item, $subref, 'setter');
728             }
729             } # end subroutine make_setters definition
730             ########################################################################
731              
732             =head2 make_immutable
733              
734             Creates immutable (one-time-only) setters.
735              
736             CAC->make_immutable($class, @list);
737              
738             =cut
739              
740             sub make_immutable {
741 1     1 1 2 my $package = shift;
742 1         3 my ($class, @list) = @_;
743 1         2 foreach my $item (@list) {
744 1         4 my $check = 'exists($self->{' . $item . '}) and croak(' .
745             qq("$item is immutable") . ');';
746 1         5 my $subref = $package->_setter($class, $item, before => $check);
747 1         5 $package->install_sub($class, 'set_' . $item, $subref, 'immutable');
748             }
749             } # end subroutine make_immutable definition
750             ########################################################################
751              
752             =head2 make_secrets
753              
754             my @names = $CAC->make_secrets($class, @list);
755              
756             =cut
757              
758             sub make_secrets {
759 3     3 1 4 my $package = shift;
760 3         7 my ($class, @list) = @_;
761 3         6 my @names;
762 3         5 foreach my $item (@list) {
763 4         11 my $subref = $package->_setter($class, $item);
764 4         10 my $name = '--set_' . $item;
765 4         8 push(@names, $name);
766 4         11 $package->install_sub($class, $name, $subref, 'private');
767             }
768 3         11 return(@names);
769             } # end subroutine make_secrets definition
770             ########################################################################
771              
772             =head2 make_aliases
773              
774             Constructs 'get_' aliases for a @list of accessors.
775              
776             $CAC->make_aliases($class, @list);
777              
778             =cut
779              
780             sub make_aliases {
781 15     15 1 24 my $package = shift;
782 15         26 my ($class, @list) = @_;
783 15         26 foreach my $item (@list) {
784 25         87 my $subref = $package->do_eval("sub {\$_[0]->$item}", $item);
785 25         106 $package->install_sub($class, 'get_' . $item, $subref, "->$item");
786             }
787             } # end subroutine make_aliases definition
788             ########################################################################
789              
790             =head2 make_aka
791              
792             Create a list of alias methods which runtime refer to $realname.
793              
794             $CAC->make_aka($where, $realname, @aliases);
795              
796             =cut
797              
798             sub make_aka {
799 0     0 1 0 my $package = shift;
800 0         0 my ($class, $item, @aka) = @_;
801              
802 0         0 my $get_attr = attributes->can('get');
803 0         0 my $got = $class->can($item);
804 0 0 0     0 my $attr = (
805             $get_attr and $got and grep(/^lvalue$/, $get_attr->($got))
806             ) ? '() :lvalue' : '';
807 0         0 my $subref = $package->do_eval("sub $attr {\$_[0]->$item}", $item);
808 0         0 foreach my $aka (@aka) {
809 0         0 $package->install_sub($class, $aka, $subref, "->$item");
810             }
811             } # end subroutine make_aka definition
812             ########################################################################
813              
814             =head2 do_eval
815              
816             my $subref = $package->do_eval($string, @checks);
817              
818             =cut
819              
820             sub do_eval {
821 63     63 1 73 my $self = shift;
822 63         110 my ($string, @checks) = @_;
823 63         100 foreach my $check (@checks) {
824 63 50       311 ($check =~ m/^[a-z_][\w]*$/i) or croak("'$check' not a valid name");
825             }
826 63 50       5553 my $subref = eval($string);
  1         8  
  1         1135  
  1         7  
  1         2  
  1         6  
  1         5  
  1         1  
  1         8  
  2         1357  
  7         987  
  2         3  
  2         10  
  1         2  
  1         9  
  1         2  
  1         6  
  1         32  
  4         171  
  0         0  
  0         0  
  1         36  
  1         2  
  1         9  
  3         43  
  3         199  
  2         3  
  2         12  
827 63 50       171 $@ and croak("oops $@");
828 63         166 return($subref);
829             } # end subroutine do_eval definition
830             ########################################################################
831              
832             =head1 List Accessors
833              
834             =head2 make_array_method
835              
836             $CAC->make_array_method(
837             class => $class,
838             item => $name,
839             functions => [@functions],
840             secret => $bool,
841             );
842              
843             If secret is true, will return the list of names.
844              
845             =cut
846              
847             sub make_array_method {
848 5     5 1 459 my $package = shift;
849 11         2322 my %opts = @_;
850 5 100       20 my $class = $opts{class} or die;
851 5         556 my $item = $opts{item};
852 4         5 my @functions = @{$opts{functions}};
  6         85  
853 5         22 my %subs = $package->_get_array_subs($item);
854 7         1045 my @ret;
855 7 50       44 ($item =~ m/^[a-z_][\w]*$/i) or croak("'$item' not a valid name");
856 4         7 foreach my $f (@functions) {
857 9 50       23 my $str = $subs{$f} or croak("no such function $f");
858 9         10 my $name = $item;
859 9 100       20 unless($f eq 'get') {
860 5 100       15 $name = ($opts{secret} ? '--' : '') . $f . '_' . $item;
861 5 100       15 $opts{secret} and push(@ret, $name);
862             }
863 10 50 50     985 my $subref = eval($str);
    50 100        
    50 50        
    100          
864 11 50       25 $@ and croak("oops $@");
865 11 100       175 $package->install_sub($class, $name, $subref,
866             ($opts{secret} ? 'private ' : '') . "$f array");
867             }
868 5         30 return(@ret);
869             } # end subroutine make_array_method definition
870             ########################################################################
871              
872             =head2 _get_array_subs
873              
874             my %subs = $CAC->_get_array_subs($name);
875              
876             =cut
877              
878             sub _get_array_subs {
879 4     4   6 my $package = shift;
880 4         6 my ($item) = @_;
881              
882 4         6 my $s = '$_[0]';
883 4         73 my %subs = (
884             get => "sub {$s\->{$item} or return; \@{$s\->{$item}}}",
885             set => "sub {my \$self = shift;
886             \$self->{$item} ||= []; \@{\$self->{$item}} = (\@_)}",
887             inner => "sub {$s\->{$item}}",
888             add => "sub {my \$self = shift;
889             \$self->{$item} or Carp::croak(\"'$item' list is empty\");
890             push(\@{\$self->{$item}}, \@_);}",
891             'pop' => "sub {$s\->{$item} or
892             Carp::croak(\"'$item' list is empty\");
893             pop(\@{$s\->{$item}});}",
894             'shift' => "sub {$s\->{$item} or
895             Carp::croak(\"'$item' list is empty\");
896             shift(\@{$s\->{$item}});}",
897             'unshift' => "sub {my \$self = shift;
898             \$self->{$item} or Carp::croak(\"'$item' list is empty\");
899             unshift(\@{\$self->{$item}}, \@_);}",
900             );
901 6         90 return(%subs);
902             } # end subroutine _get_array_subs definition
903             ########################################################################
904              
905             =head1 Class Accessors
906              
907             =head2 make_class_data
908              
909             $CAC->make_class_data($mode, $class, $key, $value);
910              
911             If mode is 'rs', returns the secret setter name.
912              
913             =cut
914              
915             sub make_class_data {
916 10     10 1 147 my $package = shift;
917 10         20 my ($mode, $class, $key, $value) = @_;
918              
919             my $getsub = sub {
920 20     20   12414 my $self = shift;
921 20         107 return($value);
922 10         42 };
923             my $setsub = sub { # TODO should be like C.D.Inheritable?
924 10     10   2672 my $self = shift;
925 10         27 $value = shift;
926 10         40 };
927 11         156 $package->install_sub($class, $key, $getsub, 'class getter');
928 11 100       30 if($mode eq 'rw') {
    100          
929 4         14 $package->install_sub($class, 'set_' . $key, $setsub,
930             'class setter');
931             }
932             elsif($mode eq 'rs') {
933 4         10 my $name = '--set_' . $key;
934 4         10 $package->install_sub($class, $name, $setsub,
935             'private class setter');
936 4         16 return($name);
937             }
938             else {
939 3 50       7 ($mode eq 'ro') or die "no such mode '$mode'";
940             }
941 6         24 return;
942             } # end subroutine make_class_data definition
943             ########################################################################
944              
945             # TODO
946             # opt '+aliases';
947             # opts prefix => '_';
948             # $package->options
949              
950             =head1 AUTHOR
951              
952             Eric Wilhelm @
953              
954             http://scratchcomputing.com/
955              
956             =head1 BUGS
957              
958             If you found this module on CPAN, please report any bugs or feature
959             requests through the web interface at L. I will be
960             notified, and then you'll automatically be notified of progress on your
961             bug as I make changes.
962              
963             If you pulled this development version from my /svn/, please contact me
964             directly.
965              
966             =head1 COPYRIGHT
967              
968             Copyright (C) 2006-2007 Eric L. Wilhelm, All Rights Reserved.
969              
970             =head1 NO WARRANTY
971              
972             Absolutely, positively NO WARRANTY, neither express or implied, is
973             offered with this software. You use this software at your own risk. In
974             case of loss, no person or entity owes you anything whatseover. You
975             have been warned.
976              
977             =head1 LICENSE
978              
979             This program is free software; you can redistribute it and/or modify it
980             under the same terms as Perl itself.
981              
982             =cut
983              
984             # vi:ts=2:sw=2:et:sta
985             1;