File Coverage

blib/lib/Class/AutoClass.pm
Criterion Covered Total %
statement 463 479 96.6
branch 188 226 83.1
condition 30 43 69.7
subroutine 71 72 98.6
pod 9 30 30.0
total 761 850 89.5


line stmt bran cond sub pod time code
1             package Class::AutoClass;
2 12     12   226047 use strict;
  12         32  
  12         843  
3             our $VERSION = '1.0';
4 12     12   68 use vars qw($AUTOCLASS $AUTODB @ISA %CACHE @EXPORT);
  12         23  
  12         1336  
5             $AUTOCLASS = __PACKAGE__;
6 12     12   18112 use Class::AutoClass::Root;
  12         36  
  12         472  
7 12     12   8456 use Class::AutoClass::Args;
  12         36  
  12         350  
8 12     12   15725 use Storable qw(dclone);
  12         71976  
  12         1009  
9 12     12   119 use Carp;
  12         22  
  12         17773  
10             @ISA = qw(Class::AutoClass::Root);
11              
12             sub new {
13 65     65 1 12555 my ( $class, @args ) = @_;
14 65   33     390 $class = ( ref $class ) || $class;
15             # NG 06-02-03: 1st attempt to call declare at runtime if not declared at compile-time
16             # declare($class) unless $class->DECLARED;
17             # NG 06-02-03: 2nd attempt to declare at runtime if not declared at compile-time
18             # include $case and flag to indicate this is runtime
19 65 100       320 declare($class,CASE($class),'runtime') unless $class->DECLARED;
20              
21 65   50     309 my $classes = $class->ANCESTORS || []; # NG 04-12-03. In case declare not called
22 65         697 my $can_new = $class->CAN_NEW;
23 65 100       196 if ( !@$classes ) { # compute on the fly for backwards compatibility
24             # enumerate internal super-classes and find a class to create object
25 1         3 ( $classes, $can_new ) = _enumerate($class);
26             }
27 65 50       192 my $self = $can_new ? $can_new->new(@args) : {};
28 65         143 bless $self, $class; # Rebless what comes from new just in case
29 65         552 my $args = new Class::AutoClass::Args(@args);
30 65         667 my $defaults = new Class::AutoClass::Args( $args->defaults );
31              
32             # set arg defaults into args
33 65         419 while ( my ( $keyword, $value ) = each %$defaults ) {
34 0 0       0 $args->{$keyword} = $value unless exists $args->{$keyword};
35             }
36              
37             ################################################################################
38             # NG 05-12-08: initialization strategy changed. instead of init'ing class by class
39             # down the hierarchy, it's now done all at once.
40 65         417 $self->_init($class,$args); # init attributes from args and defaults
41              
42             # $defaults=new Class::AutoClass::Args; # NG 05-12-07: reset $defaults.
43             # # will accumulate instance defaults during initialization
44             # my $default2code={};
45              
46 65         157 for my $class (@$classes) {
47 132         1182 my $init_self = $class->can('_init_self');
48 132 100       569 $self->$init_self( $class, $args ) if $init_self;
49             # $self->_init( $class, $args, $defaults, $default2code );
50             }
51             ################################################################################
52              
53 65 100       664 if($self->{__NULLIFY__}) {
    100          
54 1         13 return undef;
55             } elsif ($self->{__OVERRIDE__}) { # override self with the passed object
56 1         2 $self=$self->{__OVERRIDE__};
57 1         12 return $self;
58             } else {
59 63         377 return $self;
60             }
61             }
62              
63             ################################################################################
64             # NG 05-12-08: initialization strategy changed. instead of init'ing class by class
65             # down the hierarchy, it's now done all at once.
66             sub _init {
67 71     71   1175 my($self,$class,$args)=@_;
68 71         191 my @attributes=ATTRIBUTES_RECURSIVE($class);
69 71         222 my $defaults=DEFAULTS_RECURSIVE($class); # Args object
70 71         227 my %fixed_attributes=FIXED_ATTRIBUTES_RECURSIVE($class);
71 71         293 my %synonyms=SYNONYMS_RECURSIVE($class);
72 71         214 my %reverse=SYNONYMS_REVERSE($class); # reverse of SYNONYMS_RECURSIVE
73 71         213 my %cattributes=CATTRIBUTES_RECURSIVE($class);
74 71         191 my @cattributes=keys %cattributes;
75 71         378 my %iattributes=IATTRIBUTES_RECURSIVE($class);
76 71         351 my @iattributes=keys %iattributes;
77 71         179 for my $func (@cattributes) { # class attributes
78 151         273 my $fixed_func=$fixed_attributes{$func};
79 151 100       436 next unless exists $args->{$fixed_func};
80             # no strict 'refs';
81             # next unless ref $self eq $class;
82 13         500 $class->$func($args->{$fixed_func});
83             }
84 71         143 for my $func (@iattributes) { # instance attributes
85 729         1151 my $fixed_func=$fixed_attributes{$func};
86 729 100       2814 if (exists $args->{$fixed_func}) {
    100          
87 73         1786 $self->$func( $args->{$fixed_func} );
88             } elsif (exists $defaults->{$fixed_func}) {
89             # because of synonyms, this is more complicated than it might appear.
90             # there are 4 cases: consider syn=>real
91             # 1) args sets syn, defaults sets syn
92             # 2) args sets real, defaults sets syn
93             # 3) args sets syn, defaults sets real
94             # 4) args sets real, defaults sets real
95 159 50       334 next if exists $args->{$fixed_func}; # handles cases 1,4 plus case of not synonym
96 159         274 my $real=$synonyms{$func};
97 159 100 100     410 next if $real && exists $args->{$fixed_attributes{$real}}; # case 2
98 157         211 my $syn_list=$reverse{$func};
99 22         144 next if $syn_list &&
100 157 100 100     405 grep {exists $args->{$fixed_attributes{$_}}} @$syn_list; # case 3
101             # okay to set default!!
102 150         258 my $value=$defaults->{$fixed_func};
103 150 50       274 $value=ref $value? dclone($value): $value; # deep copy refs so each instance has own copy
104 150         3497 $self->$func($value);
105             }
106             }
107             }
108              
109             ########################################
110              
111             #sub _init {
112             # my ( $self, $class, $args, $defaults, $default2code ) = @_;
113             # my %synonyms = SYNONYMS($class);
114             # my $attributes = ATTRIBUTES($class);
115             # # only object methods here
116             # $self->set_instance_defaults( $args, $defaults, $default2code, $class ); # NG 05-12-07
117             # $self->set_attributes( $attributes, $args, $defaults, $default2code, $class ); # NG 05-12-07
118             # my $init_self = $class->can('_init_self');
119             # $self->$init_self( $class, $args ) if $init_self;
120             #}
121              
122             sub set {
123 8     8 1 18 my $self = shift;
124 8         39 my $args = new Class::AutoClass::Args(@_);
125 8         39 while ( my ( $key, $value ) = each %$args ) {
126 12         42 my $func = $self->can($key);
127 12 50       366 $self->$func($value) if $func;
128             }
129             }
130              
131             sub get {
132 16     16 1 38 my $self = shift;
133 16         53 my @keys = Class::AutoClass::Args::fix_keyword(@_);
134 16         27 my @results;
135 16         26 for my $key (@keys) {
136 16         62 my $func = $self->can($key);
137 16 50       491 my $result = $func ? $self->$func() : undef;
138 16         52 push( @results, $result );
139             }
140 16 50       96 wantarray ? @results : $results[0];
141             }
142              
143             ########################################
144             # NG 05-12-09: changed to always call method. previous version just stored
145             # value for class attributes.
146             # note: this is user level method -- not just internal!!!
147             sub set_attributes {
148 2     2 1 4 my ( $self, $attributes, $args ) = @_;
149 2         19 my $class=$self->class;
150 2 50       10 $self->throw('Atrribute list must be an array ref') unless ref $attributes eq 'ARRAY';
151 2         9 my @attributes=Class::AutoClass::Args::fix_keyword(@$attributes);
152 2         6 for my $func (@attributes) {
153 8 50 33     71 next unless exists $args->{$func} && $class->can($func);
154 8         213 $self->$func( $args->{$func} );
155             }
156             }
157              
158             ## NG 05-12-07: process defaults. $defaults contains defaults seen so far in the
159             # # recursive initialization process that are NOT in $args. As we descend, also
160             # # have to check synonyms:
161             # @keywords=$class->ATTRIBUTES_RECURSIVE;
162             # for my $func (@keywords) {
163             # next unless exists $defaults->{$func};
164             # my $code=$class->can($func);
165             # next if $default2code->{$func} == $code;
166             # $self->$func($defaults->{$func});
167             # $default2code->{$func}=$code;
168             # }
169             ## for my $func (keys %$defaults) {
170             ## next if !$class->can($func);
171             ## $self->$func($defaults->{$func});
172             ## delete $defaults->{$func};
173             ## }
174             #}
175              
176             ## sets default attributes on a newly created instance
177             ## NG 05-12-07: changed to accumulate defaults in $defaults. setting done in set_attributes.
178             ## previous version set values directly into object HASH. this is wrong, since
179             ## it skips the important step of running the attribute's 'set' method.
180             #sub set_instance_defaults {
181             # my ( $self, $args, $defaults, $default2code, $class ) = @_;
182             # my %class_funcs;
183             # my $class_defaults = DEFAULTS($class);
184             # map { $class_funcs{$_}++ } CLASS_ATTRIBUTES($class);
185             # while ( my ( $key, $value ) = each %$class_defaults ) {
186             # next if exists $class_funcs{$key} || exists $args->{$key};
187             # $defaults->{$key} = ref $value? dclone($value): $value; # deep copy refs;
188             # delete $default2code->{$key}; # NG 05-12-07: so new default will be set
189             # }
190             #}
191              
192             ########################################
193             # NG 05-12-09: rewrote to use CATTRIBUTES_RECURSIVE. also changed to always call
194             # method. previous version just stored values
195             # sets class defaults at "declare time"
196             sub set_class_defaults {
197 41     41 1 88 my ( $class ) = @_;
198 41         92 my $defaults = DEFAULTS_RECURSIVE($class); # Args object
199 41         117 my %fixed_attributes=FIXED_ATTRIBUTES_RECURSIVE($class);
200 41         150 my %cattributes=CATTRIBUTES_RECURSIVE($class);
201 41         123 my @cattributes=keys %cattributes;
202 41         104 for my $func (@cattributes) { # class attributes
203 85         152 my $fixed_func=$fixed_attributes{$func};
204 85 100       225 next unless exists $defaults->{$fixed_func};
205 78         118 my $value=$defaults->{$fixed_func};
206             # NG 06-02-03. vcassen observed that dclone not needed here since there
207             # can only be one copy of each class attribute
208             # $value=ref $value? dclone($value): $value; # deep copy refs so each instance has own copy
209 78         2234 $class->$func($value);
210             }
211             }
212             ########################################
213 52     52 0 1273 sub class { ref $_[0]; }
214              
215             sub ISA {
216 87     87 0 131 my ($class) = @_;
217 87 50       184 $class = $class->class if ref $class; # get class if called as object method
218 12     12   82 no strict 'refs';
  12         26  
  12         1145  
219 87         107 @{ $class . '::ISA' };
  87         431  
220             }
221              
222             sub AUTO_ATTRIBUTES {
223 83     83 1 125 my ($class) = @_;
224 83 50       217 $class = $class->class if ref $class; # get class if called as object method
225 12     12   219 no strict 'refs';
  12         32  
  12         1054  
226 83         94 @{ $class . '::AUTO_ATTRIBUTES' };
  83         401  
227             }
228              
229             sub OTHER_ATTRIBUTES {
230 42     42 1 78 my ($class) = @_;
231 42 50       114 $class = $class->class if ref $class; # get class if called as object method
232 12     12   228 no strict 'refs';
  12         27  
  12         762  
233 42         71 @{ $class . '::OTHER_ATTRIBUTES' };
  42         152  
234             }
235              
236             sub CLASS_ATTRIBUTES {
237 83     83 0 119 my ($class) = @_;
238 12     12   57 no strict 'refs';
  12         22  
  12         368  
239 12     12   58 no warnings; # supress unitialized var warning
  12         20  
  12         1191  
240 83         108 @{ $class . '::CLASS_ATTRIBUTES' };
  83         525  
241             }
242              
243             sub SYNONYMS {
244 42     42 1 72 my ($class) = @_;
245 42 50       108 $class = $class->class if ref $class; # get class if called as object method
246 12     12   59 no strict 'refs';
  12         18  
  12         976  
247 42         108 %{ $class . '::SYNONYMS' };
  42         228  
248             }
249             sub SYNONYMS_RECURSIVE {
250 135     135 0 232 my $class = shift @_;
251 135 100       327 $class = $class->class if ref $class; # get class if called as object method
252 12     12   60 no strict 'refs';
  12         29  
  12         2689  
253 135         172 my %synonyms;
254 135 100       303 if (@_) {
255 28         44 %synonyms=%{ $class . '::SYNONYMS_RECURSIVE' } = @_;
  28         206  
256 28         46 my %reverse;
257 28         139 while(my($syn,$real)=each %synonyms) {
258 86   100     343 my $list=$reverse{$real} || ($reverse{$real}=[]);
259 86         365 push(@$list,$syn);
260             }
261 28         98 SYNONYMS_REVERSE($class, %reverse);
262             } else {
263 107         140 %synonyms=%{ $class . '::SYNONYMS_RECURSIVE' };
  107         595  
264             }
265 135 100       588 wantarray? %synonyms: \%synonyms;
266             }
267             sub SYNONYMS_REVERSE { # reverse of SYNONYMS_RECURSIVE. used to set instance defaults
268 99     99 0 193 my $class = shift @_;
269 99 100       320 $class = $class->class if ref $class; # get class if called as object method
270 12     12   107 no strict 'refs';
  12         17  
  12         1634  
271 28         191 my %synonyms=@_ ? %{ $class . '::SYNONYMS_REVERSE' } = @_:
  71         345  
272 99 100       247 %{ $class . '::SYNONYMS_REVERSE' };
273 99 100       438 wantarray? %synonyms: \%synonyms;
274             }
275             # ATTRIBUTES -- all attributes
276             sub ATTRIBUTES {
277 42     42 0 69 my $class = shift @_;
278 42 50       114 $class = $class->class if ref $class; # get class if called as object method
279 12     12   63 no strict 'refs';
  12         21  
  12         1498  
280 42 100       129 my @attributes=@_ ? @{ $class . '::ATTRIBUTES' } = @_ : @{ $class . '::ATTRIBUTES' };
  35         279  
  7         42  
281 42 50       156 wantarray? @attributes: \@attributes;
282             }
283             sub ATTRIBUTES_RECURSIVE {
284 135     135 0 232 my $class = shift @_;
285 135 100       482 $class = $class->class if ref $class; # get class if called as object method
286 12     12   61 no strict 'refs';
  12         29  
  12         2245  
287 35     35   59 sub _uniq {my %h; @h{@_}=@_; values %h;}
  35         285  
  35         206  
288 35         403 my @attributes=@_ ? @{ $class . '::ATTRIBUTES_RECURSIVE' } = _uniq(@_):
  100         660  
289 135 100       378 @{ $class . '::ATTRIBUTES_RECURSIVE' };
290 135 100       708 wantarray? @attributes: \@attributes;
291             }
292             # maps attributes to fixed (ie, de-cased) attributes. use when initializing attributes
293             # to args or defauls
294             sub FIXED_ATTRIBUTES_RECURSIVE {
295 153     153 0 299 my $class = shift @_;
296 153 100       354 $class = $class->class if ref $class; # get class if called as object method
297 12     12   73 no strict 'refs';
  12         23  
  12         1666  
298 35         632 my %attributes=@_ ? %{ $class . '::FIXED_ATTRIBUTES_RECURSIVE' } = @_:
  118         1556  
299 153 100       347 %{ $class . '::FIXED_ATTRIBUTES_RECURSIVE' };
300 153 100       3362 wantarray? %attributes: \%attributes;
301             }
302             # IATTRIBUTES -- instance attributes -- hash
303             sub IATTRIBUTES {
304 83     83 0 144 my $class = shift @_;
305 83 50       188 $class = $class->class if ref $class; # get class if called as object method
306 12     12   60 no strict 'refs';
  12         28  
  12         1286  
307 83 100       226 my %attributes=@_ ? %{ $class . '::IATTRIBUTES' } = @_ : %{ $class . '::IATTRIBUTES' };
  32         461  
  51         284  
308 83 100       411 wantarray? %attributes: \%attributes;
309             }
310             sub IATTRIBUTES_RECURSIVE {
311 135     135 0 239 my $class = shift @_;
312 135 100       391 $class = $class->class if ref $class; # get class if called as object method
313 12     12   68 no strict 'refs';
  12         171  
  12         1547  
314 35         621 my %attributes=@_ ? %{ $class . '::IATTRIBUTES_RECURSIVE' } = @_:
  100         835  
315 135 100       308 %{ $class . '::IATTRIBUTES_RECURSIVE' };
316 135 100       1023 wantarray? %attributes: \%attributes;
317             }
318             # CATTRIBUTES -- class attributes -- hash
319              
320             # NG 05-12-08: commented out. DEFAULTS_ARGS renamed to DEFAULTS
321             #sub DEFAULTS {
322             # my ($class) = @_;
323             # $class = $class->class if ref $class; # get class if called as object method
324             # no strict 'refs';
325             # %{ $class . '::DEFAULTS' };
326             #}
327             sub CATTRIBUTES {
328 42     42 0 100 my $class = shift @_;
329 42 50       127 $class = $class->class if ref $class; # get class if called as object method
330 12     12   64 no strict 'refs';
  12         20  
  12         1569  
331 42 100       119 my %attributes=@_ ? %{ $class . '::CATTRIBUTES' } = @_ : %{ $class . '::CATTRIBUTES' };
  30         213  
  12         60  
332 42 50       127 wantarray? %attributes: \%attributes;
333             }
334             sub CATTRIBUTES_RECURSIVE {
335 176     176 0 321 my $class = shift @_;
336 176 100       402 $class = $class->class if ref $class; # get class if called as object method
337 12     12   63 no strict 'refs';
  12         18  
  12         2003  
338 29         205 my %attributes=@_ ? %{ $class . '::CATTRIBUTES_RECURSIVE' } = @_:
  147         772  
339 176 100       508 %{ $class . '::CATTRIBUTES_RECURSIVE' };
340 176 100       767 wantarray? %attributes: \%attributes;
341             }
342             # NG 05-12-08: DEFAULTS_ARGS renamed to DEFAULTS.
343             # incorporates logic to convert %DEFAULTS to Args object
344             sub DEFAULTS {
345 41     41 0 76 my $class = shift @_;
346 41 50       114 $class = $class->class if ref $class; # get class if called as object method
347 12     12   72 no strict 'refs';
  12         22  
  12         1348  
348 40         333 ${ $class . '::DEFAULTS_ARGS' } or
  41         332  
349 41 100       63 ${ $class . '::DEFAULTS_ARGS' } = new Class::AutoClass::Args(%{ $class . '::DEFAULTS' }); # convert DEFAULTS hash into AutoArgs
  40         924  
350             }
351             sub DEFAULTS_RECURSIVE {
352 176     176 0 299 my $class = shift @_;
353 176 100       404 $class = $class->class if ref $class; # get class if called as object method
354 12     12   58 no strict 'refs';
  12         32  
  12         1505  
355 41         202 my $defaults=@_ ? ${ $class . '::DEFAULTS_RECURSIVE' } = $_[0]:
  135         434  
356 176 100       387 ${ $class . '::DEFAULTS_RECURSIVE' };
357 176 50       471 wantarray? %$defaults: $defaults;
358             }
359             # NG 06-03-14: Used to save $case from compile-time declare for use by run-time declare
360             sub CASE {
361 56     56 0 178 my $class = shift @_;
362 56 50       171 $class = $class->class if ref $class; # get class if called as object method
363 12     12   60 no strict 'refs';
  12         25  
  12         1155  
364 56 100       137 my $case=@_ ? $ { $class . '::CASE' } = $_[0] : $ { $class . '::CASE' };
  6         29  
  50         211  
365 56         226 $case;
366             }
367             sub AUTODB {
368 45     45 0 71 my ($class) = @_;
369 45 50       116 $class = $class->class if ref $class; # get class if called as object method
370 12     12   59 no strict 'refs';
  12         24  
  12         935  
371 45         63 %{ $class . '::AUTODB' };
  45         260  
372             }
373              
374             sub ANCESTORS {
375 106     106 0 264 my $class = shift @_;
376 106 50       278 $class = $class->class if ref $class; # get class if called as object method
377 12     12   73 no strict 'refs';
  12         18  
  12         1274  
378 106 100       237 @_ ? ${ $class . '::ANCESTORS' } = $_[0] : ${ $class . '::ANCESTORS' };
  41         239  
  65         331  
379             }
380              
381             sub CAN_NEW {
382 106     106 0 188 my $class = shift @_;
383 106 50       275 $class = $class->class if ref $class; # get class if called as object method
384 12     12   68 no strict 'refs';
  12         25  
  12         1070  
385 106 100       226 @_ ? ${ $class . '::CAN_NEW' } = $_[0] : ${ $class . '::CAN_NEW' };
  41         200  
  65         230  
386             }
387              
388             sub FORCE_NEW {
389 78     78 0 116 my $class = shift @_;
390 78 50       157 $class = $class->class if ref $class; # get class if called as object method
391 12     12   98 no strict 'refs';
  12         35  
  12         937  
392 78         86 ${ $class . '::FORCE_NEW' };
  78         759  
393             }
394             sub DECLARED { # set to 1 by declare. tested in new
395 142     142 0 281 my $class = shift @_;
396 142 50       362 $class = $class->class if ref $class; # get class if called as object method
397 12     12   219 no strict 'refs';
  12         86  
  12         1033  
398 142 100       580 @_ ? ${ $class . '::DECLARED' } = $_[0] : ${ $class . '::DECLARED' };
  42         188  
  100         621  
399             }
400             sub AUTOCLASS_DEFERRED_DECLARE {
401 44     44 0 74 my $class = shift @_;
402 44 50       106 $class = $class->class if ref $class; # get class if called as object method
403 12     12   80 no strict 'refs';
  12         16  
  12         3165  
404 44 100       112 ${ $class . '::AUTOCLASS_DEFERRED_DECLARE' }{$_[0]}=$_[0] if @_;
  3         39  
405             # push(@{ $class . '::AUTOCLASS_DEFERRED_DECLARE' }, @_) if @_;
406             # @{ $class . '::AUTOCLASS_DEFERRED_DECLARE' };
407 44         61 keys %{ $class . '::AUTOCLASS_DEFERRED_DECLARE' };
  44         243  
408             }
409             sub declare {
410 45     45 1 56154 my ( $class, $case, $is_runtime ) = @_;
411             # NG 06-03-18: improved code to recognize that user can set $CASE in module
412             # this is first step toward deprecating this parameter
413 45 100       150 if (defined $case) {
414 6         18 CASE($class,$case); # save $case for run-time
415             } else {
416 39         106 $case=CASE($class); # else, set $case from $CASE
417             }
418             ########################################
419             # NG 05-12-08,09: added code to compute RECURSIVE values, IATTRIBUTES, CATTRIBUTES
420 45         79 my @attributes_recursive;
421             my %iattributes_recursive;
422 0         0 my %cattributes_recursive;
423 0         0 my %synonyms_recursive;
424 0         0 my $defaults_recursive;
425             # get info from superclasses. recursively, this includes all ancestors
426             # NG 06-03-14: split loop to get all supers that are AutoClasses
427             # and make sure they are declared. If any not declared,
428             # have to defer this declaration to run-time
429 0         0 my $defer;
430 45         144 for my $super (ISA($class)) {
431 52 100       189 next if $super eq 'Class::AutoClass';
432             ####################
433             # NG 05-12-09: added check for super classes not yet used
434             # Caution: this all works fine if people follow the Perl convention of
435             # placing module Foo in file Foo.pm. Else, there's no easy way to
436             # translate a classname into a string that can be 'used'
437             # The test 'unless %{$class.'::'}' cause the 'use' to be skipped if
438             # the class is already loaded. This should reduce the opportunities
439             # for messing up the class-to-file translation.
440             # Note that %{$super.'::'} is the symbol table for the class
441 12     12   82 { no strict 'refs';
  12         23  
  12         2471  
  28         39  
442 28 100       37 unless (%{$super.'::'}) {
  28         188  
443 3         213 eval "use $super";
  8         397  
  11         59  
  11         75  
444 3 50       14 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" if $@;
445             }}
446             # next unless UNIVERSAL::isa($super,'Class::AutoClass');
447             # NG 06-03-14: handle different cases of $super being declared
448             # at runtime, okay to declare $super now since entire module
449             # has been parsed.
450             # at compile time, there is no guarantee that AutoClass variables
451             # have yet been parsed. so, we defer declaration of current class
452             # until $super is declared. CAUTION: this writes into $super's
453             # namespace which is rude if $super is not an AutoClass class !!!
454 28 100       73 if (!DECLARED($super)) {
455 7 100       15 if ($is_runtime) {
456 4 100       31 if (UNIVERSAL::isa($super,'Class::AutoClass')) {
457 3         7 declare($super,CASE($class),$is_runtime);
458             } else { # not AutoClass class, so just call it declared
459 1         3 DECLARED($class,1);
460             }
461             } else {
462 3         10 AUTOCLASS_DEFERRED_DECLARE($super,$class); # push class onto super's deferred list
463 3         7 $defer=1; # causes return before loop that does the work
464             }
465             }
466             }
467             # NG 06-03-14: AutoDB registration must be done at compile-time. if this code get
468             # moved later, remember that hacking of @ISA has to happen before class
469             # hierarchy enumerated
470 45         149 my %autodb = AUTODB($class);
471 45 50       128 if (%autodb) {
472 12     12   75 no strict 'refs';
  12         23  
  12         37579  
473             # add AutoDB::Object to @ISA if necessary
474 0 0       0 unless ( grep /^Class::AutoDB::Object/, @{ $class . '::ISA' } ) {
  0         0  
475 0         0 unshift @{ $class . '::ISA' }, 'Class::AutoDB::Object';
  0         0  
476             }
477 0         0 require 'Class/AutoDB/Object.pm';
478 0         0 require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
479             }
480             # NG 05-12-02: auto-register subclasses which do not set %AUTODB
481             # if (%autodb) { # register after setting ANCESTORS
482 45 50       326 if (UNIVERSAL::isa($class,'Class::AutoDB::Object')) {
483 0         0 require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
484 0         0 my $args = Class::AutoClass::Args->new( %autodb, -class => $class ); # TODO - spec says %AUTODB=(1) should work
485 0         0 Class::AutoDB::auto_register($args);
486             }
487            
488 45 100       143 return if $defer;
489             # NG 06-03-14: this part of the loop does the work
490 42         107 for my $super (ISA($class)) {
491 47 100 100     291 next if $super eq 'Class::AutoClass' || !UNIVERSAL::isa($super,'Class::AutoClass');
492 23         74 push(@attributes_recursive,ATTRIBUTES_RECURSIVE($super));
493 23         46 my %h;
494 23         68 %h=IATTRIBUTES_RECURSIVE($super);
495 23         149 @iattributes_recursive{keys %h}=values %h;
496 23         88 undef %h;
497 23         59 %h=CATTRIBUTES_RECURSIVE($super);
498 23         80 @cattributes_recursive{keys %h}=values %h;
499 23         54 undef %h;
500 23         61 %h=SYNONYMS_RECURSIVE($super);
501 23         77 @synonyms_recursive{keys %h}=values %h;
502 23         56 my $d=DEFAULTS_RECURSIVE($super);
503 23         168 @$defaults_recursive{keys %$d}=values %$d;
504             }
505              
506             # add info from self. do this after parents so our defaults, synonyms override parents
507             # for IATTRIBUTES, don't add in any that are already defined, since this just creates
508             # redundant methods
509 42         169 my %synonyms = SYNONYMS($class);
510 42         65 my %iattributes;
511             my %cattributes;
512             # init cattributes to declared CLASS_ATTRIBUTES
513 42         108 map {$cattributes{$_}=$class} CLASS_ATTRIBUTES($class);
  64         167  
514             # iattributes = all attributes that are not cattributes
515 42 50 33     121 map {$iattributes{$_}=$class unless $iattributes_recursive{$_} || $cattributes{$_}}
  150         1026  
516             (AUTO_ATTRIBUTES($class),OTHER_ATTRIBUTES($class));
517             # add in synonyms
518 42         178 while(my($syn,$real)=each %synonyms) {
519 47 50 33     142 confess "Inconsistent declaration for attribute $syn: both synonym and real attribute"
520             if $cattributes{$syn} && $iattributes{$syn};
521 47 100 66     230 $cattributes{$syn}=$class if $cattributes{$real} || $cattributes_recursive{$real};
522 47 100 100     284 $iattributes{$syn}=$class if $iattributes{$real} || $iattributes_recursive{$real};
523             }
524 42         208 IATTRIBUTES($class,%iattributes);
525 42         217 CATTRIBUTES($class,%cattributes);
526 42         373 ATTRIBUTES($class,keys %iattributes,keys %cattributes);
527              
528             # store our attributes into recursives
529 42         315 @iattributes_recursive{keys %iattributes}=values %iattributes;
530 42         131 @cattributes_recursive{keys %cattributes}=values %cattributes;
531 42         151 push(@attributes_recursive,keys %iattributes,keys %cattributes);
532             # are all these declarations consistent?
533 42 100       231 if (my @inconsistents=grep {exists $cattributes_recursive{$_}} keys %iattributes_recursive) {
  364         1653  
534             # inconsistent class vs. instance declarations
535 1         5 my @errstr=("Inconsistent declarations for attribute(s) @inconsistents");
536 2         8 map {
537 1         2 push(@errstr,
538             "\tAttribute $_: declared instance attribute in $iattributes_recursive{$_}, class attribute in $cattributes_recursive{$_}");
539             } @inconsistents;
540 1         370 confess join("\n",@errstr);
541             }
542             # store our synonyms into recursive
543 41         135 @synonyms_recursive{keys %synonyms}=values %synonyms;
544             # store our defaults into recursive
545              
546 41         128 my $d=DEFAULTS($class);
547 41         306 @$defaults_recursive{keys %$d}=values %$d;
548             # store computed values into class
549 41         167 ATTRIBUTES_RECURSIVE($class,@attributes_recursive);
550 41         289 IATTRIBUTES_RECURSIVE($class,%iattributes_recursive);
551 41         357 CATTRIBUTES_RECURSIVE($class,%cattributes_recursive);
552 41         189 SYNONYMS_RECURSIVE($class,%synonyms_recursive);
553 41         183 DEFAULTS_RECURSIVE($class,$defaults_recursive);
554              
555             # note that attributes are case sensitive, while defaults and args are not.
556             # (this may be a crock, but it's documented this way). to deal with this, we build
557             # a map from de-cased attributes to attributes. really, the map takes use from
558             # id's as fixed by Args to attributes as they exist here
559 41         53 my %fixed_attributes;
560 41         1468 my @fixed_attributes=Class::AutoClass::Args::fix_keywords(@attributes_recursive);
561 41         276 @fixed_attributes{@attributes_recursive}=@fixed_attributes;
562 41         248 FIXED_ATTRIBUTES_RECURSIVE($class,%fixed_attributes);
563              
564             ########################################
565              
566             # enumerate internal super-classes and find an external class to create object
567              
568             # NG 06-03-14: moved code for AutoDB registration higher.
569             # my %autodb = AUTODB($class);
570             # if (%autodb) { # hack ISA before setting ancestors
571             # no strict 'refs';
572              
573             # # add AutoDB::Object to @ISA if necessary
574             # unless ( grep /^Class::AutoDB::Object/, @{ $class . '::ISA' } ) {
575             # unshift @{ $class . '::ISA' }, 'Class::AutoDB::Object';
576             # }
577             # require 'Class/AutoDB/Object.pm';
578             # require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
579             # }
580              
581 41         228 my ( $ancestors, $can_new ) = _enumerate($class);
582 41         126 ANCESTORS( $class, $ancestors );
583 41         99 CAN_NEW( $class, $can_new );
584              
585             # DEFAULTS_ARGS( $class, new Class::AutoClass::Args( DEFAULTS($class) ) ); # convert DEFAULTS hash into AutoArgs. NG 05-12-08: commented out since logic moved to DEFAULTS sub
586              
587             # # NG 05-12-02: auto-register subclasses which do not set %AUTODB
588             # # if (%autodb) { # register after setting ANCESTORS
589             # if (UNIVERSAL::isa($class,'Class::AutoDB::Object')) { # register after setting ANCESTORS
590             # require 'Class/AutoDB.pm'; # AutoDB.pm is needed for calling auto_register
591             # my $args = Class::AutoClass::Args->new( %autodb, -class => $class ); # TODO - spec says %AUTODB=(1) should work
592             # Class::AutoDB::auto_register($args);
593             # }
594              
595             ########################################
596             # NG 05-12-09: changed loops to iterate separately over instance and class attributes.
597             # commented out code for AutoDB dispatch -- could never have run anyway
598             # since %keys never set. also not longer compatible with new
599             # Registration format.
600             # generate the methods
601            
602 41         94 my @auto_attributes=AUTO_ATTRIBUTES($class);
603 41         120 undef %iattributes;
604 41         92 %iattributes=IATTRIBUTES($class);
605 41 50       104 my @iattributes=grep {$iattributes{$_} && !exists $synonyms{$_}} @auto_attributes;
  120         582  
606 41         671 my @class_attributes=(@auto_attributes,CLASS_ATTRIBUTES($class));
607 41 100       78 my @cattributes=grep {$cattributes{$_} && !exists $synonyms{$_}} @class_attributes;
  183         759  
608              
609 41         93 for my $func (@iattributes) {
610 120         337 my $fixed_func = Class::AutoClass::Args::fix_keyword($func);
611 120         742 my $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
612             \$_[0]->{\'$fixed_func\'}=\$_[1]:
613             \$_[0]->{\'$fixed_func\'};}";
614 120 100   53   18072 eval $sub;
  53 100       1612  
  40 100       2860  
  53 100       1877  
  38 100       249  
  52         6176  
615             }
616 41         106 for my $func (@cattributes) {
617 63         182 my $fixed_func = Class::AutoClass::Args::fix_keyword($func);
618 63         380 my $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
619             \${$class\:\:$fixed_func\}=\$_[1]:
620             \${$class\:\:$fixed_func\};}";
621 63 100   24   5781 eval $sub;
  24 100       1257  
  26 100       352  
  22 100       188  
  31 100       2135  
  15 100       108  
  17         125  
622             }
623             # NG 05-12-08: commented out. $args was never set anyway... This renders moot the
624             # 'then' clause of the 'if' below. I left it in just in case I have to
625             # revert the change :)
626             # TODO: eliminate 'then' clause if not needed
627             # if ( $args and $args->{keys} ) {
628             # %keys = map { split } split /,/, $args->{keys};
629             # }
630             # if ( $keys{$func} ) { # AutoDB dispatch
631             # $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
632             # \$_[0] . '::AUTOLOAD'->{\'$fixed_func\'}=\$_[1]:
633             # \$_[0] . '::AUTOLOAD'->{\'$fixed_func\'};}";
634             # } else {
635             # if ( exists $cattributes{$func} ) {
636             # $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
637             # \${$class\:\:$fixed_func\}=\$_[1]:
638             # \${$class\:\:$fixed_func\};}";
639             # } else {
640             # $sub = '*' . $class . '::' . $func . "=sub{\@_>1?
641             # \$_[0]->{\'$fixed_func\'}=\$_[1]:
642             # \$_[0]->{\'$fixed_func\'};}";
643             # }
644             # }
645             # eval $sub;
646             # }
647 41         202 while ( my ( $func, $old_func ) = each %synonyms ) {
648 47 50       376 next if $func eq $old_func; # avoid redundant def if old same as new
649             # my $class_defined=$iattributes_recursive{$old_func} || $cattributes_recursive{$old_func};
650             # my $sub=
651             # '*' . $class . '::' . $func . '=\& ' . $class_defined . '::' . $old_func;
652 47         138 my $sub =
653             '*' . $class . '::' . $func . "=sub {\$_[0]->$old_func(\@_[1..\$\#_])}";
654 47     8   4641 eval $sub;
  32         12607  
655             }
656 41 100 100     214 if ( defined $case && $case =~ /lower|lc/i )
657             { # create lowercase versions of each method, too
658 1         3 for my $func (@iattributes,@cattributes) {
659 9         145 my $lc_func = lc $func;
660             next
661 9 100       22 if $lc_func eq $func; # avoid redundant def if func already lowercase
662 4         13 my $sub=
663             '*' . $class . '::' . $lc_func . '=\& '. $class . '::' . $func;
664             # my $sub =
665             # '*' . $class . '::' . $lc_func . "=sub {\$_[0]->$func(\@_[1..\$\#_])}";
666 4         199 eval $sub;
667             }
668             }
669 41 100 100     177 if ( defined $case && $case =~ /upper|uc/i )
670             { # create uppercase versions of each method, too
671 5         14 for my $func (@iattributes,@cattributes) {
672 19         32 my $uc_func = uc $func;
673             next
674 19 100       45 if $uc_func eq $func; # avoid redundant def if func already uppercase
675 17         40 my $sub=
676             '*' . $class . '::' . $uc_func . '=\& '. $class . '::' . $func;
677             # my $sub =
678             # '*' . $class . '::' . $uc_func . "=sub {\$_[0]->$func(\@_[1..\$\#_])}";
679 17         906 eval $sub;
680             }
681             }
682             # NG 05-12-08: removed $args from parameter list
683             # NG 05-12-09: converted call from method ($class->...) to function. removed eval that
684             # wrappped call. provided regression test for class that does not inherit
685             # from AutoClass
686 41         140 set_class_defaults($class);
687 41         123 DECLARED($class,1); # NG 06-02-03: so 'new' can know when to call declare
688              
689             # NG 06-03-14: Process deferred subclasses
690 41         98 my @deferreds=AUTOCLASS_DEFERRED_DECLARE($class);
691 41         532 for my $subclass (@deferreds) {
692 3 50       8 declare($subclass,CASE($subclass),$is_runtime) unless DECLARED($subclass);
693             }
694             }
695              
696             sub _enumerate {
697 74     42   2411 my ($class) = @_;
698 61         433 my $classes = [];
699 67         2014 my $types = {};
700 59         388 my $can_new;
701 69         940 __enumerate( $classes, $types, \$can_new, $class );
702 54         534 return ( $classes, $can_new );
703             }
704              
705             sub __enumerate {
706 12     12   99 no warnings;
  12         20  
  12         1465  
707 91     82   4314 my ( $classes, $types, $can_new, $class ) = @_;
708 114 100       683 die "Circular inheritance structure. \$class=$class"
709             if ( $types->{$class} eq 'pending' );
710 90 100       591 return $types->{$class} if defined $types->{$class};
711 82         295 $types->{$class} = 'pending';
712 91         181 my @isa;
713             {
714 12     12   68 no strict "refs";
  12         20  
  12         3207  
  82         116  
715 78         95 @isa = @{ $class . '::ISA' };
  78         323  
716             }
717 84         170 my $type = 'external';
718 81         144 for my $super (@isa) {
719 108 100       442 $type = 'internal', next if $super eq $AUTOCLASS;
720 43         293 my $super_type = __enumerate( $classes, $types, $can_new, $super );
721 40 100       150 $type = $super_type unless $type eq 'internal';
722             }
723 78 100 33     205 if ( !FORCE_NEW($class) && !$$can_new && $type eq 'internal' ) {
      66        
724 78         240 for my $super (@isa) {
725 84 100       418 next unless $types->{$super} eq 'external';
726 0 100       0 $$can_new = $super, last if $super->can('new');
727             }
728             }
729 78 100       273 push( @$classes, $class ) if $type eq 'internal';
730 78         141 $types->{$class} = $type;
731 78         188 return $types->{$class};
732             }
733              
734             sub _is_positional {
735 0 100   0   0 @_ % 2 || $_[0] !~ /^-/;
736             }
737             1;
738             __END__