X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FAutoLoader.pm;h=be6429e6e832c76b1ab01785298e3709c016900e;hb=743a64fea7e861a13581486312a91a30a446b273;hp=dba8ca2f5fb1617497df7ed91d27f1f8b212f389;hpb=8990e3071044a96302560bbdb5706f3e74cf1bef;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/AutoLoader.pm b/lib/AutoLoader.pm index dba8ca2..be6429e 100644 --- a/lib/AutoLoader.pm +++ b/lib/AutoLoader.pm @@ -1,15 +1,168 @@ package AutoLoader; +use Carp; +$DB::sub = $DB::sub; # Avoid warning + +=head1 NAME + +AutoLoader - load functions only on demand + +=head1 SYNOPSIS + + package FOOBAR; + use Exporter; + use AutoLoader; + @ISA = qw(Exporter AutoLoader); + +=head1 DESCRIPTION + +This module tells its users that functions in the FOOBAR package are +to be autoloaded from F. See +L and L. + +=head2 __END__ + +The module using the autoloader should have the special marker C<__END__> +prior to the actual subroutine declarations. All code that is before the +marker will be loaded and compiled when the module is used. At the marker, +perl will cease reading and parsing. See also the B module, a +utility that automatically splits a module into a collection of files for +autoloading. + +When a subroutine not yet in memory is called, the C function +attempts to locate it in a directory relative to the location of the module +file itself. As an example, assume F is located in +F. The autoloader will look for perl +subroutines for this package in F. +The C<.al> file is named using the subroutine name, sans package. + +=head2 Loading Stubs + +The B module provide a special import() method that will +load the stubs (from F file) of the calling module. +These stubs are needed to make inheritance work correctly for class +modules. + +Modules that inherit from B should always ensure that they +override the AutoLoader->import() method. If the module inherit from +B like shown in the I section this is already taken +care of. For class methods an empty import() would do nicely: + + package MyClass; + use AutoLoader; # load stubs + @ISA=qw(AutoLoader); + sub import {} # hide AutoLoader::import + +You can also set up autoloading by importing the AUTOLOAD function +instead of inheriting from B: + + package MyClass; + use AutoLoader; # load stubs + *AUTOLOAD = \&AutoLoader::AUTOLOAD; + + +=head2 Package Lexicals + +Package lexicals declared with C in the main block of a package using +the B will not be visible to auto-loaded functions, due to the +fact that the given scope ends at the C<__END__> marker. A module using such +variables as package globals will not work properly under the B. + +The C pragma (see L) may be used in such situations +as an alternative to explicitly qualifying all globals with the package +namespace. Variables pre-declared with this pragma will be visible to any +autoloaded routines (but will not be invisible outside the package, +unfortunately). + +=head2 AutoLoader vs. SelfLoader + +The B is a counterpart to the B module. Both delay +the loading of subroutines, but the B accomplishes the goal via +the C<__DATA__> marker rather than C<__END__>. While this avoids the use of +a hierarchy of disk files and the associated open/close for each routine +loaded, the B suffers a disadvantage in the one-time parsing of +the lines after C<__DATA__>, after which routines are cached. B +can also handle multiple packages in a file. + +B only reads code as it is requested, and in many cases should be +faster, but requires a machanism like B be used to create the +individual files. The B will invoke B +automatically if the B is used in a module source file. + +=head1 CAVEAT + +On systems with restrictions on file name length, the file corresponding to a +subroutine may have a shorter name that the routine itself. This can lead to +conflicting file names. The I package warns of these potential +conflicts when used to split a module. + +=cut AUTOLOAD { - my $name = "auto/$AUTOLOAD.al"; - $name =~ s#::#/#g; + my $name; + # Braces used to preserve $1 et al. + { + my ($pkg,$func) = $AUTOLOAD =~ /(.*)::([^:]+)$/; + $pkg =~ s#::#/#g; + if (defined($name=$INC{"$pkg.pm"})) + { + $name =~ s#^(.*)$pkg\.pm$#$1auto/$pkg/$func.al#; + $name = undef unless (-r $name); + } + unless (defined $name) + { + $name = "auto/$AUTOLOAD.al"; + $name =~ s#::#/#g; + } + } + my $save = $@; eval {require $name}; if ($@) { - ($p,$f,$l) = caller($AutoLevel); - $@ =~ s/ at .*\n//; - die "$@ at $f line $l\n"; + if (substr($AUTOLOAD,-9) eq '::DESTROY') { + *$AUTOLOAD = sub {}; + } else { + # The load might just have failed because the filename was too + # long for some old SVR3 systems which treat long names as errors. + # If we can succesfully truncate a long name then it's worth a go. + # There is a slight risk that we could pick up the wrong file here + # but autosplit should have warned about that when splitting. + if ($name =~ s/(\w{12,})\.al$/substr($1,0,11).".al"/e){ + eval {require $name}; + } + if ($@){ + $@ =~ s/ at .*\n//; + croak $@; + } + } } + $@ = $save; + $DB::sub = $AUTOLOAD; # Now debugger know where we are. goto &$AUTOLOAD; } + +sub import { + my ($callclass, $callfile, $callline,$path,$callpack) = caller(0); + ($callpack = $callclass) =~ s#::#/#; + # Try to find the autosplit index file. Eg., if the call package + # is POSIX, then $INC{POSIX.pm} is something like + # '/usr/local/lib/perl5/POSIX.pm', and the autosplit index file is in + # '/usr/local/lib/perl5/auto/POSIX/autosplit.ix', so we require that. + # + # However, if @INC is a relative path, this might not work. If, + # for example, @INC = ('lib'), then + # $INC{POSIX.pm} is 'lib/POSIX.pm', and we want to require + # 'auto/POSIX/autosplit.ix' (without the leading 'lib'). + # + if (defined($path = $INC{$callpack . '.pm'})) { + # Try absolute path name. + $path =~ s#^(.*)$callpack\.pm$#$1auto/$callpack/autosplit.ix#; + eval { require $path; }; + # If that failed, try relative path with normal @INC searching. + if ($@) { + $path ="auto/$callpack/autosplit.ix"; + eval { require $path; }; + } + carp $@ if ($@); + } +} 1;