This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
VMS syntax nit in new MakeMaker test.
[perl5.git] / lib / base.pm
CommitLineData
dc6d0c4f
JH
1package base;
2
864f8ab4 3use strict 'vars';
dc6d0c4f 4use vars qw($VERSION);
28994922 5$VERSION = '2.10';
dc6d0c4f
JH
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};
28994922 21 return( ($fglob && 'GLOB' eq ref($fglob) && *$fglob{HASH}) ? 1 : 0 );
dc6d0c4f
JH
22}
23
24sub has_version {
25 my($base) = shift;
26 my $vglob = ${$base.'::'}{VERSION};
864f8ab4 27 return( ($vglob && *$vglob{SCALAR}) ? 1 : 0 );
dc6d0c4f
JH
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
YK
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
YK
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
JH
61}
62
dc6d0c4f
JH
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
CP
74 if ( $inheritor eq $base ) {
75 warn "Class '$inheritor' tried to inherit from itself\n";
76 }
77
dc6d0c4f
JH
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
RGS
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
JH
95Base class package "$base" is empty.
96 (Perhaps you need to 'use' the module which defines that package first.)
97ERROR
150ffd39
RGS
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
JH
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
JH
110 if ($fields_base) {
111 require Carp;
112 Carp::croak("Can't multiply inherit %FIELDS");
113 } else {
114 $fields_base = $base;
dc6d0c4f
JH
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
JH
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
JH
157 }
158 else {
159 $dattr->[$v] = INHERITED | $battr->[$v];
dc6d0c4f
JH
160 $dfields->{$k} = $v;
161 }
162 }
864f8ab4 163
446e776f
DM
164 foreach my $idx (1..$#{$battr}) {
165 next if defined $dattr->[$idx];
166 $dattr->[$idx] = $battr->[$idx] & INHERITED;
864f8ab4 167 }
dc6d0c4f
JH
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
EM
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
JH
191 require Foo;
192 require Bar;
193 push @ISA, qw(Foo Bar);
fb73857a 194 }
195
45e8908f
EM
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
JH
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
JB
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
A
220=head1 HISTORY
221
fb73857a 222This module was introduced with Perl 5.004_04.
223
9b6f3a27
CP
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