AutoReloader
view release on metacpan or search on metacpan
lib/AutoReloader.pm view on Meta::CPAN
# if more: package, filename [, checkfuncref [, auto ]]
sub gensub {
my $package = scalar(@_) == 1 ? caller : shift;
my $file = shift;
my $chkfunc = shift || $AL {'checksub'};
my $auto = shift || $AL {'auto'} || 'auto';
my $function;
{
($function = pop (@{[ File::Spec->splitpath($file) ]}) ) =~ s/\..*//;
$file .= $AL {'suffix'} || '.al' unless $file =~ /\.\w+$/;
unless (-e $file) {
my ($filename, $seen);
{
$filename = File::Spec -> catfile ($auto, $package, $file);
foreach my $d ('.',@INC) { # check current working dir first
my $f = File::Spec -> catfile ($d,$filename);
if (-e $f) {
$file = $f;
last;
}
}
last if $seen;
unless (-e $file) {
# redo the search with a truncated filename
$file =~ s/(\w{12,})(\.\w+)$/substr($1,0,11).$2/e;
$seen++;
redo;
}
}
die
"Can't locate function file '$filename' for package '$package'\n"
unless -e $file;
}
}
if (my $addr = $AL {'Inc'} -> {"$package\::$function"} ) {
return $AL {Sub} -> {$addr} -> {'outer'};
}
else {
# file not known yet
my $inner;
my $h = {};
my $cr = $chkfunc -> ($file);
my $subname = "$package\::$function";
$h = {
file => $file,
check => \$AL {'check'},
checksub => \$chkfunc,
checkref => \$cr,
function => $subname,
};
my $outer = load ($package, $file, $h) or die $@;
my $outeraddr = Scalar::Util::refaddr ($outer);
$h -> {'outer'} = $outer;
Scalar::Util::weaken ($h -> {'outer'});
$AL{Sub} -> {$outeraddr} = $h;
$AL{Inc} -> {$subname} = $outeraddr;
return bless $outer, __PACKAGE__;
}
};
{
my $load = \&load;
sub load {
my ($package, $file, $h) = @_;
delete $INC {$file};
my $ref = eval "package $package; require '$file'";
#warn $@ if $@;
return undef if $@;
{
# just in case the require dinn' return a ref -
# then a named subroutine has been loaded.
# All other cases are errors.
unless (
Scalar::Util::reftype($ref)
and
Scalar::Util::reftype($ref) eq 'CODE') {
$ref = \&{$h -> {'function'}};
no strict 'refs';
no warnings 'redefine';
*{$h -> {'function'} } = $h ->{'outer'} if $h -> {'outer'};
}
${$h->{inner}} = $ref;
my $sub = sub {
my $cr = $h -> {'checkref'};
if( ${ $h -> {'check'} } and ${ $h-> {'checksub'} }
and
( my $c = ${ $h->{checksub} } -> ($file) ) != $$cr) {
warn "reloading $file" if $Debug;
$$cr = $c;
$load -> ($package, $file, $h);
}
goto ${ $h -> {'inner'} };
};
}
}
}
sub DESTROY {
my $outeraddr = Scalar::Util::refaddr ($_[0]);
my $h = $AL {'Sub'} -> {$outeraddr};
delete $AL {'Inc'} -> { $h -> {'function'}};
delete $AL {'Sub'} -> {$outeraddr};
}
sub AUTOLOAD {
no strict;
my $sub = $AUTOLOAD;
my ($pkg, $func, $filename);
{
($pkg, $func) = ($sub =~ /(.*)::([^:]+)$/);
$pkg = File::Spec -> catdir (split /::/, $pkg);
}
my $save = $@;
( run in 0.770 second using v1.01-cache-2.11-cpan-39bf76dae61 )