File Coverage

blib/lib/Class/AutoClass.pm
Criterion Covered Total %
statement 452 484 93.3
branch 146 182 80.2
condition 51 112 45.5
subroutine 71 72 98.6
pod 5 29 17.2
total 725 879 82.4


line stmt bran cond sub pod time code
1             package Class::AutoClass;
2             our $VERSION = '1.56_04';
3             $VERSION=eval $VERSION; # I think this is the accepted idiom..
4              
5 37     37   241145 use strict;
  37         44  
  37         869  
6 37     37   112 use Carp;
  37         36  
  37         2070  
7 37     37   18446 use Storable qw(dclone);
  37         88703  
  37         2228  
8 37     37   17524 use Hash::AutoHash::Args qw(fix_keyword fix_keywords);
  37         552636  
  37         195  
9 37     37   16615 use Class::AutoClass::Root;
  37         61  
  37         975  
10 37     37   198 use base qw(Class::AutoClass::Root);
  37         38  
  37         2233  
11              
12 37     37   139 use vars qw($AUTOCLASS $AUTODB %CACHE @EXPORT);
  37         37  
  37         31621  
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 700385 my ( $self_or_class, @args ) = @_;
18 609   66     2274 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       2163 declare($class,CASE($class),'runtime') unless $class->DECLARED;
24              
25 609   50     1666 my $classes = $class->ANCESTORS || []; # NG 04-12-03. In case declare not called
26 609         1300 my $can_new = $class->CAN_NEW;
27 609 100       1122 if ( !@$classes ) { # compute on the fly for backwards compatibility
28             # enumerate internal super-classes and find a class to create object
29 20         51 ( $classes, $can_new ) = _enumerate($class);
30             }
31             # NG 09-11-07: when called 'from below' via SUPER::new, respect existing object
32 609         449 my $self;
33 609 100       794 if (ref $self_or_class) {
34 100         87 $self=$self_or_class;
35             } else {
36 509 100       895 $self = $can_new ? $can_new->new(@args) : {};
37 509         1024 bless $self, $class; # Rebless what comes from new just in case
38             }
39 609         1906 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       20396 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         19787 $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         2545 for my $class (@$classes) {
59 1943         6315 my $init_self = $class->can('_init_self');
60 1943 100       4691 $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       10301 $self=$self->{__OVERRIDE__} if $self->{__OVERRIDE__};
64             # $self->_init( $class, $args, $defaults, $default2code );
65             }
66             ################################################################################
67              
68 609 100       906 if($self->{__NULLIFY__}) {
69 1         3 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         1705 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   762 my($self,$class,$args)=@_;
85 609         896 my @attributes=ATTRIBUTES_RECURSIVE($class);
86 609         900 my $defaults=DEFAULTS_RECURSIVE($class); # Args object
87 609         834 my %fixed_attributes=FIXED_ATTRIBUTES_RECURSIVE($class);
88 609         949 my %synonyms=SYNONYMS_RECURSIVE($class);
89 609         864 my %reverse=SYNONYMS_REVERSE($class); # reverse of SYNONYMS_RECURSIVE
90 609         815 my %cattributes=CATTRIBUTES_RECURSIVE($class);
91 609         726 my @cattributes=keys %cattributes;
92 609         868 my %iattributes=IATTRIBUTES_RECURSIVE($class);
93 609         999 my @iattributes=keys %iattributes;
94 609         787 for my $func (@cattributes) { # class attributes
95 379         3021 my $fixed_func=$fixed_attributes{$func};
96 379 100       928 next unless exists $args->{$fixed_func};
97             # no strict 'refs';
98             # next unless ref $self eq $class;
99 97         2940 $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         2246 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       1853 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       1066 next if exists $args->{$fixed_func}; # handles cases 1,4 plus case of not synonym
115 421         4262 my $real=$synonyms{$fixed_func};
116 421 100 100     761 next if $real && exists $args->{$fixed_attributes{$real}}; # case 2
117 418         733 my $syn_list=$reverse{$fixed_func};
118             next if $syn_list &&
119 418 100 100     617 grep {exists $args->{$fixed_attributes{$_}}} @$syn_list; # case 3
  51         149  
120             # okay to set default!!
121 414         867 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         276 my $copy;
125 414 100       521 if (ref $value) {
126 13         11 $copy=eval{dclone($value)};
  13         309  
127 13 100       25 $value=$copy unless $@; # use $copy unless dclone failed
128             }
129             # $value=ref $value? dclone($value): $value;
130 414         6782 $self->$fixed_func($value);
131             }
132              
133 609         1227 for my $func (@iattributes) { # instance attributes
134 1637         15016 my $fixed_func=$fixed_attributes{$func};
135 1637 100       2761 if (exists $args->{$fixed_func}) {
136 411         9376 $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 803 my $self = shift;
173 14         32 my $args = new Hash::AutoHash::Args(@_);
174 14         681 while ( my ( $key, $value ) = each %$args ) {
175 42         681 my $func = $self->can($key);
176 42 50       655 $self->$func($value) if $func;
177             }
178             }
179              
180             sub get {
181 219     219 1 319313 my $self = shift;
182 219         402 my @keys = fix_keyword(@_);
183 219         9475 my @results;
184 219         267 for my $key (@keys) {
185 2942         3980 my $func = $self->can($key);
186 2942 50       36828 my $result = $func ? $self->$func() : undef;
187 2942         4243 push( @results, $result );
188             }
189 219 100       1386 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 398 my ( $self, $attributes, $args ) = @_;
198 13         14 my $class=ref $self;
199 13 50       29 $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         20 for my $func (@$attributes) {
203 36 100 66     302 next unless exists $args->{$func} && $class->can($func);
204 32         850 $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 445 my ( $class ) = @_;
248 556         618 my $defaults = DEFAULTS_RECURSIVE($class); # Args object
249 556         740 my %fixed_attributes=FIXED_ATTRIBUTES_RECURSIVE($class);
250 556         784 my %cattributes=CATTRIBUTES_RECURSIVE($class);
251 556         629 my @cattributes=keys %cattributes;
252 556         742 for my $func (@cattributes) { # class attributes
253 258         205 my $fixed_func=$fixed_attributes{$func};
254 258 100       500 next unless exists $defaults->{$fixed_func};
255 71         59 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         1274 $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 944 my ($class) = @_;
269 1116   33     2496 $class = (ref $class) || $class; # get class if called as object method
270 37     37   187 no strict 'refs';
  37         41  
  37         2014  
271 1116         791 @{ $class . '::ISA' };
  1116         3103  
272             }
273              
274             sub AUTO_ATTRIBUTES {
275 1113     1113 0 1005 my ($class) = @_;
276 1113   33     2515 $class = (ref $class) || $class; # get class if called as object method
277 37     37   796 no strict 'refs';
  37         681  
  37         1938  
278 1113         771 @{ $class . '::AUTO_ATTRIBUTES' };
  1113         2794  
279             }
280              
281             sub OTHER_ATTRIBUTES {
282 557     557 0 470 my ($class) = @_;
283 557   33     1292 $class = (ref $class) || $class; # get class if called as object method
284 37     37   125 no strict 'refs';
  37         46  
  37         1701  
285 557         388 @{ $class . '::OTHER_ATTRIBUTES' };
  557         1199  
286             }
287              
288             sub CLASS_ATTRIBUTES {
289 1113     1113 0 887 my ($class) = @_;
290 37     37   131 no strict 'refs';
  37         33  
  37         700  
291 37     37   119 no warnings; # supress unitialized var warning
  37         40  
  37         2840  
292 1113         753 @{ $class . '::CLASS_ATTRIBUTES' };
  1113         2448  
293             }
294              
295             sub SYNONYMS {
296 557     557 0 511 my ($class) = @_;
297 557   33     1324 $class = (ref $class) || $class; # get class if called as object method
298 37     37   123 no strict 'refs';
  37         42  
  37         1833  
299 557         440 %{ $class . '::SYNONYMS' };
  557         1751  
300             }
301             sub SYNONYMS_RECURSIVE {
302 1782     1782 0 1536 my $class = shift @_;
303 1782   33     4030 $class = (ref $class) || $class; # get class if called as object method
304 37     37   118 no strict 'refs';
  37         40  
  37         5568  
305 1782         1288 my %synonyms;
306 1782 100       1932 if (@_) {
307 76         66 %synonyms=%{ $class . '::SYNONYMS_RECURSIVE' } = @_;
  76         336  
308 76         65 my %reverse;
309 76         183 while(my($syn,$real)=each %synonyms) {
310 261   100     664 my $list=$reverse{$real} || ($reverse{$real}=[]);
311 261         594 push(@$list,$syn);
312             }
313 76         142 SYNONYMS_REVERSE($class, %reverse);
314             } else {
315 1706         1503 %synonyms=%{ $class . '::SYNONYMS_RECURSIVE' };
  1706         3986  
316             }
317 1782 100       3037 wantarray? %synonyms: \%synonyms;
318             }
319             sub SYNONYMS_REVERSE { # reverse of SYNONYMS_RECURSIVE. used to set instance defaults
320 685     685 0 614 my $class = shift @_;
321 685   33     1699 $class = (ref $class) || $class; # get class if called as object method
322 37     37   867 no strict 'refs';
  37         35  
  37         2603  
323 76         367 my %synonyms=@_ ? %{ $class . '::SYNONYMS_REVERSE' } = @_:
324 685 100       885 %{ $class . '::SYNONYMS_REVERSE' };
  609         2224  
325 685 100       1307 wantarray? %synonyms: \%synonyms;
326             }
327             # ATTRIBUTES -- all attributes
328             sub ATTRIBUTES {
329 557     557 0 568 my $class = shift @_;
330 557   33     1342 $class = (ref $class) || $class; # get class if called as object method
331 37     37   132 no strict 'refs';
  37         34  
  37         2697  
332 557 100       697 my @attributes=@_ ? @{ $class . '::ATTRIBUTES' } = @_ : @{ $class . '::ATTRIBUTES' };
  85         373  
  472         1690  
333 557 50       825 wantarray? @attributes: \@attributes;
334             }
335             sub ATTRIBUTES_RECURSIVE {
336 1782     1782 0 1659 my $class = shift @_;
337 1782   33     4273 $class = (ref $class) || $class; # get class if called as object method
338 37     37   122 no strict 'refs';
  37         44  
  37         3711  
339 84     84   61 sub _uniq {my %h; @h{@_}=@_; values %h;}
  84         421  
  84         354  
340 84         633 my @attributes=@_ ? @{ $class . '::ATTRIBUTES_RECURSIVE' } = _uniq(@_):
341 1782 100       2396 @{ $class . '::ATTRIBUTES_RECURSIVE' };
  1698         4955  
342 1782 100       3396 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 1458 my $class = shift @_;
348 1721   33     3758 $class = (ref $class) || $class; # get class if called as object method
349 37     37   129 no strict 'refs';
  37         37  
  37         2617  
350 84         1057 my %attributes=@_ ? %{ $class . '::FIXED_ATTRIBUTES_RECURSIVE' } = @_:
351 1721 100       2013 %{ $class . '::FIXED_ATTRIBUTES_RECURSIVE' };
  1637         5663  
352 1721 100       4287 wantarray? %attributes: \%attributes;
353             }
354             # IATTRIBUTES -- instance attributes -- hash
355             sub IATTRIBUTES {
356 1113     1113 0 978 my $class = shift @_;
357 1113   33     2479 $class = (ref $class) || $class; # get class if called as object method
358 37     37   125 no strict 'refs';
  37         35  
  37         2649  
359 1113 100       1356 my %attributes=@_ ? %{ $class . '::IATTRIBUTES' } = @_ : %{ $class . '::IATTRIBUTES' };
  80         448  
  1033         2801  
360 1113 100       2161 wantarray? %attributes: \%attributes;
361             }
362             sub IATTRIBUTES_RECURSIVE {
363 1782     1782 0 1693 my $class = shift @_;
364 1782   33     3974 $class = (ref $class) || $class; # get class if called as object method
365 37     37   118 no strict 'refs';
  37         32  
  37         3196  
366 84         785 my %attributes=@_ ? %{ $class . '::IATTRIBUTES_RECURSIVE' } = @_:
367 1782 100       2023 %{ $class . '::IATTRIBUTES_RECURSIVE' };
  1698         4678  
368 1782 100       3821 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 514 my $class = shift @_;
381 557   33     1381 $class = (ref $class) || $class; # get class if called as object method
382 37     37   113 no strict 'refs';
  37         777  
  37         3466  
383 557 100       691 my %attributes=@_ ? %{ $class . '::CATTRIBUTES' } = @_ : %{ $class . '::CATTRIBUTES' };
  81         315  
  476         1457  
384 557 50       775 wantarray? %attributes: \%attributes;
385             }
386             sub CATTRIBUTES_RECURSIVE {
387 2338     2338 0 2281 my $class = shift @_;
388 2338   33     5294 $class = (ref $class) || $class; # get class if called as object method
389 37     37   130 no strict 'refs';
  37         33  
  37         2453  
390 80         321 my %attributes=@_ ? %{ $class . '::CATTRIBUTES_RECURSIVE' } = @_:
391 2338 100       2588 %{ $class . '::CATTRIBUTES_RECURSIVE' };
  2258         5315  
392 2338 100       3898 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 537 my $class = shift @_;
398 558   33     1366 $class = (ref $class) || $class; # get class if called as object method
399 37     37   118 no strict 'refs';
  37         34  
  37         3147  
400 558         2178 ${ $class . '::DEFAULTS_ARGS' } or
401 558 100       392 ${ $class . '::DEFAULTS_ARGS' } = new Hash::AutoHash::Args(%{ $class . '::DEFAULTS' }); # convert DEFAULTS hash into AutoArgs
  556         17105  
  556         2840  
402             }
403             sub DEFAULTS_RECURSIVE {
404 2338     2338 0 1995 my $class = shift @_;
405 2338   33     5262 $class = (ref $class) || $class; # get class if called as object method
406 37     37   124 no strict 'refs';
  37         36  
  37         2304  
407 556         1767 my $defaults=@_ ? ${ $class . '::DEFAULTS_RECURSIVE' } = $_[0]:
408 2338 100       2686 ${ $class . '::DEFAULTS_RECURSIVE' };
  1782         3051  
409 2338 50       3126 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 805 my $class = shift @_;
414 881   33     2127 $class = (ref $class) || $class; # get class if called as object method
415 37     37   115 no strict 'refs';
  37         33  
  37         2097  
416 881 50       1034 my $case=@_ ? $ { $class . '::CASE' } = $_[0] : $ { $class . '::CASE' };
  0         0  
  881         2685  
417 881         1172 $case;
418             }
419             sub AUTODB {
420 559     559 0 486 my ($class) = @_;
421 559   33     1350 $class = (ref $class) || $class; # get class if called as object method
422 37     37   456 no strict 'refs';
  37         41  
  37         2269  
423 559         403 %{ $class . '::AUTODB' };
  559         2401  
424             }
425              
426             sub ANCESTORS {
427 1165     1165 0 1055 my $class = shift @_;
428 1165   33     3015 $class = (ref $class) || $class; # get class if called as object method
429 37     37   120 no strict 'refs';
  37         33  
  37         2085  
430 1165 100       1470 @_ ? ${ $class . '::ANCESTORS' } = $_[0] : ${ $class . '::ANCESTORS' };
  556         1654  
  609         1905  
431             }
432              
433             sub CAN_NEW {
434 1165     1165 0 1026 my $class = shift @_;
435 1165   33     2627 $class = (ref $class) || $class; # get class if called as object method
436 37     37   115 no strict 'refs';
  37         27  
  37         2080  
437 1165 100       1429 @_ ? ${ $class . '::CAN_NEW' } = $_[0] : ${ $class . '::CAN_NEW' };
  556         1395  
  609         1169  
438             }
439              
440             sub FORCE_NEW {
441 2131     2131 0 1609 my $class = shift @_;
442 2131   33     4409 $class = (ref $class) || $class; # get class if called as object method
443 37     37   114 no strict 'refs';
  37         35  
  37         1689  
444 2131         1303 ${ $class . '::FORCE_NEW' };
  2131         11301  
445             }
446             sub DECLARED { # set to 1 by declare. tested in new
447 1947     1947 0 1823 my $class = shift @_;
448 1947   33     4669 $class = (ref $class) || $class; # get class if called as object method
449 37     37   118 no strict 'refs';
  37         36  
  37         2050  
450 1947 100       2421 @_ ? ${ $class . '::DECLARED' } = $_[0] : ${ $class . '::DECLARED' };
  634         1519  
  1313         4511  
451             }
452             sub AUTOCLASS_DEFERRED_DECLARE {
453 558     558 0 479 my $class = shift @_;
454 558   33     1308 $class = (ref $class) || $class; # get class if called as object method
455 37     37   114 no strict 'refs';
  37         42  
  37         4597  
456 558 100       813 ${ $class . '::AUTOCLASS_DEFERRED_DECLARE' }{$_[0]}=$_[0] if @_;
  2         6  
457             # push(@{ $class . '::AUTOCLASS_DEFERRED_DECLARE' }, @_) if @_;
458             # @{ $class . '::AUTOCLASS_DEFERRED_DECLARE' };
459 558         388 keys %{ $class . '::AUTOCLASS_DEFERRED_DECLARE' };
  558         1949  
460             }
461             sub declare {
462 559     559 1 284052 my ( $class, $case, $is_runtime ) = @_;
463 559 100       1171 $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       788 if (defined $case) {
468 0         0 CASE($class,$case); # save $case for run-time
469             } else {
470 559         1107 $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         566 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         893 for my $super (ISA($class)) {
485 899 100       1451 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   146 { no strict 'refs';
  37         34  
  37         4358  
  698         493  
503 698 100       448 unless (%{$super.'::'}) {
  698         1508  
504 3 50       137 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       787 if (!DECLARED($super)) {
516 80 100       125 if ($is_runtime) {
517 78 50       345 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         107 DECLARED($class,1);
521             }
522             } else {
523 2         3 AUTOCLASS_DEFERRED_DECLARE($super,$class); # push class onto super's deferred list
524 2         2 $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         834 my %autodb = AUTODB($class);
532 559 50       947 if (%autodb) {
533 37     37   132 no strict 'refs';
  37         36  
  37         36080  
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       2405 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       780 return if $defer;
563             # NG 06-03-14: this part of the loop does the work
564 557         636 for my $super (ISA($class)) {
565 896 100 100     3300 next if $super eq 'Class::AutoClass' || !UNIVERSAL::isa($super,'Class::AutoClass');
566 617         799 push(@attributes_recursive,ATTRIBUTES_RECURSIVE($super));
567 617         476 my %h;
568 617         721 %h=IATTRIBUTES_RECURSIVE($super);
569 617         905 @iattributes_recursive{keys %h}=values %h;
570 617         772 undef %h;
571 617         698 %h=CATTRIBUTES_RECURSIVE($super);
572 617         775 @cattributes_recursive{keys %h}=values %h;
573 617         490 undef %h;
574 617         702 %h=SYNONYMS_RECURSIVE($super);
575 617         732 @synonyms_recursive{keys %h}=values %h;
576 617         672 my $d=DEFAULTS_RECURSIVE($super);
577 617         1317 @$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         823 my %synonyms = SYNONYMS($class);
584 557         451 my %iattributes;
585             my %cattributes;
586             # init cattributes to declared CLASS_ATTRIBUTES
587 557         696 map {$cattributes{$_}=$class} CLASS_ATTRIBUTES($class);
  108         287  
588             # iattributes = all attributes that are not cattributes
589 557 50 66     706 map {$iattributes{$_}=$class unless $iattributes_recursive{$_} || $cattributes{$_}}
  303         1084  
590             (AUTO_ATTRIBUTES($class),OTHER_ATTRIBUTES($class));
591             # add in synonyms
592 557         1526 while(my($syn,$real)=each %synonyms) {
593             confess "Inconsistent declaration for attribute $syn: both synonym and real attribute"
594 93 0 33     187 if $cattributes{$syn} && $iattributes{$syn};
595 93 50 33     226 $cattributes{$syn}=$class if $cattributes{$real} || $cattributes_recursive{$real};
596 93 50 66     349 $iattributes{$syn}=$class if $iattributes{$real} || $iattributes_recursive{$real};
597             }
598 557         987 IATTRIBUTES($class,%iattributes);
599 557         1012 CATTRIBUTES($class,%cattributes);
600 557         1031 ATTRIBUTES($class,keys %iattributes,keys %cattributes);
601              
602             # store our attributes into recursives
603 557         884 @iattributes_recursive{keys %iattributes}=values %iattributes;
604 557         515 @cattributes_recursive{keys %cattributes}=values %cattributes;
605 557         610 push(@attributes_recursive,keys %iattributes,keys %cattributes);
606             # are all these declarations consistent?
607 557 100       1097 if (my @inconsistents=grep {exists $cattributes_recursive{$_}} keys %iattributes_recursive) {
  1088         1052  
608             # inconsistent class vs. instance declarations
609 1         3 my @errstr=("Inconsistent declarations for attribute(s) @inconsistents");
610             map {
611 1         1 push(@errstr,
  2         5  
612             "\tAttribute $_: declared instance attribute in $iattributes_recursive{$_}, class attribute in $cattributes_recursive{$_}");
613             } @inconsistents;
614 1         668 confess join("\n",@errstr);
615             }
616             # store our synonyms into recursive
617 556         576 @synonyms_recursive{keys %synonyms}=values %synonyms;
618             # store our defaults into recursive
619              
620 556         680 my $d=DEFAULTS($class);
621 556         1574 @$defaults_recursive{keys %$d}=values %$d;
622             # store computed values into class
623 556         6931 ATTRIBUTES_RECURSIVE($class,@attributes_recursive);
624 556         1005 IATTRIBUTES_RECURSIVE($class,%iattributes_recursive);
625 556         1021 CATTRIBUTES_RECURSIVE($class,%cattributes_recursive);
626 556         926 SYNONYMS_RECURSIVE($class,%synonyms_recursive);
627 556         844 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         392 my %fixed_attributes;
634 556         1050 my @fixed_attributes=fix_keywords(@attributes_recursive);
635 556         8591 @fixed_attributes{@attributes_recursive}=@fixed_attributes;
636 556         933 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         1053 my ( $ancestors, $can_new ) = _enumerate($class);
656 556         760 ANCESTORS( $class, $ancestors );
657 556         700 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         704 my @auto_attributes=AUTO_ATTRIBUTES($class);
677 556         787 undef %iattributes;
678 556         651 %iattributes=IATTRIBUTES($class);
679 556 100       635 my @iattributes=grep {$iattributes{$_} && !exists $synonyms{$_}} @auto_attributes;
  228         754  
680 556         702 my @class_attributes=(@auto_attributes,CLASS_ATTRIBUTES($class));
681 556 100       537 my @cattributes=grep {$cattributes{$_} && !exists $synonyms{$_}} @class_attributes;
  335         667  
682              
683 556         607 for my $func (@iattributes) {
684 221         449 my $fixed_func = fix_keyword($func);
685 221         2623 my $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
686             \$_[0]->{\'$fixed_func\'}=\$_[1]:
687             \$_[0]->{\'$fixed_func\'};}";
688 221 100   171   16399 eval $sub;
  171 100       10155  
  166 100       21529  
  248 100       3511  
  100         6771  
689             }
690 556         524 for my $func (@cattributes) {
691 107         193 my $fixed_func = fix_keyword($func);
692 107         1288 my $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
693             \${$class\:\:$fixed_func\}=\$_[1]:
694             \${$class\:\:$fixed_func\};}";
695 107 100   125   6760 eval $sub;
  205 100       7785  
  162         15232  
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         1172 while ( my ( $func, $old_func ) = each %synonyms ) {
722 93 50       161 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         239 my $sub =
727             '*' . $class . '::' . $func . "=sub {\$_[0]->$old_func(\@_[1..\$\#_])}";
728 93     124   6206 eval $sub;
  230         11036  
  226         6800  
729             }
730 556 50 33     1040 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     922 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         747 set_class_defaults($class);
761 556         760 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         669 my @deferreds=AUTOCLASS_DEFERRED_DECLARE($class);
765 556         1963 for my $subclass (@deferreds) {
766 2 50       3 declare($subclass,CASE($subclass),$is_runtime) unless DECLARED($subclass);
767             }
768             }
769              
770             sub _enumerate {
771 576     576   542 my ($class) = @_;
772 576         554 my $classes = [];
773 576         537 my $types = {};
774 576         422 my $can_new;
775 576         776 __enumerate( $classes, $types, \$can_new, $class );
776 576         1137 return ( $classes, $can_new );
777             }
778              
779             sub __enumerate {
780 37     37   193 no warnings;
  37         42  
  37         2564  
781 2567     2567   2132 my ( $classes, $types, $can_new, $class ) = @_;
782             die "Circular inheritance structure. \$class=$class"
783 2567 50       3877 if ( $types->{$class} eq 'pending' );
784 2567 100       3588 return $types->{$class} if defined $types->{$class};
785 2131         2320 $types->{$class} = 'pending';
786 2131         1392 my @isa;
787             {
788 37     37   133 no strict "refs";
  37         35  
  37         6295  
  2131         1213  
789 2131         1461 @isa = @{ $class . '::ISA' };
  2131         4844  
790             }
791 2131         1474 my $type = 'external';
792 2131         1734 for my $super (@isa) {
793 2825 100       3850 $type = 'internal', next if $super eq $AUTOCLASS;
794 1991         2377 my $super_type = __enumerate( $classes, $types, $can_new, $super );
795 1991 100       3171 $type = $super_type unless $type eq 'internal';
796             }
797 2131 100 66     2090 if ( !FORCE_NEW($class) && !$$can_new && $type eq 'internal' ) {
      100        
798 1698         1390 for my $super (@isa) {
799 2399 100       3652 next unless $types->{$super} eq 'external';
800 78 50       372 $$can_new = $super, last if $super->can('new');
801             }
802             }
803 2131 100       3572 push( @$classes, $class ) if $type eq 'internal';
804 2131         1832 $types->{$class} = $type;
805 2131         2726 return $types->{$class};
806             }
807              
808             sub _is_positional {
809 0 0   0   0 @_ % 2 || $_[0] !~ /^-/;
810             }
811             1;
812              
813              
814              
815             __END__