Add Module::Load to 5.9.x
Jos I. Boumans [Wed, 9 Aug 2006 12:23:42 +0000 (14:23 +0200)]
Message-ID: <9866.194.109.0.185.1155119022.squirrel@webmail.xs4all.nl>

p4raw-id: //depot/perl@28695

MANIFEST
lib/Module/Load.pm [new file with mode: 0644]
lib/Module/Load/t/01_Module-Load.t [new file with mode: 0644]
lib/Module/Load/t/to_load/LoadIt.pm [new file with mode: 0644]
lib/Module/Load/t/to_load/LoadMe.pl [new file with mode: 0644]
lib/Module/Load/t/to_load/Must/Be/Loaded.pm [new file with mode: 0644]
lib/Module/Load/t/to_load/TestModule.pm [new file with mode: 0644]
lib/Module/Load/t/to_load/ToBeLoaded [new file with mode: 0644]
lib/Module/Load/t/to_load/config_file [new file with mode: 0644]

index f9799fe..b24a54d 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -2050,6 +2050,14 @@ lib/Module/CoreList/bin/corelist Module::CoreList
 lib/Module/CoreList.pm                 Module::CoreList
 lib/Module/CoreList/t/corelist.t       Module::CoreList
 lib/Module/CoreList/t/find_modules.t   Module::CoreList
+lib/Module/Load.pm     Module::Load
+lib/Module/Load/t/01_Module-Load.t     Module::Load tests
+lib/Module/Load/t/to_load/config_file  Module::Load tests
+lib/Module/Load/t/to_load/LoadIt.pm    Module::Load tests
+lib/Module/Load/t/to_load/LoadMe.pl    Module::Load tests
+lib/Module/Load/t/to_load/Must/Be/Loaded.pm    Module::Load tests
+lib/Module/Load/t/to_load/TestModule.pm        Module::Load tests
+lib/Module/Load/t/to_load/ToBeLoaded   Module::Load tests
 lib/Net/Changes.libnet         libnet
 lib/Net/Cmd.pm                 libnet
 lib/Net/Config.eg              libnet
