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