File Coverage

blib/lib/Class/AutoClass.pm
Criterion Covered Total %
statement 452 484 93.3
branch 148 182 81.3
condition 51 112 45.5
subroutine 71 72 98.6
pod 5 29 17.2
total 727 879 82.7


line stmt bran cond sub pod time code
1             package Class::AutoClass;
2             our $VERSION = '1.56';
3             $VERSION=eval $VERSION; # I think this is the accepted idiom..
4              
5 37     37   456865 use strict;
  37         84  
  37         1324  
6 37     37   201 use Carp;
  37         64  
  37         3639  
7 37     37   73765 use Storable qw(dclone);
  37         175835  
  37         3831  
8 37     37   69298 use Hash::AutoHash::Args qw(fix_keyword fix_keywords);
  37         649246  
  37         919  
9 37     37   42743 use Class::AutoClass::Root;
  37         377  
  37         2532  
10 37     37   268 use base qw(Class::AutoClass::Root);
  37         61  
  37         4903  
11              
12 37     37   1486 use vars qw($AUTOCLASS $AUTODB %CACHE @EXPORT);
  37         67  
  37         86468  
13             $AUTOCLASS = __PACKAGE__;
14              
15             sub new {
16             # NG 09-11-07: when called 'from below' via SUPER::new, respect existing object
17 609     609 1 1619668 my ( $self_or_class, @args ) = @_;
18 609   66     6323 my $class = ( ref $self_or_class ) || $self_or_class;
19             # NG 06-02-03: 1st attempt to call declare at runtime if not declared at compile-time
20             # declare($class) unless $class->DECLARED;
21             # NG 06-02-03: 2nd attempt to declare at runtime if not declared at compile-time
22             # include $case and flag to indicate this is runtime
23 609 100       5021 declare($class,CASE($class),'runtime') unless $class->DECLARED;
24              
25 609   50     4435 my $classes = $class->ANCESTORS || []; # NG 04-12-03. In case declare not called
26 609         3356 my $can_new = $class->CAN_NEW;
27 609 100       1762 if ( !@$classes ) { # compute on the fly for backwards compatibility
28             # enumerate internal super-classes and find a class to create object
29 20         67 ( $classes, $can_new ) = _enumerate($class);
30             }
31             # NG 09-11-07: when called 'from below' via SUPER::new, respect existing object
32 609         778 my $self;
33 609 100       2219 if (ref $self_or_class) {
34 100         233 $self=$self_or_class;
35             } else {
36 509 100       1452 $self = $can_new ? $can_new->new(@args) : {};
37 509         2144 bless $self, $class; # Rebless what comes from new just in case
38             }
39 609         2944 my $args = new Hash::AutoHash::Args(@args);
40             # NG 09-03-19: put defaults processing under 'if' since rarely used
41             # minor efficiency gain (avoids creation of empty Args object)
42 609 50       41920 if ($args->defaults) {
43 0         0 my $defaults = new Hash::AutoHash::Args( $args->defaults );
44             # set arg defaults into args
45 0         0 while ( my ( $keyword, $value ) = each %$defaults ) {
46 0 0       0 $args->{$keyword} = $value unless exists $args->{$keyword};
47             }}
48              
49             ################################################################################
50             # NG 05-12-08: initialization strategy changed. instead of init'ing class by class
51             # down the hierarchy, it's now done all at once.
52 609         34806 $self->_init($class,$args); # init attributes from args and defaults
53              
54             # $defaults=new Hash::AutoHash::Args; # NG 05-12-07: reset $defaults.
55             # # will accumulate instance defaults during initialization
56             # my $default2code={};
57              
58 609         4557 for my $class (@$classes) {
59 1943         18946 my $init_self = $class->can('_init_self');
60 1943 100       9465 $self->$init_self( $class, $args ) if $init_self;
61             # NG 10-08-22: moved test for OVERRIDE to here to fix bug in which subsequent
62             # calls to _init_self continue to operate on original $self !
63 1943 100       23182 $self=$self->{__OVERRIDE__} if $self->{__OVERRIDE__};
64             # $self->_init( $class, $args, $defaults, $default2code );
65             }
66             ################################################################################
67              
68 609 100       1750 if($self->{__NULLIFY__}) {
69 1         4 return undef;
70             # NG 10-08-22: moved test for OVERRIDE to here to fix bug in which subsequent
71             # calls to _init_self continue to operate on original $self !
72             # } elsif ($self->{__OVERRIDE__}) { # override self with the passed object
73             # $self=$self->{__OVERRIDE__};
74             # return $self;
75             } else {
76 608         2848 return $self;
77             }
78             }
79              
80             ################################################################################
81             # NG 05-12-08: initialization strategy changed. instead of init'ing class by class
82             # down the hierarchy, it's now done all at once.
83             sub _init {
84 609     609   2416 my($self,$class,$args)=@_;
85 609         1430 my @attributes=ATTRIBUTES_RECURSIVE($class);
86 609         1777 my $defaults=DEFAULTS_RECURSIVE($class); # Args object
87 609         1503 my %fixed_attributes=FIXED_ATTRIBUTES_RECURSIVE($class);
88 609         1512 my %synonyms=SYNONYMS_RECURSIVE($class);
89 609         1422 my %reverse=SYNONYMS_REVERSE($class); # reverse of SYNONYMS_RECURSIVE
90 609         1485 my %cattributes=CATTRIBUTES_RECURSIVE($class);
91 609         1231 my @cattributes=keys %cattributes;
92 609         1823 my %iattributes=IATTRIBUTES_RECURSIVE($class);
93 609         1660 my @iattributes=keys %iattributes;
94 609         1285 for my $func (@cattributes) { # class attributes
95 379         5770 my $fixed_func=$fixed_attributes{$func};
96 379 100       1808 next unless exists $args->{$fixed_func};
97             # no strict 'refs';
98             # next unless ref $self eq $class;
99 97         4905 $class->$func($args->{$fixed_func});
100             }
101             # NG 08-03-21: moved default processing to separate loop before arg processing to fix bug.
102             # Bug: if attribute early in @iattributes sets attribute that comes later,
103             # and later attribute has default, default clobbers value previously set!!
104 609         4460 for my $fixed_func (keys %$defaults) {
105             # NG 09-04-22: skip class attributes. defaults should only be set at declare-time
106 678 100       3239 next if $cattributes{$fixed_func};
107            
108             # because of synonyms, this is more complicated than it might appear.
109             # there are 4 cases: consider syn=>real
110             # 1) args sets syn, defaults sets syn
111             # 2) args sets real, defaults sets syn
112             # 3) args sets syn, defaults sets real
113             # 4) args sets real, defaults sets real
114 525 100       2697 next if exists $args->{$fixed_func}; # handles cases 1,4 plus case of not synonym
115 421         7805 my $real=$synonyms{$fixed_func};
116 421 100 100     1319 next if $real && exists $args->{$fixed_attributes{$real}}; # case 2
117 418         1245 my $syn_list=$reverse{$fixed_func};
118 51         285 next if $syn_list &&
119 418 100 100     1165 grep {exists $args->{$fixed_attributes{$_}}} @$syn_list; # case 3
120             # okay to set default!!
121 414         1449 my $value=$defaults->{$fixed_func};
122             # NG 10-01-06: allow CODE and GLOB defaults. dclone can't copy these...
123             # deep copy other refs so each instance has own copy
124 414         419 my $copy;
125 414 100       773 if (ref $value) {
126 13         17 $copy=eval{dclone($value)};
  13         607  
127 13 100       140 $value=$copy unless $@; # use $copy unless dclone failed
128             }
129             # $value=ref $value? dclone($value): $value;
130 414         18612 $self->$fixed_func($value);
131             }
132              
133 609         2581 for my $func (@iattributes) { # instance attributes
134 1637         30653 my $fixed_func=$fixed_attributes{$func};
135 1637 100       5898 if (exists $args->{$fixed_func}) {
136 411         16093 $self->$func( $args->{$fixed_func} );
137             # } elsif (exists $defaults->{$fixed_func}) {
138             # # because of synonyms, this is more complicated than it might appear.
139             # # there are 4 cases: consider syn=>real
140             # # 1) args sets syn, defaults sets syn
141             # # 2) args sets real, defaults sets syn
142             # # 3) args sets syn, defaults sets real
143             # # 4) args sets real, defaults sets real
144             # next if exists $args->{$fixed_func}; # handles cases 1,4 plus case of not synonym
145             # my $real=$synonyms{$func};
146             # next if $real && exists $args->{$fixed_attributes{$real}}; # case 2
147             # my $syn_list=$reverse{$func};
148             # next if $syn_list &&
149             # grep {exists $args->{$fixed_attributes{$_}}} @$syn_list; # case 3
150             # # okay to set default!!
151             # my $value=$defaults->{$fixed_func};
152             # $value=ref $value? dclone($value): $value; # deep copy refs so each instance has own copy
153             # $self->$func($value);
154             }
155             }
156             }
157              
158             ########################################
159              
160             #sub _init {
161             # my ( $self, $class, $args, $defaults, $default2code ) = @_;
162             # my %synonyms = SYNONYMS($class);
163             # my $attributes = ATTRIBUTES($class);
164             # # only object methods here
165             # $self->set_instance_defaults( $args, $defaults, $default2code, $class ); # NG 05-12-07
166             # $self->set_attributes( $attributes, $args, $defaults, $default2code, $class ); # NG 05-12-07
167             # my $init_self = $class->can('_init_self');
168             # $self->$init_self( $class, $args ) if $init_self;
169             #}
170              
171             sub set {
172 14     14 1 602 my $self = shift;
173 14         47 my $args = new Hash::AutoHash::Args(@_);
174 14         1076 while ( my ( $key, $value ) = each %$args ) {
175 42         1073 my $func = $self->can($key);
176 42 50       990 $self->$func($value) if $func;
177             }
178             }
179              
180             sub get {
181 219     219 1 615192 my $self = shift;
182 219         877 my @keys = fix_keyword(@_);
183 219         16479 my @results;
184 219         1063 for my $key (@keys) {
185 2942         7581 my $func = $self->can($key);
186 2942 50       65326 my $result = $func ? $self->$func() : undef;
187 2942         7464 push( @results, $result );
188             }
189 219 100       2615 wantarray ? @results : $results[0];
190             }
191              
192             ########################################
193             # NG 05-12-09: changed to always call method. previous version just stored
194             # value for class attributes.
195             # note: this is user level method -- not just internal!!!
196             sub set_attributes {
197 13     13 1 6301 my ( $self, $attributes, $args ) = @_;
198 13         22 my $class=ref $self;
199 13 50       43 $self->throw('Atrribute list must be an array ref') unless ref $attributes eq 'ARRAY';
200             # NG 09-03-19: fix_keywords now handled by Args tied hash
201             # my @attributes=fix_keyword(@$attributes);
202 13         22 for my $func (@$attributes) {
203 36 100 66     543 next unless exists $args->{$func} && $class->can($func);
204 32         1475 $self->$func( $args->{$func} );
205             }
206             }
207              
208             ## NG 05-12-07: process defaults. $defaults contains defaults seen so far in the
209             # # recursive initialization process that are NOT in $args. As we descend, also
210             # # have to check synonyms:
211             # @keywords=$class->ATTRIBUTES_RECURSIVE;
212             # for my $func (@keywords) {
213             # next unless exists $defaults->{$func};
214             # my $code=$class->can($func);
215             # next if $default2code->{$func} == $code;
216             # $self->$func($defaults->{$func});
217             # $default2code->{$func}=$code;
218             # }
219             ## for my $func (keys %$defaults) {
220             ## next if !$class->can($func);
221             ## $self->$func($defaults->{$func});
222             ## delete $defaults->{$func};
223             ## }
224             #}
225              
226             ## sets default attributes on a newly created instance
227             ## NG 05-12-07: changed to accumulate defaults in $defaults. setting done in set_attributes.
228             ## previous version set values directly into object HASH. this is wrong, since
229             ## it skips the important step of running the attribute's 'set' method.
230             #sub set_instance_defaults {
231             # my ( $self, $args, $defaults, $default2code, $class ) = @_;
232             # my %class_funcs;
233             # my $class_defaults = DEFAULTS($class);
234             # map { $class_funcs{$_}++ } CLASS_ATTRIBUTES($class);
235             # while ( my ( $key, $value ) = each %$class_defaults ) {
236             # next if exists $class_funcs{$key} || exists $args->{$key};
237             # $defaults->{$key} = ref $value? dclone($value): $value; # deep copy refs;
238             # delete $default2code->{$key}; # NG 05-12-07: so new default will be set
239             # }
240             #}
241              
242             ########################################
243             # NG 05-12-09: rewrote to use CATTRIBUTES_RECURSIVE. also changed to always call
244             # method. previous version just stored values
245             # sets class defaults at "declare time"
246             sub set_class_defaults {
247 556     556 0 781 my ( $class ) = @_;
248 556         970 my $defaults = DEFAULTS_RECURSIVE($class); # Args object
249 556         1195 my %fixed_attributes=FIXED_ATTRIBUTES_RECURSIVE($class);
250 556         1348 my %cattributes=CATTRIBUTES_RECURSIVE($class);
251 556         1054 my @cattributes=keys %cattributes;
252 556         1575 for my $func (@cattributes) { # class attributes
253 258         383 my $fixed_func=$fixed_attributes{$func};
254 258 100       1374 next unless exists $defaults->{$fixed_func};
255 71         179 my $value=$defaults->{$fixed_func};
256             # NG 06-02-03. vcassen observed that dclone not needed here since there
257             # can only be one copy of each class attribute
258             # $value=ref $value? dclone($value): $value; # deep copy refs so each instance has own copy
259 71         2045 $class->$func($value);
260             }
261             }
262             ########################################
263             # NG 09-11-12: removed this sub, since it pollutes namespace unreasonably
264             # also changed all uses, of course. here and in AutoDB
265             # sub class { ref $_[0]; }
266              
267             sub ISA {
268 1116     1116 0 4184 my ($class) = @_;
269 1116   33     4836 $class = (ref $class) || $class; # get class if called as object method
270 37     37   561 no strict 'refs';
  37         97  
  37         3384  
271 1116         1245 @{ $class . '::ISA' };
  1116         5718  
272             }
273              
274             sub AUTO_ATTRIBUTES {
275 1113     1113 0 1904 my ($class) = @_;
276 1113   33     4030 $class = (ref $class) || $class; # get class if called as object method
277 37     37   195 no strict 'refs';
  37         65  
  37         2971  
278 1113         1557 @{ $class . '::AUTO_ATTRIBUTES' };
  1113         5967  
279             }
280              
281             sub OTHER_ATTRIBUTES {
282 557     557 0 2301 my ($class) = @_;
283 557   33     2113 $class = (ref $class) || $class; # get class if called as object method
284 37     37   195 no strict 'refs';
  37         78  
  37         2544  
285 557         800 @{ $class . '::OTHER_ATTRIBUTES' };
  557         2700  
286             }
287              
288             sub CLASS_ATTRIBUTES {
289 1113     1113 0 1639 my ($class) = @_;
290 37     37   185 no strict 'refs';
  37         84  
  37         997  
291 37     37   252 no warnings; # supress unitialized var warning
  37         90  
  37         4212  
292 1113         1243 @{ $class . '::CLASS_ATTRIBUTES' };
  1113         5320  
293             }
294              
295             sub SYNONYMS {
296 557     557 0 1086 my ($class) = @_;
297 557   33     2514 $class = (ref $class) || $class; # get class if called as object method
298 37     37   211 no strict 'refs';
  37         73  
  37         3420  
299 557         726 %{ $class . '::SYNONYMS' };
  557         3521  
300             }
301             sub SYNONYMS_RECURSIVE {
302 1782     1782 0 8801 my $class = shift @_;
303 1782   33     8436 $class = (ref $class) || $class; # get class if called as object method
304 37     37   194 no strict 'refs';
  37         83  
  37         7938  
305 1782         2115 my %synonyms;
306 1782 100       3849 if (@_) {
307 76         117 %synonyms=%{ $class . '::SYNONYMS_RECURSIVE' } = @_;
  76         767  
308 76         108 my %reverse;
309 76         292 while(my($syn,$real)=each %synonyms) {
310 261   100     1101 my $list=$reverse{$real} || ($reverse{$real}=[]);
311 261         1031 push(@$list,$syn);
312             }
313 76         262 SYNONYMS_REVERSE($class, %reverse);
314             } else {
315 1706         2003 %synonyms=%{ $class . '::SYNONYMS_RECURSIVE' };
  1706         7802  
316             }
317 1782 100       5762 wantarray? %synonyms: \%synonyms;
318             }
319             sub SYNONYMS_REVERSE { # reverse of SYNONYMS_RECURSIVE. used to set instance defaults
320 685     685 0 1077 my $class = shift @_;
321 685   33     2425 $class = (ref $class) || $class; # get class if called as object method
322 37     37   243 no strict 'refs';
  37         85  
  37         4335  
323 76         708 my %synonyms=@_ ? %{ $class . '::SYNONYMS_REVERSE' } = @_:
  609         4257  
324 685 100       1500 %{ $class . '::SYNONYMS_REVERSE' };
325 685 100       2794 wantarray? %synonyms: \%synonyms;
326             }
327             # ATTRIBUTES -- all attributes
328             sub ATTRIBUTES {
329 557     557 0 1042 my $class = shift @_;
330 557   33     2700 $class = (ref $class) || $class; # get class if called as object method
331 37     37   198 no strict 'refs';
  37         107  
  37         4587  
332 557 100       1234 my @attributes=@_ ? @{ $class . '::ATTRIBUTES' } = @_ : @{ $class . '::ATTRIBUTES' };
  85         642  
  472         3369  
333 557 50       1726 wantarray? @attributes: \@attributes;
334             }
335             sub ATTRIBUTES_RECURSIVE {
336 1782     1782 0 2911 my $class = shift @_;
337 1782   33     6377 $class = (ref $class) || $class; # get class if called as object method
338 37     37   200 no strict 'refs';
  37         86  
  37         6312  
339 84     84   117 sub _uniq {my %h; @h{@_}=@_; values %h;}
  84         760  
  84         605  
340 84         990 my @attributes=@_ ? @{ $class . '::ATTRIBUTES_RECURSIVE' } = _uniq(@_):
  1698         8358  
341 1782 100       4204 @{ $class . '::ATTRIBUTES_RECURSIVE' };
342 1782 100       6407 wantarray? @attributes: \@attributes;
343             }
344             # maps attributes to fixed (ie, de-cased) attributes. use when initializing attributes
345             # to args or defaults
346             sub FIXED_ATTRIBUTES_RECURSIVE {
347 1721     1721 0 4308 my $class = shift @_;
348 1721   33     15013 $class = (ref $class) || $class; # get class if called as object method
349 37     37   204 no strict 'refs';
  37         66  
  37         4440  
350 84         1809 my %attributes=@_ ? %{ $class . '::FIXED_ATTRIBUTES_RECURSIVE' } = @_:
  1637         10483  
351 1721 100       5148 %{ $class . '::FIXED_ATTRIBUTES_RECURSIVE' };
352 1721 100       7707 wantarray? %attributes: \%attributes;
353             }
354             # IATTRIBUTES -- instance attributes -- hash
355             sub IATTRIBUTES {
356 1113     1113 0 1888 my $class = shift @_;
357 1113   33     4415 $class = (ref $class) || $class; # get class if called as object method
358 37     37   358 no strict 'refs';
  37         75  
  37         4581  
359 1113 100       2270 my %attributes=@_ ? %{ $class . '::IATTRIBUTES' } = @_ : %{ $class . '::IATTRIBUTES' };
  80         737  
  1033         5331  
360 1113 100       3857 wantarray? %attributes: \%attributes;
361             }
362             sub IATTRIBUTES_RECURSIVE {
363 1782     1782 0 4601 my $class = shift @_;
364 1782   33     6022 $class = (ref $class) || $class; # get class if called as object method
365 37     37   190 no strict 'refs';
  37         71  
  37         4286  
366 84         1373 my %attributes=@_ ? %{ $class . '::IATTRIBUTES_RECURSIVE' } = @_:
  1698         9136  
367 1782 100       3480 %{ $class . '::IATTRIBUTES_RECURSIVE' };
368 1782 100       6794 wantarray? %attributes: \%attributes;
369             }
370             # CATTRIBUTES -- class attributes -- hash
371              
372             # NG 05-12-08: commented out. DEFAULTS_ARGS renamed to DEFAULTS
373             #sub DEFAULTS {
374             # my ($class) = @_;
375             # $class = (ref $class) || $class; # get class if called as object method
376             # no strict 'refs';
377             # %{ $class . '::DEFAULTS' };
378             #}
379             sub CATTRIBUTES {
380 557     557 0 1608 my $class = shift @_;
381 557   33     2363 $class = (ref $class) || $class; # get class if called as object method
382 37     37   215 no strict 'refs';
  37         63  
  37         4002  
383 557 100       1246 my %attributes=@_ ? %{ $class . '::CATTRIBUTES' } = @_ : %{ $class . '::CATTRIBUTES' };
  81         573  
  476         2828  
384 557 50       1557 wantarray? %attributes: \%attributes;
385             }
386             sub CATTRIBUTES_RECURSIVE {
387 2338     2338 0 3742 my $class = shift @_;
388 2338   33     9771 $class = (ref $class) || $class; # get class if called as object method
389 37     37   210 no strict 'refs';
  37         73  
  37         3979  
390 80         708 my %attributes=@_ ? %{ $class . '::CATTRIBUTES_RECURSIVE' } = @_:
  2258         17463  
391 2338 100       4632 %{ $class . '::CATTRIBUTES_RECURSIVE' };
392 2338 100       9072 wantarray? %attributes: \%attributes;
393             }
394             # NG 05-12-08: DEFAULTS_ARGS renamed to DEFAULTS.
395             # incorporates logic to convert %DEFAULTS to Args object
396             sub DEFAULTS {
397 558     558 0 966 my $class = shift @_;
398 558   33     3454 $class = (ref $class) || $class; # get class if called as object method
399 37     37   197 no strict 'refs';
  37         89  
  37         5301  
400 556         31152 ${ $class . '::DEFAULTS_ARGS' } or
  558         3852  
401 558 100       666 ${ $class . '::DEFAULTS_ARGS' } = new Hash::AutoHash::Args(%{ $class . '::DEFAULTS' }); # convert DEFAULTS hash into AutoArgs
  556         5611  
402             }
403             sub DEFAULTS_RECURSIVE {
404 2338     2338 0 4506 my $class = shift @_;
405 2338   33     9800 $class = (ref $class) || $class; # get class if called as object method
406 37     37   203 no strict 'refs';
  37         84  
  37         4293  
407 556         2979 my $defaults=@_ ? ${ $class . '::DEFAULTS_RECURSIVE' } = $_[0]:
  1782         6108  
408 2338 100       5532 ${ $class . '::DEFAULTS_RECURSIVE' };
409 2338 50       6103 wantarray? %$defaults: $defaults;
410             }
411             # NG 06-03-14: Used to save $case from compile-time declare for use by run-time declare
412             sub CASE {
413 881     881 0 1545 my $class = shift @_;
414 881   33     3514 $class = (ref $class) || $class; # get class if called as object method
415 37     37   190 no strict 'refs';
  37         77  
  37         3557  
416 881 50       1799 my $case=@_ ? $ { $class . '::CASE' } = $_[0] : $ { $class . '::CASE' };
  0         0  
  881         6330  
417 881         2261 $case;
418             }
419             sub AUTODB {
420 559     559 0 1125 my ($class) = @_;
421 559   33     2159 $class = (ref $class) || $class; # get class if called as object method
422 37     37   831 no strict 'refs';
  37         89  
  37         3304  
423 559         856 %{ $class . '::AUTODB' };
  559         4235  
424             }
425              
426             sub ANCESTORS {
427 1165     1165 0 1983 my $class = shift @_;
428 1165   33     4279 $class = (ref $class) || $class; # get class if called as object method
429 37     37   375 no strict 'refs';
  37         76  
  37         9030  
430 1165 100       2756 @_ ? ${ $class . '::ANCESTORS' } = $_[0] : ${ $class . '::ANCESTORS' };
  556         5115  
  609         3710  
431             }
432              
433             sub CAN_NEW {
434 1165     1165 0 1958 my $class = shift @_;
435 1165   33     4457 $class = (ref $class) || $class; # get class if called as object method
436 37     37   196 no strict 'refs';
  37         62  
  37         3730  
437 1165 100       2421 @_ ? ${ $class . '::CAN_NEW' } = $_[0] : ${ $class . '::CAN_NEW' };
  556         3641  
  609         2273  
438             }
439              
440             sub FORCE_NEW {
441 2131     2131 0 4888 my $class = shift @_;
442 2131   33     9304 $class = (ref $class) || $class; # get class if called as object method
443 37     37   210 no strict 'refs';
  37         104  
  37         2886  
444 2131         2227 ${ $class . '::FORCE_NEW' };
  2131         23518  
445             }
446             sub DECLARED { # set to 1 by declare. tested in new
447 1947     1947 0 3986 my $class = shift @_;
448 1947   33     8067 $class = (ref $class) || $class; # get class if called as object method
449 37     37   234 no strict 'refs';
  37         68  
  37         3215  
450 1947 100       4591 @_ ? ${ $class . '::DECLARED' } = $_[0] : ${ $class . '::DECLARED' };
  634         3021  
  1313         7861  
451             }
452             sub AUTOCLASS_DEFERRED_DECLARE {
453 558     558 0 965 my $class = shift @_;
454 558   33     2228 $class = (ref $class) || $class; # get class if called as object method
455 37     37   194 no strict 'refs';
  37         59  
  37         7772  
456 558 100       1264 ${ $class . '::AUTOCLASS_DEFERRED_DECLARE' }{$_[0]}=$_[0] if @_;
  2         9  
457             # push(@{ $class . '::AUTOCLASS_DEFERRED_DECLARE' }, @_) if @_;
458             # @{ $class . '::AUTOCLASS_DEFERRED_DECLARE' };
459 558         628 keys %{ $class . '::AUTOCLASS_DEFERRED_DECLARE' };
  558         3860  
460             }
461             sub declare {
462 559     559 1 693850 my ( $class, $case, $is_runtime ) = @_;
463 559 100       2136 $class or $class=caller; # NG 09-11-02: make $class optional
464              
465             # NG 06-03-18: improved code to recognize that user can set $CASE in module
466             # this is first step toward deprecating this parameter
467 559 50       1307 if (defined $case) {
468 0         0 CASE($class,$case); # save $case for run-time
469             } else {
470 559         1141 $case=CASE($class); # else, set $case from $CASE
471             }
472             ########################################
473             # NG 05-12-08,09: added code to compute RECURSIVE values, IATTRIBUTES, CATTRIBUTES
474 559         991 my @attributes_recursive;
475             my %iattributes_recursive;
476 0         0 my %cattributes_recursive;
477 0         0 my %synonyms_recursive;
478 0         0 my $defaults_recursive;
479             # get info from superclasses. recursively, this includes all ancestors
480             # NG 06-03-14: split loop to get all supers that are AutoClasses
481             # and make sure they are declared. If any not declared,
482             # have to defer this declaration to run-time
483 0         0 my $defer;
484 559         1600 for my $super (ISA($class)) {
485 899 100       2434 next if $super eq 'Class::AutoClass';
486             ####################
487             # NG 05-12-09: added check for super classes not yet used
488             # Caution: this all works fine if people follow the Perl convention of
489             # placing module Foo in file Foo.pm. Else, there's no easy way to
490             # translate a classname into a string that can be 'used'
491             # The test 'unless %{$class.'::'}' cause the 'use' to be skipped if
492             # the class is already loaded. This should reduce the opportunities
493             # for messing up the class-to-file translation.
494             # Note that %{$super.'::'} is the symbol table for the class
495            
496             # NG 09-01-14: fixed dumb ass bug: the eval "use..." below is, of course, not run
497             # if the class is already loaded. This means that the value of $@ is not reset
498             # by the eval. So, if it had a true value before the eval, it will have the
499             # same value afterwards causing the error code to be run!
500             # FIX: changed "use" to "require" (which returns true on success) and use the
501             # return value to control whether error code run
502 37     37   394 { no strict 'refs';
  37         91  
  37         8352  
  698         880  
503 698 100       828 unless (%{$super.'::'}) {
  698         5000  
504 3 50       142 eval "require $super" or
505             confess "'use $super' failed while declaring class $class. Note that class $super is listed in \@ISA for class $class, but is not explicitly used in the code. We suggest, as a matter of coding style, that classes listed in \@ISA be explicitly used";
506             }}
507             # next unless UNIVERSAL::isa($super,'Class::AutoClass');
508             # NG 06-03-14: handle different cases of $super being declared
509             # at runtime, okay to declare $super now since entire module
510             # has been parsed.
511             # at compile time, there is no guarantee that AutoClass variables
512             # have yet been parsed. so, we defer declaration of current class
513             # until $super is declared. CAUTION: this writes into $super's
514             # namespace which is rude if $super is not an AutoClass class !!!
515 698 100       2882 if (!DECLARED($super)) {
516 80 100       324 if ($is_runtime) {
517 78 50       611 if (UNIVERSAL::isa($super,'Class::AutoClass')) {
518 0         0 declare($super,CASE($class),$is_runtime);
519             } else { # not AutoClass class, so just call it declared
520 78         175 DECLARED($class,1);
521             }
522             } else {
523 2         4 AUTOCLASS_DEFERRED_DECLARE($super,$class); # push class onto super's deferred list
524 2         5 $defer=1; # causes return before loop that does the work
525             }
526             }
527             }
528             # NG 06-03-14: AutoDB registration must be done at compile-time. if this code get
529             # moved later, remember that hacking of @ISA has to happen before class
530             # hierarchy enumerated
531 559         1750 my %autodb = AUTODB($class);
532 559 50       1539 if (%autodb) {
533 37     37   208 no strict 'refs';
  37         69  
  37         74254  
534             # add AutoDB::Object to @ISA if necessary
535 0 0       0 unless ( grep /^Class::AutoDB::Object/, @{ $class . '::ISA' } ) {
  0         0  
536 0         0 unshift @{ $class . '::ISA' }, 'Class::AutoDB::Object';
  0         0  
537             # NG 10-09-16: I thought it work work to push Object onto end of @ISA instead of
538             # unshifting it onto front to reduce impact of namespace pollution.
539             # It does that okay, but introduces a new bug: oid generation and
540             # all that is doen by Serialize which is a base class of Object. In
541             # old implementation, that happened early; in new implementation, it
542             # happens late. Screws up a lot of things.:(
543             # Back to the dawing boards...
544             # push @{ $class . '::ISA' }, 'Class::AutoDB::Object';
545             }
546 0         0 require 'Class/AutoDB/Object.pm';
547 0         0 require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
548             }
549             # NG 05-12-02: auto-register subclasses which do not set %AUTODB
550             # if (%autodb) { # register after setting ANCESTORS
551 559 50       4395 if (UNIVERSAL::isa($class,'Class::AutoDB::Object')) {
552 0         0 require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
553             # NG 09-12-04: handle %AUTODB=0. (any single false value)
554             # explicitly handle %AUTODB=1. previous version worked 'by luck' :)
555 0 0 0     0 confess "Illegal form of \%AUTODB. \%AUTODB= reserved for future use"
556             if (scalar(keys %autodb)==1) && !(keys %autodb)[0];
557 0         0 delete $autodb{1}; # delete '1=>anything' if it exists
558 0         0 my $args = Hash::AutoHash::Args->new( %autodb, -class => $class );
559 0         0 Class::AutoDB::auto_register($args);
560             }
561            
562 559 100       2920 return if $defer;
563             # NG 06-03-14: this part of the loop does the work
564 557         1349 for my $super (ISA($class)) {
565 896 100 100     7643 next if $super eq 'Class::AutoClass' || !UNIVERSAL::isa($super,'Class::AutoClass');
566 617         1392 push(@attributes_recursive,ATTRIBUTES_RECURSIVE($super));
567 617         887 my %h;
568 617         1613 %h=IATTRIBUTES_RECURSIVE($super);
569 617         1685 @iattributes_recursive{keys %h}=values %h;
570 617         1487 undef %h;
571 617         1242 %h=CATTRIBUTES_RECURSIVE($super);
572 617         9703 @cattributes_recursive{keys %h}=values %h;
573 617         1036 undef %h;
574 617         1262 %h=SYNONYMS_RECURSIVE($super);
575 617         1695 @synonyms_recursive{keys %h}=values %h;
576 617         1211 my $d=DEFAULTS_RECURSIVE($super);
577 617         2946 @$defaults_recursive{keys %$d}=values %$d;
578             }
579              
580             # add info from self. do this after parents so our defaults, synonyms override parents
581             # for IATTRIBUTES, don't add in any that are already defined, since this just creates
582             # redundant methods
583 557         1691 my %synonyms = SYNONYMS($class);
584 557         832 my %iattributes;
585             my %cattributes;
586             # init cattributes to declared CLASS_ATTRIBUTES
587 557         1259 map {$cattributes{$_}=$class} CLASS_ATTRIBUTES($class);
  108         339  
588             # iattributes = all attributes that are not cattributes
589 557 100 66     1323 map {$iattributes{$_}=$class unless $iattributes_recursive{$_} || $cattributes{$_}}
  303         2046  
590             (AUTO_ATTRIBUTES($class),OTHER_ATTRIBUTES($class));
591             # add in synonyms
592 557         2539 while(my($syn,$real)=each %synonyms) {
593 93 50 33     273 confess "Inconsistent declaration for attribute $syn: both synonym and real attribute"
594             if $cattributes{$syn} && $iattributes{$syn};
595 93 50 33     436 $cattributes{$syn}=$class if $cattributes{$real} || $cattributes_recursive{$real};
596 93 50 66     639 $iattributes{$syn}=$class if $iattributes{$real} || $iattributes_recursive{$real};
597             }
598 557         1860 IATTRIBUTES($class,%iattributes);
599 557         1833 CATTRIBUTES($class,%cattributes);
600 557         1806 ATTRIBUTES($class,keys %iattributes,keys %cattributes);
601              
602             # store our attributes into recursives
603 557         1576 @iattributes_recursive{keys %iattributes}=values %iattributes;
604 557         1283 @cattributes_recursive{keys %cattributes}=values %cattributes;
605 557         976 push(@attributes_recursive,keys %iattributes,keys %cattributes);
606             # are all these declarations consistent?
607 557 100       2001 if (my @inconsistents=grep {exists $cattributes_recursive{$_}} keys %iattributes_recursive) {
  1088         1957  
608             # inconsistent class vs. instance declarations
609 1         8 my @errstr=("Inconsistent declarations for attribute(s) @inconsistents");
610 2         8 map {
611 1         3 push(@errstr,
612             "\tAttribute $_: declared instance attribute in $iattributes_recursive{$_}, class attribute in $cattributes_recursive{$_}");
613             } @inconsistents;
614 1         464 confess join("\n",@errstr);
615             }
616             # store our synonyms into recursive
617 556         1011 @synonyms_recursive{keys %synonyms}=values %synonyms;
618             # store our defaults into recursive
619              
620 556         1226 my $d=DEFAULTS($class);
621 556         3466 @$defaults_recursive{keys %$d}=values %$d;
622             # store computed values into class
623 556         17495 ATTRIBUTES_RECURSIVE($class,@attributes_recursive);
624 556         1900 IATTRIBUTES_RECURSIVE($class,%iattributes_recursive);
625 556         3374 CATTRIBUTES_RECURSIVE($class,%cattributes_recursive);
626 556         1621 SYNONYMS_RECURSIVE($class,%synonyms_recursive);
627 556         1877 DEFAULTS_RECURSIVE($class,$defaults_recursive);
628              
629             # note that attributes are case sensitive, while defaults and args are not.
630             # (this may be a crock, but it's documented this way). to deal with this, we build
631             # a map from de-cased attributes to attributes. really, the map takes use from
632             # id's as fixed by Args to attributes as they exist here
633 556         718 my %fixed_attributes;
634 556         1818 my @fixed_attributes=fix_keywords(@attributes_recursive);
635 556         15990 @fixed_attributes{@attributes_recursive}=@fixed_attributes;
636 556         1610 FIXED_ATTRIBUTES_RECURSIVE($class,%fixed_attributes);
637              
638             ########################################
639              
640             # enumerate internal super-classes and find an external class to create object
641              
642             # NG 06-03-14: moved code for AutoDB registration higher.
643             # my %autodb = AUTODB($class);
644             # if (%autodb) { # hack ISA before setting ancestors
645             # no strict 'refs';
646              
647             # # add AutoDB::Object to @ISA if necessary
648             # unless ( grep /^Class::AutoDB::Object/, @{ $class . '::ISA' } ) {
649             # unshift @{ $class . '::ISA' }, 'Class::AutoDB::Object';
650             # }
651             # require 'Class/AutoDB/Object.pm';
652             # require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
653             # }
654              
655 556         1919 my ( $ancestors, $can_new ) = _enumerate($class);
656 556         1542 ANCESTORS( $class, $ancestors );
657 556         1454 CAN_NEW( $class, $can_new );
658              
659             # DEFAULTS_ARGS( $class, new Hash::AutoHash::Args( DEFAULTS($class) ) ); # convert DEFAULTS hash into AutoArgs. NG 05-12-08: commented out since logic moved to DEFAULTS sub
660              
661             # # NG 05-12-02: auto-register subclasses which do not set %AUTODB
662             # # if (%autodb) { # register after setting ANCESTORS
663             # if (UNIVERSAL::isa($class,'Class::AutoDB::Object')) { # register after setting ANCESTORS
664             # require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
665             # my $args = Hash::AutoHash::Args->new( %autodb, -class => $class ); # TODO - spec says %AUTODB=(1) should work
666             # Class::AutoDB::auto_register($args);
667             # }
668              
669             ########################################
670             # NG 05-12-09: changed loops to iterate separately over instance and class attributes.
671             # commented out code for AutoDB dispatch -- could never have run anyway
672             # since %keys never set. also not longer compatible with new
673             # Registration format.
674             # generate the methods
675            
676 556         1352 my @auto_attributes=AUTO_ATTRIBUTES($class);
677 556         1143 undef %iattributes;
678 556         1157 %iattributes=IATTRIBUTES($class);
679 556 100       1082 my @iattributes=grep {$iattributes{$_} && !exists $synonyms{$_}} @auto_attributes;
  228         1124  
680 556         1209 my @class_attributes=(@auto_attributes,CLASS_ATTRIBUTES($class));
681 556 100       1151 my @cattributes=grep {$cattributes{$_} && !exists $synonyms{$_}} @class_attributes;
  335         1156  
682              
683 556         1273 for my $func (@iattributes) {
684 221         644 my $fixed_func = fix_keyword($func);
685 221         4098 my $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
686             \$_[0]->{\'$fixed_func\'}=\$_[1]:
687             \$_[0]->{\'$fixed_func\'};}";
688 221 100   227   26993 eval $sub;
  227 100       17073  
  182 100       6188  
  113 100       28194  
  234         26687  
689             }
690 556         1408 for my $func (@cattributes) {
691 107         300 my $fixed_func = fix_keyword($func);
692 107         2023 my $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
693             \${$class\:\:$fixed_func\}=\$_[1]:
694             \${$class\:\:$fixed_func\};}";
695 107 100   135   10338 eval $sub;
  211 100       14497  
  133         25702  
696             }
697             # NG 05-12-08: commented out. $args was never set anyway... This renders moot the
698             # 'then' clause of the 'if' below. I left it in just in case I have to
699             # revert the change :)
700             # TODO: eliminate 'then' clause if not needed
701             # if ( $args and $args->{keys} ) {
702             # %keys = map { split } split /,/, $args->{keys};
703             # }
704             # if ( $keys{$func} ) { # AutoDB dispatch
705             # $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
706             # \$_[0] . '::AUTOLOAD'->{\'$fixed_func\'}=\$_[1]:
707             # \$_[0] . '::AUTOLOAD'->{\'$fixed_func\'};}";
708             # } else {
709             # if ( exists $cattributes{$func} ) {
710             # $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
711             # \${$class\:\:$fixed_func\}=\$_[1]:
712             # \${$class\:\:$fixed_func\};}";
713             # } else {
714             # $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
715             # \$_[0]->{\'$fixed_func\'}=\$_[1]:
716             # \$_[0]->{\'$fixed_func\'};}";
717             # }
718             # }
719             # eval $sub;
720             # }
721 556         2124 while ( my ( $func, $old_func ) = each %synonyms ) {
722 93 50       247 next if $func eq $old_func; # avoid redundant def if old same as new
723             # my $class_defined=$iattributes_recursive{$old_func} || $cattributes_recursive{$old_func};
724             # my $sub=
725             # '*' . $class . '::' . $func . '=\& ' . $class_defined . '::' . $old_func;
726 93         282 my $sub =
727             '*' . $class . '::' . $func . "=sub {\$_[0]->$old_func(\@_[1..\$\#_])}";
728 93     103   8836 eval $sub;
  231         10852  
  209         20972  
729             }
730 556 50 33     1576 if ( defined $case && $case =~ /lower|lc/i )
731             { # create lowercase versions of each method, too
732 0         0 for my $func (@iattributes,@cattributes) {
733 0         0 my $lc_func = lc $func;
734             next
735 0 0       0 if $lc_func eq $func; # avoid redundant def if func already lowercase
736 0         0 my $sub=
737             '*' . $class . '::' . $lc_func . '=\& '. $class . '::' . $func;
738             # my $sub =
739             # '*' . $class . '::' . $lc_func . "=sub {\$_[0]->$func(\@_[1..\$\#_])}";
740 0         0 eval $sub;
741             }
742             }
743 556 50 33     1603 if ( defined $case && $case =~ /upper|uc/i )
744             { # create uppercase versions of each method, too
745 0         0 for my $func (@iattributes,@cattributes) {
746 0         0 my $uc_func = uc $func;
747             next
748 0 0       0 if $uc_func eq $func; # avoid redundant def if func already uppercase
749 0         0 my $sub=
750             '*' . $class . '::' . $uc_func . '=\& '. $class . '::' . $func;
751             # my $sub =
752             # '*' . $class . '::' . $uc_func . "=sub {\$_[0]->$func(\@_[1..\$\#_])}";
753 0         0 eval $sub;
754             }
755             }
756             # NG 05-12-08: removed $args from parameter list
757             # NG 05-12-09: converted call from method ($class->...) to function. removed eval that
758             # wrappped call. provided regression test for class that does not inherit
759             # from AutoClass
760 556         1547 set_class_defaults($class);
761 556         1376 DECLARED($class,1); # NG 06-02-03: so 'new' can know when to call declare
762              
763             # NG 06-03-14: Process deferred subclasses
764 556         1231 my @deferreds=AUTOCLASS_DEFERRED_DECLARE($class);
765 556         3695 for my $subclass (@deferreds) {
766 2 50       5 declare($subclass,CASE($subclass),$is_runtime) unless DECLARED($subclass);
767             }
768             }
769              
770             sub _enumerate {
771 576     576   888 my ($class) = @_;
772 576         953 my $classes = [];
773 576         898 my $types = {};
774 576         711 my $can_new;
775 576         1823 __enumerate( $classes, $types, \$can_new, $class );
776 576         8214 return ( $classes, $can_new );
777             }
778              
779             sub __enumerate {
780 37     37   308 no warnings;
  37         87  
  37         5381  
781 2567     2567   6634 my ( $classes, $types, $can_new, $class ) = @_;
782 2567 50       7094 die "Circular inheritance structure. \$class=$class"
783             if ( $types->{$class} eq 'pending' );
784 2567 100       7449 return $types->{$class} if defined $types->{$class};
785 2131         4832 $types->{$class} = 'pending';
786 2131         2372 my @isa;
787             {
788 37     37   217 no strict "refs";
  37         78  
  37         10086  
  2131         2702  
789 2131         2513 @isa = @{ $class . '::ISA' };
  2131         10611  
790             }
791 2131         2889 my $type = 'external';
792 2131         3456 for my $super (@isa) {
793 2825 100       7307 $type = 'internal', next if $super eq $AUTOCLASS;
794 1991         4717 my $super_type = __enumerate( $classes, $types, $can_new, $super );
795 1991 100       6565 $type = $super_type unless $type eq 'internal';
796             }
797 2131 100 66     5016 if ( !FORCE_NEW($class) && !$$can_new && $type eq 'internal' ) {
      100        
798 1698         2703 for my $super (@isa) {
799 2399 100       9005 next unless $types->{$super} eq 'external';
800 78 50       743 $$can_new = $super, last if $super->can('new');
801             }
802             }
803 2131 100       6325 push( @$classes, $class ) if $type eq 'internal';
804 2131         3690 $types->{$class} = $type;
805 2131         6350 return $types->{$class};
806             }
807              
808             sub _is_positional {
809 0 0   0   0 @_ % 2 || $_[0] !~ /^-/;
810             }
811             1;
812              
813              
814              
815             __END__