diff --git a/lib/Module/Load.pm b/lib/Module/Load.pm
new file mode 100644 (file)
index 0000000..231a8a7
--- /dev/null
@@ -0,0 +1,173 @@
+package Module::Load;
+
+$VERSION = '0.10';
+
+use strict;
+use File::Spec ();
+
+sub import {
+    my $who = _who();
+
+    {   no strict 'refs';
+        *{"${who}::load"} = *load;
+    }
+}
+
+sub load (*;@)  {
+    my $mod = shift or return;
+    my $who = _who();
+
+    if( _is_file( $mod ) ) {
+        require $mod;
+    } else {
+        LOAD: {
+            my $err;
+            for my $flag ( qw[1 0] ) {
+                my $file = _to_file( $mod, $flag);
+                eval { require $file };
+                $@ ? $err .= $@ : last LOAD;
+            }
+            die $err if $err;
+        }
+    }
+    __PACKAGE__->_export_to_level(1, $mod, @_) if @_;
+}
+
+### 5.004's Exporter doesn't have export_to_level.
+### Taken from Michael Schwerns Test::More and slightly modified
+sub _export_to_level {
+    my $pkg     = shift;
+    my $level   = shift;
+    my $mod     = shift;
+    my $callpkg = caller($level);
+
+    $mod->export($callpkg, @_);
+}
+
+sub _to_file{
+    local $_    = shift;
+    my $pm      = shift || '';
+
+    my @parts = split /::/;
+
+    ### because of [perl #19213], see caveats ###
+    my $file = $^O eq 'MSWin32'
+                    ? join "/", @parts
+                    : File::Spec->catfile( @parts );
+
+    $file   .= '.pm' if $pm;
+
+    return $file;
+}
+
+sub _who { (caller(1))[0] }
+
+sub _is_file {
+    local $_ = shift;
+    return  /^\./               ? 1 :
+            /[^\w:']/           ? 1 :
+            undef
+    #' silly bbedit..
+}
+
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Module::Load - runtime require of both modules and files
+
+=head1 SYNOPSIS
+
+       use Module::Load;
+
+    my $module = 'Data:Dumper';
+    load Data::Dumper;      # loads that module
+    load 'Data::Dumper';    # ditto
+    load $module            # tritto
+    
+    my $script = 'some/script.pl'
+    load $script;
+    load 'some/script.pl';     # use quotes because of punctuations
+    
+    load thing;             # try 'thing' first, then 'thing.pm'
+
+    load CGI, ':standard'   # like 'use CGI qw[:standard]'
+    
+
+=head1 DESCRIPTION
+
+C<load> eliminates the need to know whether you are trying to require
+either a file or a module.
+
+If you consult C<perldoc -f require> you will see that C<require> will
+behave differently when given a bareword or a string.
+
+In the case of a string, C<require> assumes you are wanting to load a
+file. But in the case of a bareword, it assumes you mean a module.
+
+This gives nasty overhead when you are trying to dynamically require
+modules at runtime, since you will need to change the module notation
+(C<Acme::Comment>) to a file notation fitting the particular platform
+you are on.
+
+C<load> eliminates the need for this overhead and will just DWYM.
+
+=head1 Rules
+
+C<load> has the following rules to decide what it thinks you want:
+
+=over 4
+
+=item *
+
+If the argument has any characters in it other than those matching
+C<\w>, C<:> or C<'>, it must be a file
+
+=item *
+
+If the argument matches only C<[\w:']>, it must be a module
+
+=item *
+
+If the argument matches only C<\w>, it could either be a module or a
+file. We will try to find C<file> first in C<@INC> and if that fails,
+we will try to find C<file.pm> in @INC.
+If both fail, we die with the respective error messages.
+
+=back
+
+=head1 Caveats
+
+Because of a bug in perl (#19213), at least in version 5.6.1, we have
+to hardcode the path separator for a require on Win32 to be C</>, like
+on Unix rather than the Win32 C<\>. Otherwise perl will not read its
+own %INC accurately double load files if they are required again, or
+in the worst case, core dump.
+
+C<Module::Load> cannot do implicit imports, only explicit imports.
+(in other words, you always have to specify explicitly what you wish
+to import from a module, even if the functions are in that modules'
+C<@EXPORT>)
+
+=head1 AUTHOR
+
+This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
+
+Thanks to Jonas B. Nielsen for making explicit imports work.
+
+=head1 COPYRIGHT
+
+This module is
+copyright (c) 2002 Jos Boumans E<lt>kane@cpan.orgE<gt>.
+All rights reserved.
+
+This library is free software;
+you may redistribute and/or modify it under the same
+terms as Perl itself.
+
+=cut                               
diff --git a/lib/Module/Load/t/01_Module-Load.t b/lib/Module/Load/t/01_Module-Load.t
new file mode 100644 (file)
index 0000000..f811447
--- /dev/null
@@ -0,0 +1,68 @@
+### Module::Load test suite ###
+BEGIN { 
+    if( $ENV{PERL_CORE} ) {
+        chdir '../lib/Module/Load' if -d '../lib/Module/Load';
+        unshift @INC, '../../..';
+    }
+} 
+
+BEGIN { chdir 't' if -d 't' }
+
+use strict;
+use lib qw[../lib to_load];
+use Module::Load;
+use Test::More tests => 13;
+
+
+{
+    my $mod = 'Must::Be::Loaded';
+    my $file = Module::Load::_to_file($mod,1);
+
+    eval { load $mod };
+
+    is( $@, '', qq[Loading module '$mod'] );
+    ok( defined($INC{$file}), q[... found in %INC] );
+}
+
+{
+    my $mod = 'LoadMe.pl';
+    my $file = Module::Load::_to_file($mod);
+
+    eval { load $mod };
+
+    is( $@, '', qq[Loading File '$mod'] );
+    ok( defined($INC{$file}), q[... found in %INC] );
+}
+
+{
+    my $mod = 'LoadIt';
+    my $file = Module::Load::_to_file($mod,1);
+
+    eval { load $mod };
+
+    is( $@, '', qq[Loading Ambigious Module '$mod'] );
+    ok( defined($INC{$file}), q[... found in %INC] );
+}
+
+{
+    my $mod = 'ToBeLoaded';
+    my $file = Module::Load::_to_file($mod);
+
+    eval { load $mod };
+
+    is( $@, '', qq[Loading Ambigious File '$mod'] );
+    ok( defined($INC{$file}), q[... found in %INC] );
+}
+
+### Test importing functions ###
+{   my $mod     = 'TestModule';
+    my @funcs   = qw[func1 func2];
+    
+    eval { load $mod, @funcs };
+    is( $@, '', qq[Loaded exporter module '$mod'] );
+    
+    for my $func (@funcs) {
+        ok( $mod->can($func),           "$mod -> can( $func )" );
+        ok( __PACKAGE__->can($func),    "we -> can ( $func )"  ); 
+    }        
+}    
diff --git a/lib/Module/Load/t/to_load/LoadIt.pm b/lib/Module/Load/t/to_load/LoadIt.pm
new file mode 100644 (file)
index 0000000..63874fd
--- /dev/null
@@ -0,0 +1,3 @@
+$VERSION = 1;
+
+1;
\ No newline at end of file
diff --git a/lib/Module/Load/t/to_load/LoadMe.pl b/lib/Module/Load/t/to_load/LoadMe.pl
new file mode 100644 (file)
index 0000000..6912615
--- /dev/null
@@ -0,0 +1 @@
+1;
\ No newline at end of file
diff --git a/lib/Module/Load/t/to_load/Must/Be/Loaded.pm b/lib/Module/Load/t/to_load/Must/Be/Loaded.pm
new file mode 100644 (file)
index 0000000..46de6d5
--- /dev/null
@@ -0,0 +1,3 @@
+$VERSION = 0.01;
+
+1;
\ No newline at end of file
diff --git a/lib/Module/Load/t/to_load/TestModule.pm b/lib/Module/Load/t/to_load/TestModule.pm
new file mode 100644 (file)
index 0000000..bf73343
--- /dev/null
@@ -0,0 +1,15 @@
+package TestModule;
+
+use strict;
+require Exporter;
+use vars qw(@EXPORT @EXPORT_OK @ISA);
+
+@ISA = qw(Exporter);
+@EXPORT = qw(func2);
+@EXPORT_OK = qw(func1);
+
+sub func1 { return "func1"; }
+
+sub func2 { return "func2"; }
+
+1;
diff --git a/lib/Module/Load/t/to_load/ToBeLoaded b/lib/Module/Load/t/to_load/ToBeLoaded
new file mode 100644 (file)
index 0000000..6912615
--- /dev/null
@@ -0,0 +1 @@
+1;
\ No newline at end of file
diff --git a/lib/Module/Load/t/to_load/config_file b/lib/Module/Load/t/to_load/config_file
new file mode 100644 (file)
index 0000000..0c47131
--- /dev/null
@@ -0,0 +1,30 @@
+    # Below is a sample of a config file you could use
+
+    # comments are denoted by a single '#'
+    # use a shared stack, or have a private instance?
+    # if none provided, set to '0',
+    private = 1
+
+    # do not be verbose
+    verbose = 0
+
+    # default tag to set on new items
+    # if none provided, set to 'NONE'
+    tag = SOME TAG
+
+    # default level to handle items
+    # if none provided, set to 'log'
+    level = carp
+
+    # extra files to include
+    # if none provided, no files are auto included
+    include = LoadMe.pl
+
+    # automatically delete items
+    # when you retrieve them from the stack?
+    # if none provided, set to '0'
+    remove = 1
+
+    # retrieve errors in chronological order, or not?
+    # if none provided, set to '1'
+    chrono = 0
\ No newline at end of file