File Coverage

blib/lib/Class/Root.pm
Criterion Covered Total %
statement 655 776 84.4
branch 202 306 66.0
condition 74 153 48.3
subroutine 70 78 89.7
pod 0 1 0.0
total 1001 1314 76.1


line stmt bran cond sub pod time code
1             package Class::Root;
2              
3 11     11   35068 use 5.006000;
  11         36  
  11         420  
4 11     11   54 use warnings;
  11         19  
  11         293  
5 11     11   49 use strict;
  11         15  
  11         1978  
6              
7             =head1 NAME
8              
9             Class::Root - framework for writing perl OO modules
10              
11             =head1 VERSION
12              
13             Version 0.02
14              
15             =cut
16              
17             our $VERSION = '0.02';
18              
19             my $ROOT_CLASS = __PACKAGE__;
20              
21             package declare;
22              
23             sub import {
24 41     41   71 shift;
25 41         108 goto &Class::Root::LOCAL::declare;
26             }
27              
28             sub new {
29 213     213 0 287 my $class = shift;
30 213         571 my $self = { @_ };
31 213         809 bless $self, $class;
32             }
33              
34             $INC{"declare.pm"} = 1;
35              
36             package Class::Root::LOCAL;
37              
38 11     11   343 use strict;
  11         17  
  11         344  
39 11     11   46 use warnings;
  11         20  
  11         285  
40              
41 11     11   13600 use English;
  11         53627  
  11         74  
42 11     11   23887 use Carp;
  11         20  
  11         1142  
43             $Carp::Verbose = 0;
44              
45 11     11   13122 use Data::Dumper;
  11         131951  
  11         828  
46              
47 11     11   11716 use Filter::Util::Call;
  11         12339  
  11         2236  
