Mailing List Archive

My patch patch.2b1c to perl5.002beta1
# This is my patch c to perl5.002beta1.

exit 0 # Just in case

This is patch.2b1c to perl5.002beta1. This patch includes
lib/SelfLoader, version 1.06, and
lib/Devel/SelfStubber, version 1.01.
These versions include prototype support.

This is simply re-posting these library modules.
I have also updated MANIFEST to include them.

Nothing else is included.

cd to your perl source directory and type
patch -p1 -N < patch.2b1c

Patch and enjoy,

Andy Dougherty doughera@lafcol.lafayette.edu
Dept. of Physics
Lafayette College, Easton PA 18042


Index: MANIFEST
*** perl5.002b1b/MANIFEST Sat Dec 2 16:13:24 1995
--- perl5.002b1c/MANIFEST Sat Dec 2 16:12:54 1995
***************
*** 242,247 ****
--- 242,248 ----
lib/Benchmark.pm A module to time pieces of code and such
lib/Carp.pm Error message base class
lib/Cwd.pm Various cwd routines (getcwd, fastcwd, chdir)
+ lib/Devel/SelfStubber.pm Generate stubs for SelfLoader.pm
lib/English.pm Readable aliases for short variables
lib/Env.pm Map environment into ordinary variables
lib/Exporter.pm Exporter base class
***************
*** 266,271 ****
--- 267,273 ----
lib/Math/Complex.pm A Complex package
lib/Net/Ping.pm Ping methods
lib/Search/Dict.pm A module to do binary search on dictionaries
+ lib/SelfLoader.pm A module to load functions only on demand.
lib/Shell.pm A module to make AUTOLOADEed system() calls
lib/SubstrHash.pm Compact hash for known key, value and table size
lib/Sys/Hostname.pm Hostname methods
Index: lib/Devel/SelfStubber.pm
*** /dev/null Fri Dec 1 16:03:22 1995
--- perl5.002b1c/lib/Devel/SelfStubber.pm Sun Nov 26 16:14:19 1995
***************
*** 0 ****
--- 1,137 ----
+ package Devel::SelfStubber;
+ require SelfLoader;
+ @ISA = qw(SelfLoader);
+ $JUST_STUBS = 1;
+ $VERSION = 1.01; sub Version {$VERSION}
+
+ # Use as
+ # perl -e 'use Devel::SelfStubber;Devel::SelfStubber->stub(MODULE_NAME,LIB)'
+ # (LIB defaults to '.') e.g.
+ # perl -e 'use Devel::SelfStubber;Devel::SelfStubber->stub('Math::BigInt')'
+ # would print out stubs needed if you added a __DATA__ before the subs.
+ # Setting $Devel::SelfStubber::JUST_STUBS to 0 will print out the whole
+ # module with the stubs entered just before the __DATA__
+
+ sub _add_to_cache {
+ my($self,$fullname,$pack,$lines, $prototype) = @_;
+ push(@DATA,@{$lines});
+ if($fullname){push(@STUBS,"sub $fullname $prototype;\n")}; # stubs
+ '1;';
+ }
+
+ sub _package_defined {
+ my($self,$line) = @_;
+ push(@DATA,$line);
+ }
+
+ sub stub {
+ my($self,$module,$lib) = @_;
+ my($line,$end,$fh,$mod_file,$found_selfloader);
+ $lib ||= '.';
+ ($mod_file = $module) =~ s,::,/,g;
+
+ $mod_file = "$lib/$mod_file.pm";
+ $fh = "${module}::DATA";
+
+ open($fh,$mod_file) || die "Unable to open $mod_file";
+ while($line = <$fh> and $line !~ m/^__DATA__/) {
+ push(@BEFORE_DATA,$line);
+ $line =~ /use\s+SelfLoader/ && $found_selfloader++;
+ }
+ $line =~ m/^__DATA__/ || die "$mod_file doesn't contain a __DATA__ token";
+ $found_selfloader ||
+ print 'die "\'use SelfLoader;\' statement NOT FOUND!!\n"',"\n";
+ $self->_load_stubs($module);
+ if ( fileno($fh) ) {
+ $end = 1;
+ while($line = <$fh>) {
+ push(@AFTER_DATA,$line);
+ }
+ }
+ unless ($JUST_STUBS) {
+ print @BEFORE_DATA;
+ }
+ print @STUBS;
+ unless ($JUST_STUBS) {
+ print "1;\n__DATA__\n",@DATA;
+ if($end) { print "__END__\n",@AFTER_DATA; }
+ }
+ }
+
+ 1;
+ __END__
+ =head1 NAME
+
+ Devel::SelfStubber - generate stubs for a SelfLoading module
+
+ =head1 SYNOPSIS
+
+ To generate just the stubs:
+
+ use Devel::SelfStubber;
+ Devel::SelfStubber->stub('MODULENAME','MY_LIB_DIR');
+
+ or to generate the whole module with stubs inserted correctly
+
+ use Devel::SelfStubber;
+ $Devel::SelfStubber::JUST_STUBS=0;
+ Devel::SelfStubber->stub('MODULENAME','MY_LIB_DIR');
+
+ MODULENAME is the Perl module name, e.g. Devel::SelfStubber,
+ NOT 'Devel/SelfStubber' or 'Devel/SelfStubber.pm'.
+
+ MY_LIB_DIR defaults to '.' if not present.
+
+ =head1 DESCRIPTION
+
+ Devel::SelfStubber prints the stubs you need to put in the module
+ before the __DATA__ token (or you can get it to print the entire
+ module with stubs correctly placed). The stubs ensure that if
+ a method is called, it will get loaded. They are needed specifically
+ for inherited autoloaded methods.
+
+ This is best explained using the following example:
+
+ Assume four classes, A,B,C & D.
+
+ A is the root class, B is a subclass of A, C is a subclass of B,
+ and D is another subclass of A.
+
+ A
+ / \
+ B D
+ /
+ C
+
+ If D calls an autoloaded method 'foo' which is defined in class A,
+ then the method is loaded into class A, then executed. If C then
+ calls method 'foo', and that method was reimplemented in class
+ B, but set to be autoloaded, then the lookup mechanism never gets to
+ the AUTOLOAD mechanism in B because it first finds the method
+ already loaded in A, and so erroneously uses that. If the method
+ foo had been stubbed in B, then the lookup mechanism would have
+ found the stub, and correctly loaded and used the sub from B.
+
+ So, for classes and subclasses to have inheritance correctly
+ work with autoloading, you need to ensure stubs are loaded.
+
+ The SelfLoader can load stubs automatically at module initialization
+ with the statement 'SelfLoader->load_stubs()';, but you may wish to
+ avoid having the stub loading overhead associated with your
+ initialization (though note that the SelfLoader::load_stubs method
+ will be called sooner or later - at latest when the first sub
+ is being autoloaded). In this case, you can put the sub stubs
+ before the __DATA__ token. This can be done manually, but this
+ module allows automatic generation of the stubs.
+
+ By default it just prints the stubs, but you can set the
+ global $Devel::SelfStubber::JUST_STUBS to 0 and it will
+ print out the entire module with the stubs positioned correctly.
+
+ At the very least, this is useful to see what the SelfLoader
+ thinks are stubs - in order to ensure future versions of the
+ SelfStubber remain in step with the SelfLoader, the
+ SelfStubber actually uses the SelfLoader to determine which
+ stubs are needed.
+
+ =cut
Index: lib/SelfLoader.pm
*** /dev/null Fri Dec 1 16:03:22 1995
--- perl5.002b1c/lib/SelfLoader.pm Sun Nov 26 16:14:50 1995
***************
*** 0 ****
--- 1,284 ----
+ package SelfLoader;
+ use Carp;
+ require Exporter;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(AUTOLOAD);
+ $VERSION = 1.06; sub Version {$VERSION}
+ $DEBUG = 0;
+
+ my %Cache; # private cache for all SelfLoader's client packages
+
+ AUTOLOAD {
+ print STDERR "SelfLoader::AUTOLOAD for $AUTOLOAD\n" if $DEBUG;
+ my $code = $Cache{$AUTOLOAD};
+ unless ($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"};
+ $code = $Cache{$AUTOLOAD};
+ $code = "sub $AUTOLOAD { }" if (!$code and $AUTOLOAD =~ m/::DESTROY$/);
+ croak "Undefined subroutine $AUTOLOAD" unless $code;
+ }
+ print STDERR "SelfLoader::AUTOLOAD eval: $code\n" if $DEBUG;
+ eval $code;
+ if ($@) {
+ $@ =~ s/ at .*\n//;
+ croak $@;
+ }
+ defined(&$AUTOLOAD) || die "SelfLoader inconsistency error";
+ delete $Cache{$AUTOLOAD};
+ goto &$AUTOLOAD
+ }
+
+ sub load_stubs { shift->_load_stubs((caller)[0]) }
+
+ sub _load_stubs {
+ my($self, $callpack) = @_;
+ my $fh = \*{"${callpack}::DATA"};
+ 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 fileno($fh);
+ $Cache{"${currpack}::<DATA"} = 1; # indicate package is cached
+
+ while($line = <$fh> and $line !~ m/^__END__/) {
+ if ($line =~ m/^sub\s+([\w:]+)\s*(\([\$\@\;\%\\]*\))?/) { # A sub declared
+ 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 ||
+ die 'SelfLoader Error: attempt to specify Selfloading',
+ " package $currpack which already has AUTOLOAD";
+ } else {
+ $self->export($currpack,'AUTOLOAD');
+ }
+ } else {
+ push(@lines,$line);
+ }
+ }
+ close($fh) unless defined($line) && $line =~ /^__END__\s*DATA/; # __END__
+ push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
+ eval join('', @stubs) if @stubs;
+ }
+
+
+ sub _add_to_cache {
+ my($self,$fullname,$pack,$lines, $protoype) = @_;
+ return () unless $fullname;
+ carp("Redefining sub $fullname") if exists $Cache{$fullname};
+ $Cache{$fullname} = join('', "package $pack; ",@$lines);
+ print STDERR "SelfLoader cached $fullname: $Cache{$fullname}" if $DEBUG;
+ # return stub to be eval'd
+ defined($protoype) ? "sub $fullname $protoype;" : "sub $fullname;"
+ }
+
+ sub _package_defined {}
+
+ 1;
+ __END__
+ =head1 NAME
+
+ SelfLoader - load functions only on demand
+
+ =head1 SYNOPSIS
+
+ package FOOBAR;
+ use SelfLoader;
+
+ ... (initializing code)
+
+ __DATA__
+ sub {....
+
+
+ =head1 DESCRIPTION
+
+ This module tells its users that functions in the FOOBAR package are to be
+ autoloaded from after the __DATA__ token. See also L<perlsub/"Autoloading">.
+
+ =head2 The __DATA__ token
+
+ The __DATA__ token tells the perl compiler that the perl code
+ for compilation is finished. Everything after the __DATA__ token
+ is available for reading via the filehandle FOOBAR::DATA,
+ where FOOBAR is the name of the current package when the __DATA__
+ token is reached. This works just the same as __END__ does in
+ package 'main', but for other modules data after __END__ is not
+ automatically retreivable , whereas data after __DATA__ is.
+ The __DATA__ token is not recognized in versions of perl prior to
+ 5.001m.
+
+ Note that it is possible to have __DATA__ tokens in the same package
+ in multiple files, and that the last __DATA__ token in a given
+ package that is encountered by the compiler is the one accessible
+ by the filehandle. This also applies to __END__ and main, i.e. if
+ the 'main' program has an __END__, but a module 'require'd (_not_ 'use'd)
+ by that program has a 'package main;' declaration followed by an '__DATA__',
+ then the DATA filehandle is set to access the data after the __DATA__
+ in the module, _not_ the data after the __END__ token in the 'main'
+ program, since the compiler encounters the 'require'd file later.
+
+ =head2 SelfLoader autoloading
+
+ The SelfLoader works by the user placing the __DATA__
+ token _after_ perl code which needs to be compiled and
+ run at 'require' time, but _before_ subroutine declarations
+ that can be loaded in later - usually because they may never
+ be called.
+
+ The SelfLoader will read from the FOOBAR::DATA filehandle to
+ load in the data after __DATA__, and load in any subroutine
+ when it is called. The costs are the one-time parsing of the
+ data after __DATA__, and a load delay for the _first_
+ call of any autoloaded function. The benefits (hopefully)
+ are a speeded up compilation phase, with no need to load
+ functions which are never used.
+
+ The SelfLoader will stop reading from __DATA__ if
+ it encounters the __END__ token - just as you would expect.
+ If the __END__ token is present, and is followed by the
+ token DATA, then the SelfLoader leaves the FOOBAR::DATA
+ filehandle open on the line after that token.
+
+ The SelfLoader exports the AUTOLOAD subroutine to the
+ package using the SelfLoader, and this loads the called
+ subroutine when it is first called.
+
+ There is no advantage to putting subroutines which will _always_
+ be called after the __DATA__ token.
+
+ =head2 Autoloading and package lexicals
+
+ A 'my $pack_lexical' statement makes the variable $pack_lexical
+ local _only_ to the file up to the __DATA__ token. Subroutines
+ declared elsewhere _cannot_ see these types of variables,
+ just as if you declared subroutines in the package but in another
+ file, they cannot see these variables.
+
+ So specifically, autoloaded functions cannot see package
+ lexicals (this applies to both the SelfLoader and the Autoloader).
+
+ =head2 SelfLoader and AutoLoader
+
+ The SelfLoader can replace the AutoLoader - just change 'use AutoLoader'
+ to 'use SelfLoader' (though note that the SelfLoader exports
+ the AUTOLOAD function - but if you have your own AUTOLOAD and
+ are using the AutoLoader too, you probably know what you're doing),
+ and the __END__ token to __DATA__. You will need perl version 5.001m
+ or later to use this (version 5.001 with all patches up to patch m).
+
+ There is no need to inherit from the SelfLoader.
+
+ The SelfLoader works similarly to the AutoLoader, but picks up the
+ subs from after the __DATA__ instead of in the 'lib/auto' directory.
+ There is a maintainance gain in not needing to run AutoSplit on the module
+ at installation, and a runtime gain in not needing to keep opening and
+ closing files to load subs. There is a runtime loss in needing
+ to parse the code after the __DATA__.
+
+ =head2 __DATA__, __END__, and the FOOBAR::DATA filehandle.
+
+ This section is only relevant if you want to use
+ the FOOBAR::DATA together with the SelfLoader.
+
+ Data after the __DATA__ token in a module is read using the
+ FOOBAR::DATA filehandle. __END__ can still be used to denote the end
+ of the __DATA__ section if followed by the token DATA - this is supported
+ by the SelfLoader. The FOOBAR::DATA filehandle is left open if an __END__
+ followed by a DATA is found, with the filehandle positioned at the start
+ of the line after the __END__ token. If no __END__ token is present,
+ or an __END__ token with no DATA token on the same line, then the filehandle
+ is closed.
+
+ The SelfLoader reads from wherever the current
+ position of the FOOBAR::DATA filehandle is, until the
+ EOF or __END__. This means that if you want to use
+ that filehandle (and ONLY if you want to), you should either
+
+ 1. Put all your subroutine declarations immediately after
+ the __DATA__ token and put your own data after those
+ declarations, using the __END__ token to mark the end
+ of subroutine declarations. You must also ensure that the SelfLoader
+ reads first by calling 'SelfLoader->load_stubs();', or by using a
+ function which is selfloaded;
+
+ or
+
+ 2. You should read the FOOBAR::DATA filehandle first, leaving
+ the handle open and positioned at the first line of subroutine
+ declarations.
+
+ You could conceivably do both.
+
+ =head2 Classes and inherited methods.
+
+ For modules which are not classes, this section is not relevant.
+ This section is only relevant if you have methods which could
+ be inherited.
+
+ A subroutine stub (or forward declaration) looks like
+
+ sub stub;
+
+ i.e. it is a subroutine declaration without the body of the
+ subroutine. For modules which are not classes, there is no real
+ need for stubs as far as autoloading is concerned.
+
+ For modules which ARE classes, and need to handle inherited methods,
+ stubs are needed to ensure that the method inheritance mechanism works
+ properly. You can load the stubs into the module at 'require' time, by
+ adding the statement 'SelfLoader->load_stubs();' to the module to do
+ this.
+
+ The alternative is to put the stubs in before the __DATA__ token BEFORE
+ releasing the module, and for this purpose the Devel::SelfStubber
+ module is available. However this does require the extra step of ensuring
+ that the stubs are in the module. If this is done I strongly recommend
+ that this is done BEFORE releasing the module - it should NOT be done
+ at install time in general.
+
+ =head1 Multiple packages and fully qualified subroutine names
+
+ Subroutines in multiple packages within the same file are supported - but you
+ should note that this requires exporting the SelfLoader::AUTOLOAD to
+ every package which requires it. This is done automatically by the
+ SelfLoader when it first loads the subs into the cache, but you should
+ really specify it in the initialization before the __DATA__ by putting
+ a 'use SelfLoader' statement in each package.
+
+ Fully qualified subroutine names are also supported. For example,
+
+ __DATA__
+ sub foo::bar {23}
+ package baz;
+ sub dob {32}
+
+ will all be loaded correctly by the SelfLoader, and the SelfLoader
+ will ensure that the packages 'foo' and 'baz' correctly have the
+ SelfLoader AUTOLOAD method when the data after __DATA__ is first parsed.
+
+ =cut


End of patch.