This is patch.2b1c to perl5.002beta1. This patch includes
authorAndy Dougherty <doughera.lafayette.edu>
Sat, 2 Dec 1995 03:12:54 +0000 (03:12 +0000)
committerAndy Dougherty <doughera.lafayette.edu>
Sat, 2 Dec 1995 03:12:54 +0000 (03:12 +0000)
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

MANIFEST
lib/Devel/SelfStubber.pm [new file with mode: 0644]
lib/SelfLoader.pm [new file with mode: 0644]

index ca4e99c..fde2483 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -242,6 +242,7 @@ lib/AutoSplit.pm    A module to split up autoload functions
 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,6 +267,7 @@ lib/Math/BigInt.pm  An arbitrary precision integer arithmetic package
 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
diff --git a/lib/Devel/SelfStubber.pm b/lib/Devel/SelfStubber.pm
new file mode 100644 (file)
index 0000000..1b5e575
--- /dev/null
@@ -0,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
diff --git a/lib/SelfLoader.pm b/lib/SelfLoader.pm
new file mode 100644 (file)
index 0000000..017d204
--- /dev/null
@@ -0,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