48              
49             my @flags;
50             BEGIN {
51 11 100   11   82 *::CT_CHECKS = sub(){1} unless defined(&::CT_CHECKS);
52 11 100       66 *::RT_CHECKS = sub(){1} unless defined(&::RT_CHECKS);
53 11 50       56 *::LOCAL_SUBS = sub(){1} unless defined(&::LOCAL_SUBS);
54              
55 11         39 @flags = qw( AF MF CF PRIV PROT RO OVER VIRT SETOPTS );
56            
57 11         20 my $i = 0;
58            
59 11         24 foreach (@flags) {
60 99         126 my $n = $i++;
61 11     11   173 no strict 'refs';
  11         22  
  11         599  
62 99     4474   1279 *$_ = sub(){ 1<<$n };
  4474         10888  
63             }
64             }
65              
66             sub flags2hr {
67 0     0   0 my $flags = shift;
68 0         0 my $hr;
69 0         0 foreach (@flags) {
70 11     11   55 no strict 'refs';
  11         16  
  11         29074  
71 0 0       0 $hr->{$_} = $flags & &$_ ? 1 : 0;
72             }
73 0         0 return $hr;
74             }
75              
76             # here we save class attributes for all classes
77             my $class_data = {};
78              
79             # hash of all subs ( methods and attributes )
80             my $subs = {};
81              
82             # class schema hash
83             my $schema = {};
84              
85             sub init_schema {
86 33     33   57 my $class = shift;
87            
88 33         362 $schema->{$class} = {
89             NUMBER_OF_PARENTS => 0,
90             HAVE_CLASS_ATTR_VALUES => 0,
91             HAVE_INSTANCE_ATTR_VALUES => 0,
92             INSTANCE_ATTR_VALUES => {},
93             CLASS_ATTR_VALUES => {},
94             PROT_EXPORT => [],
95             LOCAL_SUBS => {},
96             SUBS => {},
97             CT_OPTS => {
98             VERBOSE_SOURCE_CODE_CHANGES => 0,
99             DEFINE_LOCAL_SUBS => 0,
100             VERBOSE => 0,
101             },
102             }
103             }
104              
105             init_schema($ROOT_CLASS);
106              
107             my @export_local = qw( declare attribute class_attribute attributes method class_method overwrite override private protected virtual readonly setopts setoptions setval setvalue );
108              
109             sub prefix {
110 279     279   381 my $str = shift;
111            
112 279         904 $str =~ s/:/_/g;
113 279         747 return $str."__";
114             };
115              
116             my $ROOT_CLASS_PREFIX = prefix($ROOT_CLASS);
117              
118             my %s2f = (
119             '_' => PRIV,
120             ':' => CF,
121             '?' => RO,
122             '*' => PROT,
123             '!' => OVER,
124             '~' => VIRT,
125             );
126              
127             sub method_name_ok {
128 66     66   94 local $_ = shift;
129 66         328 /^[_:?*!~]*[a-zA-Z]\w*$/;
130             }
131              
132             sub sflags2flags {
133 185     185   333 my $sflags = shift;
134            
135 185         205 my $flags = 0;
136 185         685 foreach ( unpack('A1' x length($sflags), $sflags) ) {
137 12         30 $flags |= $s2f{$_};
138             }
139 185         355 return $flags;
140             }
141              
142             sub c2cl {
143 25     25   40 my $class = shift;
144 25         80 return $class."::LOCAL";
145             }
146              
147             sub cl2c {
148 182     182   201 my $str = shift;
149 182         733 $str =~ s/::LOCAL$//;
150 182         352 return $str;
151             }
152              
153             sub vmesg {
154 565     565   651 my $class = shift;
155 565         620 my $mesg = shift;
156            
157 565         1268 my $verbose = $schema->{$class}->{CT_OPTS}->{VERBOSE};
158 565 50       1388 print STDERR $mesg if $verbose;
159             }
160              
161             sub declare {
162              
163 182     182   316 my $caller_local = caller();
164 182         320 my $caller = cl2c($caller_local);
165            
166 182         279 my @args = ();
167              
168             #print Dumper( \@_ );
169            
170 182         325 foreach ( @_ ) {
171 366 100       1027 if ( /^([+-])(.*)/ ) {
172 2 50       8 my $v = ( $1 eq '+' ) ? 1 : 0;
173 2         7 my $k = $2;
174 2         6 my $old_v = $schema->{$caller}->{CT_OPTS}->{$k};
175 2         7 $schema->{$caller}->{CT_OPTS}->{$k} = $v;
176            
177 2 50 33     20 if ( $k eq 'DEFINE_LOCAL_SUBS' and $v and !$old_v ) {
      33        
178 2         8 define_local_subs($caller_local, $caller, $caller);
179             }
180              
181             } else {
182 364         681 push @args, $_;
183             }
184             }
185              
186 182         442 @_ = @args;
187              
188 182         248 my $i = 0;
189 182         408 while ( @_ ) {
190            
191 182         232 my $name_str = shift;
192 182         234 my $hr = shift;
193            
194 182 50       555 unless ( defined $hr ) {
195 0         0 $hr = "declare"->new( FLAGS => AF, OPTS => {} );
196             }
197              
198 182 100       416 unless ( ref($hr) eq "declare" ) {
199 1         5 $hr = "declare"->new( FLAGS => AF, OPTS => { value => $hr } );
200             }
201            
202 182         172 if ( ::CT_CHECKS ) {
203 182         200 $i += 2;
204 182 50       415 croak "declare: syntax error - wrong argument in position $i\n" unless ref($hr) eq "declare";
205             }
206            
207 182 50       736 unless ( $name_str =~ /([:_?*!~]*)([a-zA-Z]\w*)$/ ) {
208 0         0 croak "Wrong format for method name -->$name_str<--\n";
209             }
210              
211 182         336 my $flags = sflags2flags($1);
212 182         310 my $pub_name = $2;
213              
214 182         291 $flags |= $hr->{FLAGS};
215              
216             #attribute flag is set by default
217 182 100       303 $flags |= AF unless $flags & MF;
218            
219 182         359 my $priv_name = prefix($caller) . $pub_name;
220              
221 182         293 my $opts = $hr->{OPTS};
222              
223 182         219 my $name = $pub_name;
224 182         205 my $key = $pub_name;
225 182         176 my $sub;
226             my $tied_sub;
227            
228 182 100       285 if ( $flags & AF ) {
229              
230 53         81 my $oro = $opts->{readonly};
231 53 50       125 if ( defined $oro ) {
232 0 0       0 $flags |= RO if $oro;
233 0 0       0 $flags = $flags | RO ^ RO unless $oro;
234             }
235             }
236            
237             # remove PRIV flag for RO attrs
238 182         296 my $ro_flags = $flags | PRIV ^ PRIV;
239              
240             # remove PROT flag for RO attrs
241 182         301 $ro_flags = $ro_flags | PROT ^ PROT;
242              
243             # force PRIV flag fo priv part of RO and PROT
244 182 100       295 $flags |= PRIV if $flags & (RO|PROT);
245            
246 182 100       276 if ( $flags & PRIV ) {
247 17         27 $name = $priv_name;
248 17         21 $key = $priv_name;
249             }
250            
251             # set options for existing method
252 182 100       266 if ( $flags & SETOPTS ) {
253 3         11 setopts_only( CLASS => $caller, NAME => $name, OPTS => $opts );
254 3         14 next;
255             }
256            
257 179 100       380 if ( exists $opts->{value} ) {
258 37 100       72 my $key = $flags & CF ? "CLASS" : "INSTANCE";
259 37         159 $schema->{$caller}->{$key."_ATTR_VALUES"}->{$name} = $opts->{value};
260 37         102 $schema->{$caller}->{"HAVE_".$key."_ATTR_VALUES"} = 1;
261             }
262              
263 179 100       273 $sub = $hr->{SUB} if $flags & MF;
264            
265 179 100       272 if ( $flags & AF ) {
266 50         140 ( $sub, $tied_sub ) = create_accessor( NAME => $name, KEY => $key, FLAGS => $flags );
267             }
268 179         441 make_method( CLASS => $caller, NAME => $name, FLAGS => $flags, SUB => $sub, TIED_SUB => $tied_sub );
269              
270 176         206 if ( ::RT_CHECKS ) {
271 176 100       811 if ( exists $opts->{check_value} ) {
272 3         9 $schema->{$caller}->{SUBS}->{$name}->{TIED} = 1;
273 3         8 $schema->{$caller}->{SUBS}->{$name}->{CHECK_VALUE} = $opts->{check_value};
274             }
275             }
276            
277 164 100       331 if ( $flags & RO ) {
278 8         18 ( my $ro_sub ) = create_accessor( NAME => $pub_name, KEY => $priv_name, FLAGS => $ro_flags );
279 8         19 make_method( CLASS => $caller, NAME => $pub_name, FLAGS => $ro_flags, SUB => $ro_sub, TIED_SUB => $tied_sub );
280             }
281             }
282             };
283              
284             sub setopts_only {
285 3     3   11 my %args = ( @_ );
286              
287 3         7 my $class = $args{CLASS};
288 3         6 my $name = $args{NAME};
289 3         6 my $opts = $args{OPTS};
290            
291 3         9 my $mhr = $schema->{$class}->{SUBS}->{$name};
292            
293 3         4 if ( ::CT_CHECKS ) {
294              
295 3 50       9 croak "Can't set options for undefined attribute $name" unless defined $mhr;
296            
297 3 50       8 croak "Can't set options for readonly attribute $name" if $mhr->{FLAGS} & RO;
298            
299 3 50       6 croak "Can't set options for method" if $mhr->{FLAGS} & MF;
300              
301             }
302            
303 3         6 my $value = $opts->{value};
304              
305 3 100       9 if ( defined $value ) {
306 2 50       13 my $key = $mhr->{FLAGS} & CF ? "CLASS" : "INSTANCE";
307 2         8 $schema->{$class}->{$key."_ATTR_VALUES"}->{$name} = $value;
308 2         8 $schema->{$class}->{"HAVE_".$key."_ATTR_VALUES"} = 1;
309             }
310            
311 3         5 if ( ::RT_CHECKS ) {
312 3 100       11 if ( defined $opts->{check_value} ) {
313 2         5 $schema->{$class}->{SUBS}->{$name}->{TIED} = 1;
314 2         9 $schema->{$class}->{SUBS}->{$name}->{CHECK_VALUE} = $opts->{check_value};
315             }
316             }
317              
318             }
319              
320             sub gen_sub {
321              
322 132     132   154 my $name = shift;
323 132         148 my $flag = shift;
324              
325 132   100     669 my $setopts = ( $name =~ /^setopt(ion)?s$/ or $name =~ /^setval(ue)?$/ );
326              
327             my $sub = sub {
328              
329             #print "$name: ", Dumper(\@_);
330            
331 80     80   2318 my @ret = ();
332 80         267 my $hr = "declare"->new( FLAGS => 0, OPTS => {} );
333              
334 80 100       215 if ( @_ ) {
335            
336 75         115 my $arg0 = shift;
337            
338 75 100       148 if ( $setopts ) {
339              
340 10         21 my $val = $arg0;
341 10         14 my $val_pos = 1;
342            
343 10 100       29 if ( @_ ) {
344            
345 4 100       11 if ( method_name_ok($arg0) ) {
346 3         5 push @ret, $arg0;
347 3         8 $hr->{FLAGS} = SETOPTS;
348            
349 3         6 $val = shift;
350 3         3 $val_pos = 2;
351             }
352             #croak "function \"$name\": couldn't have more then 2 arguments" if @_;
353             }
354              
355 10 50       91 if ( $name =~ /^setopt(ion)?s$/ ) {
356            
357 10 50       36 croak "function \"$name\": argument at position $val_pos is not an options hr" unless ref($val) eq "HASH";
358 10         39 my %known_options = (
359             value => 1,
360             check_value => 1
361             );
362            
363 10         42 foreach my $key ( keys %$val ) {
364 12 50       49 croak "function \"$name\": unknown option $key" unless exists $known_options{$key};
365             }
366            
367 10         39 $hr->{OPTS} = $val;
368            
369             } else {
370            
371 0         0 $hr->{OPTS} = { value => $val };
372             }
373              
374            
375             } else {
376              
377 65 100       183 if ( ref($arg0) eq "declare" ) {
    50          
378 3         8 $hr = $arg0
379            
380             } elsif ( ref($arg0) eq "HASH" ) {
381              
382 0         0 croak "function \"$name\": arg0 could be a method name or other declare subfunction\n";
383             } else {
384            
385 62 50       112 croak "function \"$name\": wrong format of method name arg0\n" unless method_name_ok($arg0);
386            
387 62         104 push @ret, $arg0;
388              
389 62 100       139 if ( @_ ) {
390 60         68 my $arg1 = shift;
391            
392             #croak "function \"$name\": couldn't have more then 2 arguments" if @_;
393            
394 60 100       123 if ( ref($arg1) eq "declare" ) {
395 28         56 $hr = $arg1;
396            
397             } else {
398            
399 32         110 $hr->{OPTS} = { value => $arg1 };
400             }
401             }
402             }
403             }
404             }
405              
406 80 100       250 unless ( $setopts ) {
407 70         123 my $flags = $hr->{FLAGS};
408 70         89 $flags |= $flag;
409 70         127 $flags = $flags | SETOPTS ^ SETOPTS;
410 70         133 $hr->{FLAGS} = $flags;;
411             }
412            
413 80         129 push @ret, $hr, @_;
414            
415 80         412 return @ret;
416 132         793 };
417              
418 11     11   152 no strict 'refs';
  11         23  
  11         18526  
419 132         792 *$name = $sub;
420             };
421              
422             my %declare_subs = (
423             attribute => AF,
424             class_attribute => CF|AF,
425             protected => PROT,
426             private => PRIV,
427             virtual => VIRT,
428             overwrite => OVER,
429             override => OVER,
430             readonly => RO,
431             setopts => SETOPTS,
432             setoptions => SETOPTS,
433             setval => SETOPTS,
434             setvalue => SETOPTS,
435             );
436              
437             while ( my ($k, $v ) = each %declare_subs ) {
438             gen_sub($k, $v);
439             }
440              
441             sub method(;&) {
442             #print "method: ", Dumper(\@_);
443 50     50   119 my $sub = shift;
444 50         110 return "declare"->new( FLAGS => MF, SUB => $sub, OPTS => {} );
445             };
446              
447             sub class_method(;&) {
448             #print "class_method: ", Dumper(\@_);
449 79     79   105 my $sub = shift;
450 79         142 return "declare"->new( FLAGS => CF|MF, SUB => $sub, OPTS => {} );
451             };
452              
453              
454             sub attributes {
455              
456 1     1   2 my @ret = ();
457              
458 1         3 foreach ( @_ ) {
459 3         7 foreach my $line ( split /\n/, $_ ) {
460            
461 3         5 $line =~ s/(^|\s)#.*//;
462            
463 3         7 foreach my $str ( split /\s+/, $line ) {
464            
465 3 50       7 next unless $str;
466            
467 3 50       14 unless ( $str =~ /^([_:?*]*)([a-zA-Z]\w*)$/ ) {
468 0         0 croak "Wrong attribute format for -->$str<--\n";
469             }
470              
471 3         7 my $flags_str = $1;
472 3         4 my $name = $2;
473            
474 3         7 my $flags = AF | sflags2flags($flags_str);
475              
476 3         11 push @ret, $name, "declare"->new( FLAGS => $flags, OPTS => {} );
477             }
478             }
479             }
480              
481 1         6 return @ret;
482             };
483              
484             if ( ::CT_CHECKS ) {
485              
486             *update_schema = sub {
487              
488 414     414   474 my $o = shift;
489 414         494 my $n = !$o;
490              
491 414         1655 my $hr = { @_ };
492              
493 414         708 my $name = delete $hr->{NAME};
494 414         658 my $class = delete $hr->{CLASS};
495              
496 414         579 my $cschema = $schema->{$class};
497 414         501 my $csubs = $cschema->{SUBS};
498            
499 414 100       890 unless ( exists $csubs->{$name} ) {
500 411         588 $csubs->{$name} = $hr;
501 411         891 return "";
502             }
503            
504 3         9 my $hr2 = $csubs->{$name};
505            
506 3 50       11 my $ohr = $o ? $hr : $hr2;
507 3 50       10 my $nhr = $o ? $hr2 : $hr;
508            
509 3         8 my $oflags = $ohr->{FLAGS};
510 3         8 my $oparent = $ohr->{PARENT};
511 3         8 my $osub = $ohr->{SUB};
512            
513 3         5 my $nflags = $nhr->{FLAGS};
514 3         6 my $nparent = $nhr->{PARENT};
515 3         6 my $nsub = $nhr->{SUB};
516              
517 3         15 my $ocf = $oflags & CF;
518 3         7 my $ncf = $nflags & CF;
519              
520 3 50       16 my $overstr = $class eq $nparent ? " (defined in class \"$class\")" : " (defined in base class \"$nparent\")";
521            
522 3 50       12 if ( $ncf != $ocf ) {
523            
524 0 0       0 my $type_str1 = $ncf ? "instance method" : "class method";
525 0 0       0 my $type_str2 = $ocf ? "instance method" : "class method";
526              
527 0         0 return "$type_str1 \"$name\"$overstr also defined as $type_str2 \"$name\" in base class \"$oparent\"";
528             }
529            
530             # same method in 2 base classes
531 3 50 33     20 if ( ($class ne $nparent) and ($oparent ne $nparent) ) {
532 0 0       0 unless ( $name =~ /^(init|class_init|DESTROY)$/ ) {
533 0         0 return "Method \"$name\"$overstr also defined in base class \"$oparent\"";
534             }
535             }
536              
537             # overwriting of nonvirtual method from base class
538 3 50 33     29 if ( ($class eq $nparent) and !($nflags & OVER) and !($oflags & VIRT) ) {
      33        
539 0         0 return "Method \"$name\"$overstr also defined in base class \"$oparent\"";
540             }
541            
542 3 100 66     8 if ( $nflags & AF and $nflags & OVER ) {
543 1         5 return "attributes couldn't be overwritten";
544             }
545              
546 2 50       8 return "" if ( $osub eq $nsub );
547            
548 2         13 $csubs->{$name} = $nhr;
549 2         9 return "";
550            
551             };
552             }
553              
554             # files for which we already have a filter
555             my %filter_line = ();
556              
557             # already seen classes
558             my %import_done = ();
559              
560             my $base_init_done_key = "_BASE_INIT_DONE";
561             my $base_destroy_done_key = "_BASE_DESTROY_DONE";
562             my $attr_init_done_key = "_ATTR_INIT_DONE";
563              
564             declare import => class_method {
565 25     25   42281 my $parent = shift;
566            
567 25         43 my $isa_arg = "";
568 25 100 100     165 if ( @_ and $_[0] eq "isa" ) {
569 17         36 $isa_arg = shift;
570             }
571              
572 25         90 my ( $caller, $caller_file, $caller_line ) = caller();
573 25         81 my $caller_local = c2cl($caller);
574              
575 25 100       91 unless ( exists $schema->{$caller} ) {
576 22         50 init_schema($caller);
577             }
578              
579 25         63 my $cschema = $schema->{$caller};
580 25         41 my $copts = $cschema->{CT_OPTS};
581            
582 25         47 my @args = ();
583 25         62 foreach ( @_ ) {
584 5 50       25 if ( /^([+-])(.*)/ ) {
585 5 50       19 my $v = ( $1 eq '+' ) ? 1 : 0;
586 5         19 $copts->{$2} = $v;
587             } else {
588 0         0 push @args, $_;
589             };
590             }
591            
592 25 100       117 unless ( $isa_arg ) {
593            
594 8 100       27 if ( $copts->{DEFINE_LOCAL_SUBS} ) {
595 5         13 define_local_subs($caller, $parent);
596             }
597            
598 7 50       67 if ( my $local_import = $caller_local->can("import") ) {
599 0         0 local @_ = ( $parent, @args );
600 0         0 goto $local_import;
601             } else {
602 7         344074 return;
603             }
604             }
605            
606 17         37 my $filter_prefix = prefix($caller);
607              
608 17         48 $filter_line{$caller_file} = $caller_line+1;
609              
610             filter_add(
611             sub {
612 617     617   235344 my $status;
613            
614 617 100       2798 if ( ( $status = filter_read() ) > 0 ) {
615            
616 613         1013 my $line = $filter_line{$caller_file}++;
617            
618 613 100       1939 if ( /^\s*package\s+([\w:]+)\s*;/ ) {
619 30 100       138 filter_del() unless ( $1 eq $caller_local );
620             }
621              
622             # $class_foo->_PrivMethod will be translated in $class_foo->Class__Foo__PrivMethod
623 613         927 my $sav_line = "$_";
624 613         627 my $changed = 0;
625              
626 613 50       1128 if ( $filter_prefix ) {
627 613 100       1500 s/((-\>\s*)_(?=[A-Za-z]))/$2$filter_prefix/g and $changed=1 ;
628             }
629              
630             # $obj->__Some_Method will be translated in $obj->_Some_Method
631 613 100       1262 s/(-\>\s*_)_/$1/g and $changed=1;
632            
633 613         716 if ( ::CT_CHECKS ) {
634              
635 613         898 my $verbose_sf = $copts->{VERBOSE_SOURCE_CODE_FILTER};
636 613         1177 my $verbose = $copts->{VERBOSE};
637              
638 613 50 33     1765 if ( $changed and ($verbose or $verbose_sf) ) {
      66        
639 0         0 print STDERR "Changing source file \"$caller_file\", line $line:\nfrom..> ${sav_line}to....> $_";
640             }
641             }
642             }
643              
644 617         513641 $status;
645             }
646 17         141 );
647              
648             # @ISA
649              
650 17         319 my $caller_isa = $caller."::ISA";
651              
652 17         22 if ( ::CT_CHECKS ) {
653 17         67 vmesg($caller,"push $parent to \@$caller_isa\n");
654             }
655              
656 11     11   74 { no strict 'refs';
  11         20  
  11         1593  
  17         30  
657 17         1809 push @$caller_isa, $parent;
658             }
659              
660 17         66 $cschema->{NUMBER_OF_PARENTS}++;
661            
662             # this should be done only once for each class
663 17 50       61 unless ( $import_done{$caller} ) {
664            
665 17         34 $import_done{$caller} = 1;
666            
667 17         98 $class_data->{$caller} = {
668             $base_init_done_key => {},
669             $attr_init_done_key => {},
670             };
671              
672 17         71 ( my $inc_key = $caller ) =~ s{::}{/}g;
673 17         25 $inc_key .= '.pm';
674 17         59 $INC{$inc_key} = 1;
675              
676             # export declare and subfunctions in caller's "LOCAL" package
677 17         34 foreach my $f ( @export_local ) {
678 272         442 my $caller_f = $caller_local."::".$f;
679              
680 272         277 if ( ::CT_CHECKS ) {
681 272         565 vmesg($caller,"Defining sub $caller_f\n");
682             }
683              
684 11     11   52 no strict 'refs';
  11         20  
  11         1465  
685 272         1476 *$caller_f = *$f;
686             }
687              
688 17         48 my $class_initialize = $caller_local."::class_initialize";
689              
690 17         27 if ( ::CT_CHECKS ) {
691 17         50 vmesg($caller,"Defining sub \"$class_initialize\"\n");
692             }
693            
694             my $generic_class_init_method = sub {
695 11     11   22 my $class = shift;
696 11         113 $class->base_class_init( "CALLER=$caller", @_ );
697 17         74 };
698              
699 17         47 my $caller_class_init = $caller."::class_init";
700              
701 11     11   53 { no strict 'refs';
  11         25  
  11         2976  
  17         22  
702             *$class_initialize = sub {
703            
704 17 100   17   781 unless ( defined(&$caller_class_init) ) {
705 15 100 33     204 if ( @_ or $cschema->{NUMBER_OF_PARENTS} > 1 or $cschema->{HAVE_CLASS_ATTR_VALUES} ) {
      66        
706 8         15 if ( ::CT_CHECKS ) {
707 8         54 vmesg($caller,"Defining sub \"$caller_class_init\" with generic code\n");
708             }
709              
710 8         62 *$caller_class_init = $generic_class_init_method;
711             }
712             }
713            
714 17         124 $caller->class_init( @_ )
715 17         150 };
716             }
717            
718 17         56 my $class_verify = $caller_local."::class_verify";
719              
720 17         33 if ( ::CT_CHECKS ) {
721 17         59 vmesg($caller,"Defining sub \"$class_verify\"\n");
722             }
723            
724             my $generic_init_method = sub {
725 6     6   9 my $self = shift;
726 6         46 $self->base_init( "CALLER=$caller", @_ );
727 17         117 };
728              
729 17         42 my $caller_init = $caller."::init";
730            
731             my $generic_destroy_method = sub {
732 0     0   0 my $self = shift;
733 0         0 $self->base_destroy( "CALLER=$caller" );
734 17         106 };
735              
736 17         36 my $caller_destroy = $caller."::DESTROY";
737            
738 11     11   55 { no strict 'refs';
  11         15  
  11         10708  
  17         26  
739             *$class_verify = sub {
740            
741 17 50   17   3184 unless ( defined(&$caller_init) ) {
742 17 100 66     154 if ( $cschema->{NUMBER_OF_PARENTS} > 1 or $cschema->{HAVE_INSTANCE_ATTR_VALUES} ) {
743 6         8 if ( ::CT_CHECKS ) {
744 6         30 vmesg($caller,"Defining sub \"$caller_init\" with generic code\n");
745             }
746              
747 6         33 *$caller_init = $generic_init_method;
748             }
749             }
750              
751 17 50       125 unless ( defined(&$caller_destroy) ) {
752 17 50       70 if ( $cschema->{NUMBER_OF_PARENTS} > 1 ) {
753 0         0 if ( ::CT_CHECKS ) {
754 0         0 vmesg($caller,"Defining sub \"$caller_destroy\" with generic code\n");
755             }
756              
757 0         0 *$caller_destroy = $generic_destroy_method;
758             }
759             }
760            
761 17         133 $caller->class_schema_check( @_ )
762 17         136 };
763             }
764             }
765            
766 17         43 my $caller_prot_export = $cschema->{PROT_EXPORT};
767              
768 17         37 my $caller_prefix = prefix($caller);
769              
770 17         37 my $pschema = $schema->{$parent};
771 17         31 my $parent_prot_export = $pschema->{PROT_EXPORT};
772 17         48 my $parent_prefix = prefix($parent);
773            
774 17         45 foreach my $prot_m ( @$parent_prot_export ) {
775              
776 8         12 push @$caller_prot_export, $prot_m;
777 8         13 my $caller_prot_m = $caller_prefix.$prot_m;
778 8         19 my $parent_prot_m = $parent_prefix.$prot_m;
779            
780 8         16 my $caller_mname = $caller."::$caller_prot_m";
781 8         26 my $parent_mname = $parent."::$parent_prot_m";
782              
783 8         7 if ( ::CT_CHECKS ) {
784 8         22 vmesg($caller,"Defining sub $caller_mname as alias to $parent_mname\n");
785 8         17 my $pmhr = $pschema->{SUBS}->{$parent_prot_m};
786 8         20 my $err = update_schema( 1, CLASS => $caller, NAME => $caller_prot_m, SUB => $pmhr->{SUB}, PARENT => $parent, FLAGS => $pmhr->{FLAGS} );
787 8 50       30 croak "Schema error for class \"$caller\": $err\n" if $err;
788             }
789              
790 8         9 if ( ::LOCAL_SUBS ) {
791 8         15 my $pmhr = $pschema->{LOCAL_SUBS}->{$parent_prot_m};
792 8         20 $cschema->{LOCAL_SUBS}->{$caller_prot_m}->{SUB} = $pmhr->{SUB};
793 8         19 $cschema->{LOCAL_SUBS}->{$caller_prot_m}->{FLAGS} = $pmhr->{FLAGS};
794             }
795              
796 11     11   59 no strict 'refs';
  11         21  
  11         7151  
797 8         40 *$caller_mname = *$parent_mname;
798              
799             }
800            
801 17         23 if ( ::CT_CHECKS ) {
802 17         24 while ( my($m, $mhr) = each %{ $pschema->{SUBS} } ) {
  238         714  
803 221         290 my $sub = $mhr->{SUB};
804 221         297 my $parent = $mhr->{PARENT};
805 221         303 my $flags = $mhr->{FLAGS};
806 221         413 my $err = update_schema( 1, CLASS => $caller, NAME => $m, SUB => $sub, PARENT => $parent, FLAGS => $flags );
807 221 50       557 croak "Schema error: $err\n" if $err;
808             }
809             }
810              
811 17         29 if ( ::LOCAL_SUBS ) {
812 17         36 while ( my($m, $mhr) = each %{ $pschema->{LOCAL_SUBS} } ) {
  238         852  
813 221         274 my $flags = $mhr->{FLAGS};
814 221 100 66     367 next if ( $flags & PRIV or exists $cschema->{LOCAL_SUBS}->{$m} );
815 205         578 $cschema->{LOCAL_SUBS}->{$m}->{SUB} = $mhr->{SUB};
816 205         526 $cschema->{LOCAL_SUBS}->{$m}->{FLAGS} = $flags;
817             }
818             }
819             };
820              
821             sub define_local_subs {
822 7     7   13 my $caller = shift;
823 7         8 my $class = shift;
824 7         9 my $default_class = shift;
825            
826 7         9 croak "Can't define local subs with disabled LOCAL_SUBS\n" unless ::LOCAL_SUBS;
827            
828 7         21 my $clsubs = $schema->{$class}->{LOCAL_SUBS};
829            
830 7         46 while ( my($f, $mhr) = each %$clsubs ) {
831              
832 118         161 my $flags = $mhr->{FLAGS};
833            
834 118         181 my $priv = $flags & PRIV;
835              
836 118 100 66     521 next if ( $caller ne $class and $priv );
837            
838 102         129 my $sub = $mhr->{SUB};
839 102         132 my $prototype = prototype( $sub );
840 102 100 66     460 if ( defined $prototype and $prototype eq "" ) {
841 34 50       65 $f = "_$f" if $priv;
842 34 50       57 if ( $priv ) {
843 0         0 my $prefix = prefix($caller);
844 0         0 $f =~ s/^$prefix/_/;
845             }
846 34         55 my $caller_f = $caller."::".$f;
847              
848 34         40 my $lfsub = $sub;
849            
850 34         48 my $def = "";
851 34 100 100     79 if ( defined $default_class and $flags & CF ) {
852 5         11 my $ro = $flags & RO;
853              
854 5 100 66     9 if ($flags & RO and !$priv) {
855            
856             $lfsub = sub {
857 0   0 0   0 local $_ = shift || $default_class;
858 0         0 &$sub;
859 2         9 };
860              
861             } else {
862              
863             $lfsub = sub():lvalue {
864 1   33 1   8 local $_ = shift || $default_class;
865 1         4 &$sub;
866 3         27 };
867             }
868            
869 5         8 if ( ::CT_CHECKS ) {
870 5         8 $def = "D:$default_class";
871             }
872             }
873            
874 11     11   63 no strict 'refs';
  11         22  
  11         9689  
875              
876 34 100       129 if ( defined &$caller_f ) {
877 13 100       333 croak "Function \"$f\" already defined in package \"$caller\"\n" unless \&$caller_f eq $lfsub;
878             } else {
879              
880 21         22 if (::CT_CHECKS ) {
881 21         64 vmesg($caller,"Defining local sub $caller_f $def\n");
882             }
883            
884 21         141 *$caller_f = $lfsub;
885             }
886             }
887             }
888             }
889              
890             sub make_method {
891              
892 187     187   700 my %args = ( @_ );
893            
894 187         283 my $class = $args{CLASS};
895 187         250 my $name = $args{NAME};
896 187         220 my $flags = $args{FLAGS};
897 187         226 my $sub = $args{SUB};
898 187         217 my $tied_sub = $args{TIED_SUB};
899            
900 187         282 my $virt = $flags & VIRT;
901              
902 187         193 if ( ::CT_CHECKS ) {
903              
904 187 50       689 unless ( $name =~ /^[a-zA-Z]\w*$/ ) {
905 0         0 croak "Wrong method name: -->$name<--. Supported method names should match ".'/^[a-zA-Z]\w*$/'."\n";
906             }
907              
908 187 50 66     1301 if ( !$virt and !defined( $sub ) ) {
909 0         0 croak "class $class: implementation subroutine should be defined for non-virtual method \"$name\"\n";
910             }
911              
912 187 50 66     435 if ( $virt and defined( $sub ) ) {
913 0         0 croak "class $class: no implementation subroutine should be defined for virtual method \"$name\"\n";
914             }
915              
916 187         287 my $over = $flags & OVER;
917 187         295 my $cschema = $schema->{$class};
918 187         263 my $csubs = $cschema->{SUBS};
919              
920 187         187 my $code;
921 187 100 100     2118 if ( !$over and $code = $class->can($name) ) {
922 2 50       8 unless( $csubs->{$name}->{FLAGS} & VIRT ) {
923 2 50       19 my $bc = defined $csubs->{$name} ? $csubs->{$name}->{PARENT} : "???";
924              
925 2         4 my $mname = $name;
926 2 50       37 if ( $csubs->{$name}->{FLAGS} & PRIV ) {
927 0         0 my $prefix = prefix($class);
928 0         0 $mname =~ s/^$prefix/_/;
929             }
930 2         386 croak "class \"$class\": method \"$mname\" already defined in base class \"$bc\"\n";
931             }
932             }
933              
934 185 50 66     581 if ( $over and !$class->can($name) ) {
935 0         0 croak "class \"$class\": method $name not defined, can not overwrite\n";
936             }
937             }
938            
939 185 100       347 if ( $virt ) {
940             $sub = sub {
941 0     0   0 my ($package, $filename, $line ) = caller(1);
942 0         0 croak "call of virtual method \"$name\" defined in class \"$class\" from package \"$package\", file \"$filename\", line \"$line\"\n";
943 1         5 };
944             }
945              
946 185 100       312 if ( $flags & PROT ) {
947 8         15 my $prefix = prefix($class);
948 8         69 $name =~ /^$prefix(.*)/;
949 8         12 push @{ $schema->{$class}->{PROT_EXPORT} }, $1;
  8         32  
950             }
951            
952 185         362 my $method_name = $class."::".$name;
953              
954 185 100       502 unless ( exists $subs->{$sub} ) {
955 180         996 $subs->{$sub} = {
956             NAME => $name,
957             SUB => $sub,
958             TIED_SUB => $tied_sub,
959             }
960             }
961            
962 185         225 if ( ::CT_CHECKS ) {
963 185         381 my $err = update_schema( 0, CLASS => $class, PARENT => $class, NAME => $name, SUB => $sub, FLAGS => $flags );
964 185 100       548 croak "Schema error in class \"$class\": $err\n" if $err;
965             };
966              
967 184         169 if ( ::LOCAL_SUBS ) {
968 184         257 my $cschema = $schema->{$class};
969 184         537 $cschema->{LOCAL_SUBS}->{$name}->{SUB} = $sub;
970 184         399 $cschema->{LOCAL_SUBS}->{$name}->{FLAGS} = $flags;
971             }
972              
973 184         183 if ( ::CT_CHECKS ) {
974 184         602 vmesg($class,"Defining sub $method_name\n");
975             }
976            
977             {
978 11     11   64 no strict 'refs';
  11         19  
  11         501  
  184         210  
979 184 100 100     1132 if ( $name eq "class_init" or $name eq "init" or $name eq "DESTROY" ) {
      66        
980 11     11   57 no warnings;
  11         19  
  11         3752  
981 24         76 *$method_name = $sub;
982             } else {
983 160         453 *$method_name = $sub;
984             }
985             }
986              
987 184         194 if ( ::LOCAL_SUBS ) {
988            
989 184 100       879 if ( $schema->{$class}->{CT_OPTS}->{DEFINE_LOCAL_SUBS} ) {
990 16         29 my $local_func_name = $class."::LOCAL::".$name;
991            
992 16         25 my $cf = $flags & CF;
993 16         28 my $ro = $flags & RO;
994 16         24 my $priv = $flags & PRIV;
995            
996 16 100       32 if ( $priv ) {
997 8         12 my $prefix = prefix($class);
998 8         62 $name =~ /^$prefix(.*)/;
999 8         28 $local_func_name = $class."::LOCAL::_$1";
1000             }
1001              
1002 16         24 my $prototype = prototype( $sub );
1003 16 100 66     75 if ( defined $prototype and $prototype eq "" ) {
1004              
1005 15         17 my $lfsub = $sub;
1006            
1007 15         19 my $def = "";
1008 15 100       25 if ( $cf ) {
1009            
1010 7 100 100 3   47 $lfsub = ($ro and !$priv) ? sub{local $_=shift||$class; &$sub} : sub():lvalue{local $_=shift||$class; &$sub };
  1   33     10  
  1   33     3  
  3         46  
  3         6  
1011              
1012 7         11 $def = "D:$class";
1013             }
1014            
1015 15         20 if ( ::CT_CHECKS ) {
1016 15         44 vmesg($class,"Defining local sub $local_func_name\n");
1017             }
1018            
1019 11     11   58 no strict 'refs';
  11         26  
  11         4494  
1020 15         130 *$local_func_name = $lfsub;
1021             }
1022             }
1023             }
1024             };
1025              
1026             my $ties = {};
1027              
1028             if ( ::RT_CHECKS ) {
1029            
1030             *Class::Root::tiescalar::TIESCALAR = sub {
1031 49     49   85 my $class = shift;
1032 49         62 my $scalar = undef;
1033 49         204 return (bless \$scalar, $class);
1034             };
1035              
1036             *Class::Root::tiescalar::FETCH = sub {
1037 2     2   46 my $self = shift;
1038            
1039 2         7 my $hr = $ties->{$self}->{hr};
1040 2         4 my $key = $ties->{$self}->{key};
1041 2         7 return $hr->{$key};
1042             };
1043              
1044             *Class::Root::tiescalar::STORE = sub {
1045 8     8   12 my $self = shift;
1046            
1047 8         11 my $val = shift;
1048            
1049 8         16 my $hr = $ties->{$self}->{hr};
1050 8         51 my $key = $ties->{$self}->{key};
1051 8         17 my $class = $ties->{$self}->{class};
1052 8         18 my $name = $ties->{$self}->{subname};
1053              
1054             my $chk_sub = sub {
1055 8     8   10 my $sub = shift;
1056            
1057 8         9 local $_ = $val;
1058 8         26 my $err = &$sub;
1059 8 100       654 croak "check_value error for attr ", $name, " : $err" if $err;
1060 8         33 };
1061              
1062 8         22 my $rec_check;
1063             $rec_check = sub {
1064 13     13   17 my $class = shift;
1065 13         35 my $sub = $schema->{$class}->{SUBS}->{$name}->{CHECK_VALUE};
1066 13 100       37 &$chk_sub($sub) if defined $sub;
1067              
1068 9         5 my @class_isa;
1069 11     11   59 { no strict 'refs';
  11         25  
  11         14601  
  9         10  
1070 9         25 @class_isa = @{$class."::ISA"};
  9         41  
1071             }
1072              
1073 9         25 foreach my $parent ( @class_isa ) {
1074 5         16 $rec_check->($parent);
1075             }
1076 8         26 };
1077              
1078 8         18 $rec_check->($class);
1079            
1080 4         21 $hr->{$key} = $val;
1081             };
1082             }
1083              
1084             my $accessors = {};
1085              
1086             sub create_accessor {
1087              
1088 58     58   214 my %args = (
1089             @_,
1090             );
1091              
1092 58         99 my $name = $args{NAME};
1093 58         91 my $key = $args{KEY};
1094 58         1486 my $flags = $args{FLAGS};
1095              
1096 58         116 my $cf = $flags & CF;
1097 58         2646 my $ro = $flags & RO;
1098 58         89 my $priv = $flags & PRIV;
1099              
1100            
1101 58         178 my $akey = "$name/$key/$cf/$ro";
1102 58         92 my $sub = $accessors->{$akey};
1103 58         64 my $tied_sub;
1104            
1105 58 100 100     218 if ( $ro and !$priv ) {
1106            
1107             $sub or $sub = sub () {
1108 15   66 15   2795 my $self = shift || $_;
1109 15   66     68 my $class = ref($self) || $self;
1110            
1111 15 100       39 if ( @_ ) {
1112 2 50       11 my $err = $cf ?
1113             "class \"$class\": couldn't set read only class attribute \"$name\"\n"
1114             :
1115             "instance of \"$class\": couldn't set read only attribute \"$name\"\n"
1116             ;
1117 2 50       400 croak $err if @_;
1118             }
1119            
1120 13 100       30 my $data = $cf ? $class_data->{$class} : $self;
1121              
1122 13         70 return $data->{$key};
1123             }
1124            
1125 8 50       47 } else {
1126            
1127             $sub or $sub = sub () : lvalue {
1128            
1129 128   66 128   6529 my $self = shift || $_;
1130 128   66     401 my $class = ref($self) || $self;
1131              
1132 128         228 if ( ::RT_CHECKS ) {
1133 128 100       474 if ( $schema->{$class}->{SUBS}->{$name}->{TIED} ) {
1134 11         24 unshift @_, $self;
1135 11         59 goto $subs->{$sub}->{TIED_SUB};
1136             }
1137             };
1138            
1139 118 100       246 my $data = $cf ? $class_data->{$class} : $self;
1140              
1141 118 100       396 $data->{$key} = shift if @_;
1142            
1143 118         564 $data->{$key};
1144 50 100       348 };
1145              
1146 49         69 if ( ::RT_CHECKS ) {
1147 49         211 my $tref = tie my $tie, "Class::Root::tiescalar";
1148            
1149 49         1626 $ties->{$tref} = {
1150             key => $key,
1151             subname => $name,
1152             };
1153              
1154             $tied_sub = sub () : lvalue {
1155 10   33 10   89 my $self = shift || $_;
1156 10   33     33 my $class = ref($self) || $self;
1157            
1158 10         31 $ties->{$tref}->{class} = $class;
1159 10 50       32 $ties->{$tref}->{hr} = $cf ? $class_data->{$class} : $self;
1160            
1161 10 100       23 if ( @_ ) {
1162 2         11 $tie = shift
1163             }
1164              
1165 10         43 $tie;
1166 49         294 };
1167             }
1168             }
1169              
1170 57         176 $accessors->{$akey} = $sub;
1171 57         203 return( $sub, $tied_sub );
1172             }
1173              
1174             declare new => class_method {
1175 6     6   1140 my $proto = shift;
1176 6   33     36 my $class = ref($proto) || $proto;
1177              
1178 6         11 my $self = {};
1179 6         128 $self->{$attr_init_done_key} = {};
1180 6         15 $self->{$base_init_done_key} = {};
1181              
1182 6         16 bless($self, $class);
1183              
1184 6         9 if ( ::RT_CHECKS ) {
1185            
1186 6         9 my $key = 0;
1187 6         18 foreach ( @_ ) {
1188 0         0 $key ^= 1;
1189 0 0 0     0 if ( $key and /^_/ ) {
1190 0         0 croak "constructor new: couldn't set private attribute \"$_\"\n";
1191             }
1192             }
1193             }
1194              
1195 6         26 $self->init( @_ );
1196              
1197 6         18 return $self;
1198             };
1199              
1200             my $root_init = sub {
1201             my $self = shift;
1202             my $class = ref($self);
1203            
1204             my %args = ( @_ );
1205              
1206             while ( my($k,$v) = each %args ) {
1207             my $method = $k;
1208             unless ( $self->{$attr_init_done_key}->{$method} ) {
1209             $self->{$attr_init_done_key}->{$method} = 1;
1210             if ( ::RT_CHECKS ) {
1211             eval { $self->$method($v) };
1212             croak "Error calling method \"$method\" for instance of class \"$class\": $EVAL_ERROR\n" if $EVAL_ERROR;
1213             } else {
1214             $self->$method($v);
1215             }
1216             }
1217             }
1218             };
1219              
1220 6     6   16 declare init => method { goto $root_init };
1221              
1222             declare base_init => method {
1223 6     6   10 my $self = shift;
1224            
1225 6         7 my $caller;
1226 6 50 33     52 if ( @_ and $_[0] =~ /^CALLER=(.*)/ ) {
1227 6         7 shift;
1228 6         17 $caller = $1;
1229             }
1230              
1231 6 50       16 unless ( defined $caller ) {
1232 0         0 $caller = caller();
1233 0         0 $caller =~ s/::LOCAL$//;
1234             }
1235              
1236 6         43 $self->{$base_init_done_key}->{$caller} = 1;
1237              
1238 6         10 my %attr_values = %{ $schema->{$caller}->{INSTANCE_ATTR_VALUES} };
  6         39  
1239 6         21 my @args = ( %attr_values );
1240            
1241 6         12 my $key = 0;
1242 6         17 my $prefix = prefix($caller);
1243              
1244 6         15 foreach ( @_ ) {
1245 0         0 my $attr = $_;
1246            
1247 0         0 $key ^= 1;
1248 0 0       0 $attr =~ s/^_/$prefix/ if $key;
1249              
1250 0         0 push @args, $attr;
1251             }
1252            
1253 6         7 my @caller_isa;
1254            
1255 11     11   96 { no strict 'refs';
  11         30  
  11         2874  
  6         9  
1256 6         8 @caller_isa = @{ $caller."::ISA" };
  6         30  
1257             }
1258            
1259 6         10 my $not_seen_parents = 0;
1260 6         11 for my $parent ( @caller_isa ) {
1261            
1262 6 50       21 next if $self->{$base_init_done_key}->{$parent};
1263              
1264 6 50       40 if ( my $code = $parent->can("init") ) {
1265 6         7 $not_seen_parents++;
1266 6         20 $self->$code( @args );
1267             }
1268             }
1269              
1270 6 50       40 unless ( $not_seen_parents ) {
1271 0         0 $self->$root_init(@args);
1272             }
1273             };
1274              
1275             declare base_destroy => method {
1276 0     0   0 my $self = shift;
1277            
1278 0         0 my $caller;
1279 0 0 0     0 if ( @_ and $_[0] =~ /^CALLER=(.*)/ ) {
1280 0         0 $caller = $1;
1281             }
1282              
1283 0 0       0 unless ( defined $caller ) {
1284 0         0 $caller = caller();
1285 0         0 $caller =~ s/::LOCAL$//;
1286             }
1287              
1288 0         0 $self->{$base_destroy_done_key}->{$caller} = 1;
1289            
1290 0         0 my @caller_isa;
1291            
1292 11     11   62 { no strict 'refs';
  11         20  
  11         5664  
  0         0  
1293 0         0 @caller_isa = @{ $caller."::ISA" };
  0         0  
1294             }
1295            
1296 0         0 for my $parent ( @caller_isa ) {
1297            
1298 0 0       0 next if $self->{$base_destroy_done_key}->{$parent};
1299              
1300 0 0       0 if ( my $code = $parent->can("DESTROY") ) {
1301 0         0 $self->$code;
1302             }
1303             }
1304              
1305             };
1306              
1307             my $root_class_init = sub {
1308             my $class = shift;
1309            
1310             my $cdata = $class_data->{$class};
1311              
1312             my %args = ( @_ );
1313              
1314             while ( my($k,$v) = each %args ) {
1315             my $method = $k;
1316             unless ( $cdata->{$attr_init_done_key}->{$method} ) {
1317             $cdata->{$attr_init_done_key}->{$method} = 1;
1318             if ( ::RT_CHECKS ) {
1319             eval { $class->$method($v) };
1320             croak "Error calling method \"$method\" for \"$class\": $EVAL_ERROR\n" if $EVAL_ERROR;
1321             } else {
1322             $class->$method($v);
1323             }
1324             }
1325             }
1326             };
1327              
1328 17     17   65 declare class_init => class_method { goto $root_class_init };
1329              
1330             declare base_class_init => class_method {
1331 13     13   41 my $class = shift;
1332 13         31 my $cdata = $class_data->{$class};
1333              
1334 13         18 my $caller;
1335 13 100 66     110 if ( @_ and $_[0] =~ /^CALLER=(.*)/ ) {
1336 11         26 shift;
1337 11         34 $caller = $1;
1338             }
1339            
1340 13 100       37 unless ( defined $caller ) {
1341 2         5 $caller = caller();
1342 2         9 $caller =~ s/::LOCAL$//;
1343             }
1344            
1345 13         49 $cdata->{$base_init_done_key}->{$caller} = 1;
1346              
1347 13         21 my %attr_values = %{ $schema->{$caller}->{CLASS_ATTR_VALUES} };
  13         81  
1348 13         52 my @args = ( %attr_values );
1349            
1350 13         21 my $key = 0;
1351 13         42 my $prefix = prefix($caller);
1352            
1353 13         117 foreach ( @_ ) {
1354 10         13 my $attr = $_;
1355              
1356 10         11 $key ^= 1;
1357 10 100       18 $attr =~ s/^_/$prefix/ if $key;
1358              
1359 10         23 push @args, $attr;
1360             }
1361            
1362 13         23 my @caller_isa;
1363            
1364 11     11   64 { no strict 'refs';
  11         24  
  11         13094  
  13         18  
1365 13         61 @caller_isa = @{ $caller."::ISA" };
  13         68  
1366             }
1367            
1368 13         23 my $not_seen_parents = 0;
1369 13         24 for my $parent ( @caller_isa ) {
1370              
1371 13 50       54 next if $cdata->{$base_init_done_key}->{$parent};
1372              
1373 13 50       103 if ( my $code = $parent->can("class_init") ) {
1374 13         116 $not_seen_parents++;
1375 13         40 $class->$code( @args );
1376             }
1377             }
1378              
1379 13 50       80 unless ( $not_seen_parents ) {
1380 0         0 $class->$root_class_init(@args);
1381             }
1382            
1383             };
1384              
1385             declare class_schema_check => class_method {
1386 17     17   36 my $class = shift;
1387            
1388 17         29 return 1 unless ::CT_CHECKS;
1389              
1390 17         34 my $err = "";
1391 17         29 while( my($name, $mhr) = each %{ $schema->{$class}->{SUBS} } ) {
  307         965  
1392            
1393             #print $name, Dumper($mhr);
1394              
1395 290         435 my $flags = $mhr->{FLAGS};
1396 290         375 my $parent = $mhr->{PARENT};
1397 290 100 100     425 if ( $flags & VIRT and $parent ne $class ) {
1398 1         9 $err .= "Virtual method \"$name\" defined in class \"$parent\" not implemented in derived class \"$class\"\n";
1399             }
1400             }
1401            
1402 17 100       58 if ( $err ) {
1403 1         175 croak $err;
1404             }
1405              
1406 16         468 return 1;
1407             };
1408              
1409              
1410             if ( ::CT_CHECKS ) {
1411              
1412             declare class_schema => class_method sub(){
1413              
1414 0     0     my $proto = shift;
1415 0   0       my $class = ref($proto) || $proto;
1416              
1417 0           my $local_caller = caller();
1418 0           my $caller = cl2c($local_caller);
1419            
1420 0 0         $class = $caller unless defined $class;
1421            
1422 0           my $cschema = $schema->{$class};
1423              
1424 0           my $str = "";
1425 0           $str .= "class \"$class\" schema:\n";
1426              
1427 0           my $csubs = $cschema->{SUBS};
1428            
1429 0           my $class_attributes = "";
1430 0           my $attributes = "";
1431 0           my $class_methods = "";
1432 0           my $methods = "";
1433            
1434 0           foreach my $m ( sort keys %$csubs ) {
1435 0           my $mhr = $csubs->{$m};
1436              
1437 0           my $flags = $mhr->{FLAGS};
1438 0           my $parent = $mhr->{PARENT};
1439 0           my $priv = $flags & PRIV;
1440 0           my $prot = $flags & PROT;
1441              
1442 0 0 0       next if ( $priv and !$prot and $parent ne $class );
      0        
1443            
1444 0           my $mflags = "";
1445 0 0 0       if ( $priv and !$prot ) {
1446 0           $mflags = "priv";
1447 0           my $prefix = prefix($class);
1448 0           $m =~ s/^$prefix/_/;
1449             }
1450              
1451 0 0         if ( $prot ) {
1452 0           $mflags = "prot";
1453 0           my $prefix = prefix($class);
1454 0 0         next unless ( $m =~ /^$prefix/ );
1455 0           $m =~ s/^$prefix/_/;
1456             }
1457              
1458 0 0         if ( $flags & VIRT ) {
1459 0           $mflags = "virt";
1460             }
1461              
1462 0 0 0       if ( $flags & RO and !$priv ) {
1463 0           $mflags = "ro";
1464             }
1465              
1466 0           my $r;
1467 0 0         $r = \$attributes if $flags & AF;
1468 0 0 0       $r = \$class_attributes if ( $flags & CF and $flags & AF);
1469 0 0         $r = \$methods if $flags & MF;
1470 0 0 0       $r = \$class_methods if ( $flags & CF and $flags & MF);
1471              
1472 0           $$r .= sprintf "%4s%-20s%-10s%s\n", "", $m, $mflags, $parent;
1473            
1474             }
1475            
1476 0           $str .= " class attributes:\n";
1477 0           $str .= $class_attributes;
1478            
1479 0           $str .= " attributes:\n";
1480 0           $str .= $attributes;
1481              
1482 0           $str .= " class methods:\n";
1483 0           $str .= $class_methods;
1484              
1485 0           $str .= " methods:\n";
1486 0           $str .= $methods;
1487            
1488 0           return $str;
1489             };
1490              
1491             my $dump = sub {
1492              
1493             my $proto = shift;
1494             my $o_dump = ref($proto) ? 1 : 0;
1495             my $class = ref($proto) || $proto;
1496            
1497             my $str = $o_dump ? "instance \"$proto\"" : "class \"$class\"";
1498             $str .= " dump:\n";
1499              
1500             my $self = $o_dump ? $proto : $class;
1501            
1502             my $hr = {};
1503              
1504             my $cschema = $schema->{$class};
1505              
1506             my $csubs = $cschema->{SUBS};
1507              
1508             foreach my $m ( keys %$csubs ) {
1509             my $mhr = $csubs->{$m};
1510              
1511             my $flags = $mhr->{FLAGS};
1512             my $parent = $mhr->{PARENT};
1513             my $priv = $flags & PRIV;
1514             my $prot = $flags & PROT;
1515            
1516             next unless ( $flags & AF );
1517              
1518             next if ( $o_dump and $flags & CF );
1519             next if ( !$o_dump and !($flags & CF) );
1520             next if ( $priv|$prot and $parent ne $class );
1521              
1522             my $nm = $m;
1523             if ( $priv|$prot ) {
1524             my $prefix = prefix($class);
1525              
1526             $nm =~ s/^$prefix/_/;
1527             }
1528            
1529 11     11   87 no strict 'refs';
  11         28  
  11         4081  
1530             $hr->{$nm} = $self->$m;
1531              
1532             }
1533            
1534             local $Data::Dumper::Indent = 1;
1535             local $Data::Dumper::Sortkeys = 1;
1536             my $dumper = Dumper( $hr );
1537             my @lines = split "\n", $dumper;
1538             my @less_lines = @lines[1..$#lines-1];
1539            
1540             $str .= join "\n", @less_lines;
1541             $str .= "\n" if scalar(@less_lines);
1542            
1543             return $str;
1544             };
1545              
1546             declare instance_dump => method {
1547 0     0     my $self = shift;
1548 0           my $class = ref($self);
1549              
1550 0           return $dump->($self);
1551             };
1552              
1553             declare class_dump => class_method {
1554 0     0     my $proto = shift;
1555 0   0       my $class = ref($proto) || $proto;
1556              
1557 0           return $dump->($class);
1558             };
1559              
1560             }
1561              
1562             1; # End of Class::Root
1563              
1564             __END__