perl
view release on metacpan or search on metacpan
dist/SelfLoader/lib/SelfLoader.pm view on Meta::CPAN
}x;
NEWERPERL
}
else {
eval <<'OLDERPERL';
# allow checking for valid ': attrlist' attachments
# (we use 'our' rather than 'my' here, due to the rather complex and buggy
# behaviour of lexicals with qr// and (??{$lex}) )
our $nested;
$nested = qr{ \( (?: (?> [^()]+ ) | (??{ $nested }) )* \) }x;
our $one_attr = qr{ (?> (?! \d) \w+ (?:$nested)? ) (?:\s*\:\s*|\s+(?!\:)) }x;
$AttrList = qr{ \s* : \s* (?: $one_attr )* }x;
OLDERPERL
}
}
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(AUTOLOAD);
sub Version {$VERSION}
sub DEBUG () { 0 }
my %Cache; # private cache for all SelfLoader's client packages
# in croak and carp, protect $@ from "require Carp;" RT #40216
sub croak { { local $@; require Carp; } goto &Carp::croak }
sub carp { { local $@; require Carp; } goto &Carp::carp }
AUTOLOAD {
our $AUTOLOAD;
print STDERR "SelfLoader::AUTOLOAD for $AUTOLOAD\n" if DEBUG;
my $SL_code = $Cache{$AUTOLOAD};
my $save = $@; # evals in both AUTOLOAD and _load_stubs can corrupt $@
unless ($SL_code) {
# Maybe this pack had stubs before __DATA__, and never initialized.
# Or, this maybe an automatic DESTROY method call when none exists.
$AUTOLOAD =~ m/^(.*)::/;
SelfLoader->_load_stubs($1) unless exists $Cache{"${1}::<DATA"};
$SL_code = $Cache{$AUTOLOAD};
$SL_code = "sub $AUTOLOAD { }"
if (!$SL_code and $AUTOLOAD =~ m/::DESTROY$/);
croak "Undefined subroutine $AUTOLOAD" unless $SL_code;
}
print STDERR "SelfLoader::AUTOLOAD eval: $SL_code\n" if DEBUG;
{
no strict;
eval $SL_code;
}
if ($@) {
$@ =~ s/ at .*\n//;
croak $@;
}
$@ = $save;
defined(&$AUTOLOAD) || die "SelfLoader inconsistency error";
delete $Cache{$AUTOLOAD};
goto &$AUTOLOAD
}
sub load_stubs { shift->_load_stubs((caller)[0]) }
sub _load_stubs {
# $endlines is used by Devel::SelfStubber to capture lines after __END__
my($self, $callpack, $endlines) = @_;
no strict "refs";
my $fh = \*{"${callpack}::DATA"};
use strict;
my $currpack = $callpack;
my($line,$name,@lines, @stubs, $protoype);
print STDERR "SelfLoader::load_stubs($callpack)\n" if DEBUG;
croak("$callpack doesn't contain an __DATA__ token")
unless defined fileno($fh);
# Protect: fork() shares the file pointer between the parent and the kid
if(sysseek($fh, tell($fh), 0)) {
open my $nfh, '<&', $fh or croak "reopen: $!";# dup() the fd
close $fh or die "close: $!"; # autocloses, but be
# paranoid
open $fh, '<&', $nfh or croak "reopen2: $!"; # dup() the fd "back"
close $nfh or die "close after reopen: $!"; # autocloses, but be
# paranoid
$fh->untaint;
}
$Cache{"${currpack}::<DATA"} = 1; # indicate package is cached
local($/) = "\n";
while(defined($line = <$fh>) and $line !~ m/^__END__/) {
if ($line =~ m/ ^\s* # indentation
sub\s+([\w:]+)\s* # 'sub' and sub name
(
(?:\([\\\$\@\%\&\*\;]*\))? # optional prototype sigils
(?:$AttrList)? # optional attribute list
)/x) {
push(@stubs, $self->_add_to_cache($name, $currpack,
\@lines, $protoype));
$protoype = $2;
@lines = ($line);
if (index($1,'::') == -1) { # simple sub name
$name = "${currpack}::$1";
} else { # sub name with package
$name = $1;
$name =~ m/^(.*)::/;
if (defined(&{"${1}::AUTOLOAD"})) {
\&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
die 'SelfLoader Error: attempt to specify Selfloading',
" sub $name in non-selfloading module $1";
} else {
$self->export($1,'AUTOLOAD');
}
}
} elsif ($line =~ m/^package\s+([\w:]+)/) { # A package declared
push(@stubs, $self->_add_to_cache($name, $currpack,
\@lines, $protoype));
$self->_package_defined($line);
$name = '';
@lines = ();
$currpack = $1;
$Cache{"${currpack}::<DATA"} = 1; # indicate package is cached
if (defined(&{"${1}::AUTOLOAD"})) {
\&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
( run in 0.452 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )