File Coverage

blib/lib/base.pm
Criterion Covered Total %
statement 0 73 0.0
branch 0 32 0.0
condition 0 19 0.0
subroutine 0 7 0.0
pod 0 4 0.0
total 0 135 0.0


line stmt bran cond sub pod time code
1             package base;
2              
3             use strict 'vars';
4             use vars qw($VERSION);
5             $VERSION = '2.22';
6             $VERSION = eval $VERSION;
7              
8             # constant.pm is slow
9             sub SUCCESS () { 1 }
10              
11             sub PUBLIC () { 2**0 }
12             sub PRIVATE () { 2**1 }
13             sub INHERITED () { 2**2 }
14             sub PROTECTED () { 2**3 }
15              
16              
17             my $Fattr = \%fields::attr;
18              
19             sub has_fields {
20 0     0 0   my($base) = shift;
21 0           my $fglob = ${"$base\::"}{FIELDS};
  0            
22 0 0 0       return( ($fglob && 'GLOB' eq ref($fglob) && *$fglob{HASH}) ? 1 : 0 );
23             }
24              
25             sub has_attr {
26 0     0 0   my($proto) = shift;
27 0   0       my($class) = ref $proto || $proto;
28 0           return exists $Fattr->{$class};
29             }
30              
31             sub get_attr {
32 0 0   0 0   $Fattr->{$_[0]} = [1] unless $Fattr->{$_[0]};
33 0           return $Fattr->{$_[0]};
34             }
35              
36             if ($] < 5.009) {
37             *get_fields = sub {
38             # Shut up a possible typo warning.
39             () = \%{$_[0].'::FIELDS'};
40             my $f = \%{$_[0].'::FIELDS'};
41              
42             # should be centralized in fields? perhaps
43             # fields::mk_FIELDS_be_OK. Peh. As long as %{ $package . '::FIELDS' }
44             # is used here anyway, it doesn't matter.
45             bless $f, 'pseudohash' if (ref($f) ne 'pseudohash');
46              
47             return $f;
48             }
49             }
50             else {
51             *get_fields = sub {
52             # Shut up a possible typo warning.
53 0     0     () = \%{$_[0].'::FIELDS'};
  0            
54 0           return \%{$_[0].'::FIELDS'};
  0            
55             }
56             }
57              
58             if ($] < 5.008) {
59             *_module_to_filename = sub {
60             (my $fn = $_[0]) =~ s!::!/!g;
61             $fn .= '.pm';
62             return $fn;
63             }
64             }
65             else {
66             *_module_to_filename = sub {
67 0     0     (my $fn = $_[0]) =~ s!::!/!g;
68 0           $fn .= '.pm';
69 0           utf8::encode($fn);
70 0           return $fn;
71             }
72             }
73              
74              
75             sub import {
76 0     0     my $class = shift;
77              
78 0 0         return SUCCESS unless @_;
79              
80             # List of base classes from which we will inherit %FIELDS.
81 0           my $fields_base;
82              
83 0           my $inheritor = caller(0);
84              
85 0           my @bases;
86 0           foreach my $base (@_) {
87 0 0         if ( $inheritor eq $base ) {
88 0           warn "Class '$inheritor' tried to inherit from itself\n";
89             }
90              
91 0 0         next if grep $_->isa($base), ($inheritor, @bases);
92              
93             # Following blocks help isolate $SIG{__DIE__} changes
94             {
95 0           my $sigdie;
  0            
96             {
97 0           local $SIG{__DIE__};
  0            
98 0           my $fn = _module_to_filename($base);
99 0           eval { require $fn };
  0            
100             # Only ignore "Can't locate" errors from our eval require.
101             # Other fatal errors (syntax etc) must be reported.
102             #
103             # changing the check here is fragile - if the check
104             # here isn't catching every error you want, you should
105             # probably be using parent.pm, which doesn't try to
106             # guess whether require is needed or failed,
107             # see [perl #118561]
108 0 0 0       die if $@ && $@ !~ /^Can't locate \Q$fn\E .*? at .* line [0-9]+(?:, <[^>]*> (?:line|chunk) [0-9]+)?\.\n\z/s
      0        
109             || $@ =~ /Compilation failed in require at .* line [0-9]+(?:, <[^>]*> (?:line|chunk) [0-9]+)?\.\n\z/;
110 0 0         unless (%{"$base\::"}) {
  0            
111 0           require Carp;
112 0           local $" = " ";
113 0           Carp::croak(<
114             Base class package "$base" is empty.
115             (Perhaps you need to 'use' the module which defines that package first,
116             or make that module available in \@INC (\@INC contains: @INC).
117             ERROR
118             }
119 0   0       $sigdie = $SIG{__DIE__} || undef;
120             }
121             # Make sure a global $SIG{__DIE__} makes it out of the localization.
122 0 0         $SIG{__DIE__} = $sigdie if defined $sigdie;
123             }
124 0           push @bases, $base;
125              
126 0 0 0       if ( has_fields($base) || has_attr($base) ) {
127             # No multiple fields inheritance *suck*
128 0 0         if ($fields_base) {
129 0           require Carp;
130 0           Carp::croak("Can't multiply inherit fields");
131             } else {
132 0           $fields_base = $base;
133             }
134             }
135             }
136             # Save this until the end so it's all or nothing if the above loop croaks.
137 0           push @{"$inheritor\::ISA"}, @bases;
  0            
138              
139 0 0         if( defined $fields_base ) {
140 0           inherit_fields($inheritor, $fields_base);
141             }
142             }
143              
144              
145             sub inherit_fields {
146 0     0 0   my($derived, $base) = @_;
147              
148 0 0         return SUCCESS unless $base;
149              
150 0           my $battr = get_attr($base);
151 0           my $dattr = get_attr($derived);
152 0           my $dfields = get_fields($derived);
153 0           my $bfields = get_fields($base);
154              
155 0           $dattr->[0] = @$battr;
156              
157 0 0         if( keys %$dfields ) {
158 0           warn <<"END";
159             $derived is inheriting from $base but already has its own fields!
160             This will cause problems. Be sure you use base BEFORE declaring fields.
161             END
162              
163             }
164              
165             # Iterate through the base's fields adding all the non-private
166             # ones to the derived class. Hang on to the original attribute
167             # (Public, Private, etc...) and add Inherited.
168             # This is all too complicated to do efficiently with add_fields().
169 0           while (my($k,$v) = each %$bfields) {
170 0           my $fno;
171 0 0 0       if ($fno = $dfields->{$k} and $fno != $v) {
172 0           require Carp;
173 0           Carp::croak ("Inherited fields can't override existing fields");
174             }
175              
176 0 0         if( $battr->[$v] & PRIVATE ) {
177 0           $dattr->[$v] = PRIVATE | INHERITED;
178             }
179             else {
180 0           $dattr->[$v] = INHERITED | $battr->[$v];
181 0           $dfields->{$k} = $v;
182             }
183             }
184              
185 0           foreach my $idx (1..$#{$battr}) {
  0            
186 0 0         next if defined $dattr->[$idx];
187 0           $dattr->[$idx] = $battr->[$idx] & INHERITED;
188             }
189             }
190              
191              
192             1;
193              
194             __END__