Upgrade to PathTools 3.25
[p5sagit/p5-mst-13.2.git] / lib / base.pm
CommitLineData
dc6d0c4f 1package base;
2
864f8ab4 3use strict 'vars';
dc6d0c4f 4use vars qw($VERSION);
150ffd39 5$VERSION = '2.09';
dc6d0c4f 6
7# constant.pm is slow
8sub SUCCESS () { 1 }
9
10sub PUBLIC () { 2**0 }
11sub PRIVATE () { 2**1 }
12sub INHERITED () { 2**2 }
13sub PROTECTED () { 2**3 }
14
15
16my $Fattr = \%fields::attr;
17
18sub has_fields {
19 my($base) = shift;
20 my $fglob = ${"$base\::"}{FIELDS};
864f8ab4 21 return( ($fglob && *$fglob{HASH}) ? 1 : 0 );
dc6d0c4f 22}
23
24sub has_version {
25 my($base) = shift;
26 my $vglob = ${$base.'::'}{VERSION};
864f8ab4 27 return( ($vglob && *$vglob{SCALAR}) ? 1 : 0 );
dc6d0c4f 28}
29
30sub has_attr {
31 my($proto) = shift;
32 my($class) = ref $proto || $proto;
33 return exists $Fattr->{$class};
34}
35
36sub get_attr {
37 $Fattr->{$_[0]} = [1] unless $Fattr->{$_[0]};
38 return $Fattr->{$_[0]};
39}
40
8731c5d9 41if ($] < 5.009) {
42 *get_fields = sub {
43 # Shut up a possible typo warning.
44 () = \%{$_[0].'::FIELDS'};
45 my $f = \%{$_[0].'::FIELDS'};
dc6d0c4f 46
8731c5d9 47 # should be centralized in fields? perhaps
48 # fields::mk_FIELDS_be_OK. Peh. As long as %{ $package . '::FIELDS' }
49 # is used here anyway, it doesn't matter.
50 bless $f, 'pseudohash' if (ref($f) ne 'pseudohash');
51
52 return $f;
53 }
54}
55else {
56 *get_fields = sub {
57 # Shut up a possible typo warning.
58 () = \%{$_[0].'::FIELDS'};
59 return \%{$_[0].'::FIELDS'};
60 }
dc6d0c4f 61}
62
dc6d0c4f 63sub import {
64 my $class = shift;
65
66 return SUCCESS unless @_;
67
68 # List of base classes from which we will inherit %FIELDS.
69 my $fields_base;
70
71 my $inheritor = caller(0);
72
73 foreach my $base (@_) {
9b6f3a27 74 if ( $inheritor eq $base ) {
75 warn "Class '$inheritor' tried to inherit from itself\n";
76 }
77
dc6d0c4f 78 next if $inheritor->isa($base);
79
80 if (has_version($base)) {
81 ${$base.'::VERSION'} = '-1, set by base.pm'
82 unless defined ${$base.'::VERSION'};
83 }
84 else {
150ffd39 85 my $sigdie;
86 {
87 local $SIG{__DIE__};
88 eval "require $base";
89 # Only ignore "Can't locate" errors from our eval require.
90 # Other fatal errors (syntax etc) must be reported.
91 die if $@ && $@ !~ /^Can't locate .*? at \(eval /;
92 unless (%{"$base\::"}) {
93 require Carp;
94 Carp::croak(<<ERROR);
dc6d0c4f 95Base class package "$base" is empty.
96 (Perhaps you need to 'use' the module which defines that package first.)
97ERROR
150ffd39 98 }
99 $sigdie = $SIG{__DIE__};
100 }
101 # Make sure a global $SIG{__DIE__} makes it out of the localization.
102 $SIG{__DIE__} = $sigdie if defined $sigdie;
dc6d0c4f 103 ${$base.'::VERSION'} = "-1, set by base.pm"
104 unless defined ${$base.'::VERSION'};
105 }
106 push @{"$inheritor\::ISA"}, $base;
107
dc6d0c4f 108 if ( has_fields($base) || has_attr($base) ) {
3c4b39be 109 # No multiple fields inheritance *suck*
864f8ab4 110 if ($fields_base) {
111 require Carp;
112 Carp::croak("Can't multiply inherit %FIELDS");
113 } else {
114 $fields_base = $base;
dc6d0c4f 115 }
116 }
117 }
118
119 if( defined $fields_base ) {
120 inherit_fields($inheritor, $fields_base);
121 }
122}
123
124
125sub inherit_fields {
126 my($derived, $base) = @_;
127
128 return SUCCESS unless $base;
129
130 my $battr = get_attr($base);
131 my $dattr = get_attr($derived);
132 my $dfields = get_fields($derived);
133 my $bfields = get_fields($base);
134
135 $dattr->[0] = @$battr;
136
137 if( keys %$dfields ) {
138 warn "$derived is inheriting from $base but already has its own ".
139 "fields!\n".
45e8908f 140 "This will cause problems.\n".
dc6d0c4f 141 "Be sure you use base BEFORE declaring fields\n";
142 }
143
144 # Iterate through the base's fields adding all the non-private
145 # ones to the derived class. Hang on to the original attribute
146 # (Public, Private, etc...) and add Inherited.
147 # This is all too complicated to do efficiently with add_fields().
148 while (my($k,$v) = each %$bfields) {
149 my $fno;
150 if ($fno = $dfields->{$k} and $fno != $v) {
151 require Carp;
152 Carp::croak ("Inherited %FIELDS can't override existing %FIELDS");
153 }
154
155 if( $battr->[$v] & PRIVATE ) {
864f8ab4 156 $dattr->[$v] = PRIVATE | INHERITED;
dc6d0c4f 157 }
158 else {
159 $dattr->[$v] = INHERITED | $battr->[$v];
dc6d0c4f 160 $dfields->{$k} = $v;
161 }
162 }
864f8ab4 163
446e776f 164 foreach my $idx (1..$#{$battr}) {
165 next if defined $dattr->[$idx];
166 $dattr->[$idx] = $battr->[$idx] & INHERITED;
864f8ab4 167 }
dc6d0c4f 168}
169
170
1711;
172
173__END__
174
fb73857a 175=head1 NAME
176
45e8908f 177base - Establish IS-A relationship with base classes at compile time
fb73857a 178
179=head1 SYNOPSIS
180
181 package Baz;
fb73857a 182 use base qw(Foo Bar);
183
184=head1 DESCRIPTION
185
45e8908f 186Allows you to both load one or more modules, while setting up inheritance from
187those modules at the same time. Roughly similar in effect to
fb73857a 188
45e8908f 189 package Baz;
fb73857a 190 BEGIN {
dc6d0c4f 191 require Foo;
192 require Bar;
193 push @ISA, qw(Foo Bar);
fb73857a 194 }
195
45e8908f 196If any of the listed modules are not loaded yet, I<base> silently attempts to
197C<require> them (and silently continues if the C<require> failed). Whether to
198C<require> a base class module is determined by the absence of a global variable
199$VERSION in the base package. If $VERSION is not detected even after loading
200it, <base> will define $VERSION in the base package, setting it to the string
201C<-1, set by base.pm>.
202
dc6d0c4f 203Will also initialize the fields if one of the base classes has it.
3c4b39be 204Multiple inheritance of fields is B<NOT> supported, if two or more
dc6d0c4f 205base classes each have inheritable fields the 'base' pragma will
206croak. See L<fields>, L<public> and L<protected> for a description of
207this feature.
f1192cee 208
36c726b3 209=head1 DIAGNOSTICS
210
211=over 4
212
213=item Base class package "%s" is empty.
214
215base.pm was unable to require the base package, because it was not
216found in your path.
217
218=back
219
b8bc843f 220=head1 HISTORY
221
fb73857a 222This module was introduced with Perl 5.004_04.
223
9b6f3a27 224Attempting to inherit from yourself generates a warning:
225
226 use Foo;
227 use base 'Foo';
228
229 # Class 'Foo' tried to inherit from itself
fb73857a 230
dc6d0c4f 231=head1 CAVEATS
fb73857a 232
45e8908f 233Due to the limitations of the implementation, you must use
dc6d0c4f 234base I<before> you declare any of your own fields.
17f410f9 235
fb73857a 236
dc6d0c4f 237=head1 SEE ALSO
fb73857a 238
dc6d0c4f 239L<fields>
fb73857a 240
dc6d0c4f 241=cut