package base; use strict 'vars'; use vars qw($VERSION); $VERSION = '2.14'; $VERSION = eval $VERSION; # constant.pm is slow sub SUCCESS () { 1 } sub PUBLIC () { 2**0 } sub PRIVATE () { 2**1 } sub INHERITED () { 2**2 } sub PROTECTED () { 2**3 } my $Fattr = \%fields::attr; sub has_fields { my($base) = shift; my $fglob = ${"$base\::"}{FIELDS}; return( ($fglob && 'GLOB' eq ref($fglob) && *$fglob{HASH}) ? 1 : 0 ); } sub has_version { my($base) = shift; my $vglob = ${$base.'::'}{VERSION}; return( ($vglob && *$vglob{SCALAR}) ? 1 : 0 ); } sub has_attr { my($proto) = shift; my($class) = ref $proto || $proto; return exists $Fattr->{$class}; } sub get_attr { $Fattr->{$_[0]} = [1] unless $Fattr->{$_[0]}; return $Fattr->{$_[0]}; } if ($] < 5.009) { *get_fields = sub { # Shut up a possible typo warning. () = \%{$_[0].'::FIELDS'}; my $f = \%{$_[0].'::FIELDS'}; # should be centralized in fields? perhaps # fields::mk_FIELDS_be_OK. Peh. As long as %{ $package . '::FIELDS' } # is used here anyway, it doesn't matter. bless $f, 'pseudohash' if (ref($f) ne 'pseudohash'); return $f; } } else { *get_fields = sub { # Shut up a possible typo warning. () = \%{$_[0].'::FIELDS'}; return \%{$_[0].'::FIELDS'}; } } sub import { my $class = shift; return SUCCESS unless @_; # List of base classes from which we will inherit %FIELDS. my $fields_base; my $inheritor = caller(0); my @isa_classes; my @bases; foreach my $base (@_) { if ( $inheritor eq $base ) { warn "Class '$inheritor' tried to inherit from itself\n"; } next if grep $_->isa($base), ($inheritor, @bases); if (has_version($base)) { ${$base.'::VERSION'} = '-1, set by base.pm' unless defined ${$base.'::VERSION'}; } else { my $sigdie; { local $SIG{__DIE__}; eval "require $base"; # Only ignore "Can't locate" errors from our eval require. # Other fatal errors (syntax etc) must be reported. die if $@ && $@ !~ /^Can't locate .*? at \(eval /; unless (%{"$base\::"}) { require Carp; local $" = " "; Carp::croak(<[0] = @$battr; if( keys %$dfields ) { warn <<"END"; $derived is inheriting from $base but already has its own fields! This will cause problems. Be sure you use base BEFORE declaring fields. END } # Iterate through the base's fields adding all the non-private # ones to the derived class. Hang on to the original attribute # (Public, Private, etc...) and add Inherited. # This is all too complicated to do efficiently with add_fields(). while (my($k,$v) = each %$bfields) { my $fno; if ($fno = $dfields->{$k} and $fno != $v) { require Carp; Carp::croak ("Inherited fields can't override existing fields"); } if( $battr->[$v] & PRIVATE ) { $dattr->[$v] = PRIVATE | INHERITED; } else { $dattr->[$v] = INHERITED | $battr->[$v]; $dfields->{$k} = $v; } } foreach my $idx (1..$#{$battr}) { next if defined $dattr->[$idx]; $dattr->[$idx] = $battr->[$idx] & INHERITED; } } 1; __END__