The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
Build.PL 47
Changes 025
MANIFEST 02
META.yml 2122
Makefile.PL 811
README 11
SIGNATURE 1618
lib/Module/Runtime.pm 70189
t/Mod0.pm 09
t/Mod1.pm 09
t/ivmn.t 424
t/ivms.t 845
t/rm.t 44
t/um.t 33
t/upo.t 1111
15 files changed (This is a version diff) 150380
@@ -1,3 +1,4 @@
+{ use 5.006; }
 use warnings;
 use strict;
 
@@ -6,9 +7,11 @@ use Module::Build;
 Module::Build->new(
 	module_name => "Module::Runtime",
 	license => "perl",
+	configure_requires => {
+		"Module::Build" => 0,
+		"perl" => "5.006",
+	},
 	build_requires => {
-		"Math::Complex" => 0,
-		"Math::Trig" => 0,
 		"Module::Build" => 0,
 		"Test::More" => 0,
 		"perl" => "5.006",
@@ -16,8 +19,8 @@ Module::Build->new(
 		"warnings" => 0,
 	},
 	requires => {
-		"Carp" => 0,
 		"Exporter" => 0,
+		"Params::Classify" => 0,
 		"parent" => 0,
 		"perl" => "5.006",
 		"strict" => 0,
@@ -29,4 +32,4 @@ Module::Build->new(
 	sign => 1,
 )->create_build_script;
 
-exit 0;
+1;
@@ -1,3 +1,28 @@
+version 0.007; 2010-03-19
+
+  * add "check_" functions for argument checking
+
+  * supply regexps to check module name and spec syntax
+
+  * in "is_" functions, also cleanly handle non-string arguments
+
+  * in require_module() (also affecting use_module()), call require()
+    as a function (with appropriate name translation) instead of using
+    string eval, to avoid unnecessary complication of exception handling
+
+  * provide the "is_valid_" functions under shorter "is_" names
+
+  * revise POD markup
+
+  * check for required Perl version at runtime
+
+  * in tests, supply test modules to avoid requiring unrelated math
+    modules
+
+  * in Build.PL, explicitly declare configure-time requirements
+
+  * remove bogus "exit 0" from Build.PL
+
 version 0.006; 2009-05-19
 
   * bugfix: avoid unreliable "\w" in regexps in code
@@ -6,6 +6,8 @@ META.yml
 Makefile.PL
 README
 lib/Module/Runtime.pm
+t/Mod0.pm
+t/Mod1.pm
 t/cmn.t
 t/ivmn.t
 t/ivms.t
@@ -1,34 +1,35 @@
 ---
-name: Module-Runtime
-version: 0.006
+abstract: 'runtime module handling'
 author:
   - 'Andrew Main (Zefram) <zefram@fysh.org>'
-abstract: runtime module handling
-license: perl
-resources:
-  license: http://dev.perl.org/licenses/
-requires:
-  Carp: 0
-  Exporter: 0
-  parent: 0
-  perl: 5.006
-  strict: 0
-  warnings: 0
 build_requires:
-  Math::Complex: 0
-  Math::Trig: 0
   Module::Build: 0
   Test::More: 0
   perl: 5.006
   strict: 0
   warnings: 0
+configure_requires:
+  Module::Build: 0
+  perl: 5.006
+distribution_type: module
 dynamic_config: 0
+generated_by: 'Module::Build version 0.3603'
+license: perl
+meta-spec:
+  url: http://module-build.sourceforge.net/META-spec-v1.4.html
+  version: 1.4
+name: Module-Runtime
 provides:
   Module::Runtime:
     file: lib/Module/Runtime.pm
-    version: 0.006
-generated_by: Module::Build version 0.31012
-meta-spec:
-  url: http://module-build.sourceforge.net/META-spec-v1.2.html
-  version: 1.2
-distribution_type: module
+    version: 0.007
+requires:
+  Exporter: 0
+  Params::Classify: 0
+  parent: 0
+  perl: 5.006
+  strict: 0
+  warnings: 0
+resources:
+  license: http://dev.perl.org/licenses/
+version: 0.007
@@ -1,32 +1,35 @@
-# Note: this file was auto-generated by Module::Build::Compat version 0.31012
+# Note: this file was auto-generated by Module::Build::Compat version 0.3603
 require 5.006;
-    
+
     unless (eval "use Module::Build::Compat 0.02; 1" ) {
       print "This module requires Module::Build to install itself.\n";
-      
+
       require ExtUtils::MakeMaker;
       my $yn = ExtUtils::MakeMaker::prompt
 	('  Install Module::Build now from CPAN?', 'y');
-      
+
       unless ($yn =~ /^y/i) {
 	die " *** Cannot install without Module::Build.  Exiting ...\n";
       }
-      
+
       require Cwd;
       require File::Spec;
       require CPAN;
-      
+
       # Save this 'cause CPAN will chdir all over the place.
       my $cwd = Cwd::cwd();
-      
+
       CPAN::Shell->install('Module::Build::Compat');
       CPAN::Shell->expand("Module", "Module::Build::Compat")->uptodate
 	or die "Couldn't install Module::Build, giving up.\n";
-      
+
       chdir $cwd or die "Cannot chdir() back to $cwd: $!";
     }
     eval "use Module::Build::Compat 0.02; 1" or die $@;
     
     Module::Build::Compat->run_build_pl(args => \@ARGV);
+    my $build_script = 'Build';
+    $build_script .= '.com' if $^O eq 'VMS';
+    exit(0) unless(-e $build_script); # cpantesters convention
     require Module::Build;
     Module::Build::Compat->write_makefile(build_class => 'Module::Build');
@@ -20,7 +20,7 @@ Andrew Main (Zefram) <zefram@fysh.org>
 
 COPYRIGHT
 
-Copyright (C) 2004, 2006, 2007, 2009
+Copyright (C) 2004, 2006, 2007, 2009, 2010
 Andrew Main (Zefram) <zefram@fysh.org>
 
 LICENSE
@@ -1,5 +1,5 @@
 This file contains message digests of all files listed in MANIFEST,
-signed via the Module::Signature module, version 0.55.
+signed via the Module::Signature module, version 0.61.
 
 To verify the content in this distribution, first make sure you have
 Module::Signature installed, then type:
@@ -15,25 +15,27 @@ not run its Makefile.PL or Build.PL.
 Hash: SHA1
 
 SHA1 b6d25225ba8a64214777140d46baa28efac5f182 .cvsignore
-SHA1 195d8e8488b7d07360bd8dc33bf142a479dd0bb4 Build.PL
-SHA1 de3baf11573d608f4525a21ead3c6784d59d1d18 Changes
-SHA1 8baa595967cf445a9ffe049dda51246a8c04afb9 MANIFEST
-SHA1 a9a34a4b53e61d773a8fdc7a600054c4f059738a META.yml
-SHA1 f39315b8e83202006e8a916c6a58725d104f75ec Makefile.PL
-SHA1 fe3fe3edffe1c57eea86c8bf58537316497f1143 README
-SHA1 d433c04e4a0ab6e52187f525bc5b919a7d0e1ae3 lib/Module/Runtime.pm
+SHA1 e909e0a1d479fd4ed3897aee5c8412951b232da4 Build.PL
+SHA1 6103e60866161c8c1513f336e4a9aced06597fa8 Changes
+SHA1 f76971807c061f8f771566271fc88b6da3602dff MANIFEST
+SHA1 cefaac62020f304df8b4d4a50ce1f0b31deceb9e META.yml
+SHA1 f8469f20cf26bafaffabb905631b945ab0f81289 Makefile.PL
+SHA1 a8fb1cf3c6b9aef90fceb32bdf029977af15cb0c README
+SHA1 e0961c44d0681ab618372d1209338b7ac0820134 lib/Module/Runtime.pm
+SHA1 15f83d769adddc47c9b7f41bfd1c8d109af030f5 t/Mod0.pm
+SHA1 c9ec963e8dc84fa17c79746429c5ca0224202dff t/Mod1.pm
 SHA1 d1daf64b7648733cfacf95e0152e94d8bcc3b8bf t/cmn.t
-SHA1 e2c427946747f8d5ec5139e8239b77ec5d48075e t/ivmn.t
-SHA1 e00365f69d829875107ddffb682abb84a0d8699f t/ivms.t
+SHA1 5cfcdf0696c7f54bb87f95d8926de5ec37398ef9 t/ivmn.t
+SHA1 d14755fedf4b4c07c3c615086402b0f91c960ba7 t/ivms.t
 SHA1 0e141eecf3ca4903ef38d9413b5403a9ddb0392f t/pod_cvg.t
 SHA1 74a957cd8b93f25672ecc6aa578a671d084dd343 t/pod_syn.t
-SHA1 27c7b268069aefca1c3722372056dac9dbed21b5 t/rm.t
-SHA1 4e02c0406054fb67e1b4c2ddd95bba9df047e28c t/um.t
-SHA1 1d00e69d40b8468ba2278dd18d3fa418806f3104 t/upo.t
+SHA1 04cb55e06d43ecda3d6325c63733c313a695d19f t/rm.t
+SHA1 b7586b4ec77aa462f1aaf87a87d4c03d75d34b97 t/um.t
+SHA1 6a69a3d943d5e800c0a913dd15335030437455ce t/upo.t
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.9 (GNU/Linux)
 
-iEYEARECAAYFAkoTK0cACgkQOV9mt2VyAVGOlQCeP2LkI71Rw5ScPQybw2MY0Suu
-OUgAoKEYEfhXbo+PzaFJr5Qrt4LIJVlT
-=HBWH
+iEYEARECAAYFAkuj8CwACgkQOV9mt2VyAVGPUQCfYIUqLgv8XofkAMNKb8IZKuD8
+zVMAoIbcwvqfEBcNvvk+g0DawFlCSpJU
+=FcY1
 -----END PGP SIGNATURE-----
@@ -4,19 +4,35 @@ Module::Runtime - runtime module handling
 
 =head1 SYNOPSIS
 
-	use Module::Runtime qw(is_valid_module_name require_module
-			use_module use_package_optimistically
-			is_valid_module_spec compose_module_name);
+	use Module::Runtime qw(
+		$module_name_rx is_module_name check_module_name
+		require_module
+	);
 
-	$ok = is_valid_module_name($module);
-	require_module($module);
+	if($module_name =~ /\A$module_name_rx\z/o) { ...
+	if(is_module_name($module_name)) { ...
+	check_module_name($module_name);
+
+	require_module($module_name);
+
+	use Module::Runtime qw(use_module use_package_optimistically);
 
 	$bi = use_module("Math::BigInt", 1.31)->new("1_234");
 	$widget = use_package_optimistically("Local::Widget")->new;
 
-	$ok = is_valid_module_spec("Standard::Prefix", $spec);
-	$module_name = compose_module_name("Standard::Prefix",
-						$spec);
+	use Module::Runtime qw(
+		$top_module_spec_rx $sub_module_spec_rx
+		is_module_spec check_module_spec
+		compose_module_name
+	);
+
+	if($spec =~ /\A$top_module_spec_rx\z/o) { ...
+	if($spec =~ /\A$sub_module_spec_rx\z/o) { ...
+	if(is_module_spec("Standard::Prefix", $spec)) { ...
+	check_module_spec("Standard::Prefix", $spec);
+
+	$module_name =
+		compose_module_name("Standard::Prefix", $spec);
 
 =head1 DESCRIPTION
 
@@ -27,83 +43,165 @@ modules, which are normally handled at compile time.
 
 package Module::Runtime;
 
+{ use 5.006; }
 use warnings;
 use strict;
 
-use Carp qw(croak);
+use Params::Classify qw(is_string);
 
-our $VERSION = "0.006";
+our $VERSION = "0.007";
 
 use parent "Exporter";
 our @EXPORT_OK = qw(
-	is_valid_module_name require_module
+	$module_name_rx is_module_name is_valid_module_name check_module_name
+	require_module
 	use_module use_package_optimistically
-	is_valid_module_spec compose_module_name
+	$top_module_spec_rx $sub_module_spec_rx
+	is_module_spec is_valid_module_spec check_module_spec
+	compose_module_name
 );
 
-=head1 FUNCTIONS
+=head1 REGULAR EXPRESSIONS
+
+These regular expressions do not include any anchors, so to check
+whether an entire string matches a syntax item you must supply the
+anchors yourself.
 
 =over
 
-=item is_valid_module_name(STRING)
+=item $module_name_rx
 
-This tests whether a string is a valid Perl module name, i.e., has valid
-bareword syntax.  The rule for this, precisely, is: the string must
+Matches a valid Perl module name in bareword syntax.
+The rule for this, precisely, is: the string must
 consist of one or more segments separated by C<::>; each segment must
 consist of one or more identifier characters (alphanumerics plus "_");
-the first character of the string must not be a digit.  Thus C<IO::File>,
-C<warnings>, and C<foo::123::x_0> are all valid module names, whereas
-C<IO::> and C<1foo::bar> are not.
+the first character of the string must not be a digit.  Thus "C<IO::File>",
+"C<warnings>", and "C<foo::123::x_0>" are all valid module names, whereas
+"C<IO::>" and "C<1foo::bar>" are not.
 Only ASCII characters are permitted; Perl's handling of non-ASCII
 characters in source code is inconsistent.
+C<'> separators are not permitted.
+
+=cut
+
+our $module_name_rx = qr/[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*/;
+
+=item $top_module_spec_rx
+
+Matches a module specification for use with L</compose_module_name>,
+where no prefix is being used.
+
+=cut
+
+my $qual_module_spec_rx =
+	qr#(?:/|::)[A-Z_a-z][0-9A-Z_a-z]*(?:(?:/|::)[0-9A-Z_a-z]+)*#;
+
+my $unqual_top_module_spec_rx =
+	qr#[A-Z_a-z][0-9A-Z_a-z]*(?:(?:/|::)[0-9A-Z_a-z]+)*#;
+
+our $top_module_spec_rx = qr/$qual_module_spec_rx|$unqual_top_module_spec_rx/o;
+
+=item $sub_module_spec_rx
 
-Note that C<'> separators are I<not> permitted by this function.
+Matches a module specification for use with L</compose_module_name>,
+where a prefix is being used.
 
 =cut
 
-sub is_valid_module_name($) {
-	my($string) = @_;
-	$string =~ m#\A[a-zA-Z_][0-9a-zA-Z_]*(?:::[0-9a-zA-Z_]+)*\z#
+my $unqual_sub_module_spec_rx = qr#[0-9A-Z_a-z]+(?:(?:/|::)[0-9A-Z_a-z]+)*#;
+
+our $sub_module_spec_rx = qr/$qual_module_spec_rx|$unqual_sub_module_spec_rx/o;
+
+=back
+
+=head1 FUNCTIONS
+
+=head2 Basic module handling
+
+=over
+
+=item is_module_name(ARG)
+
+Returns a truth value indicating whether I<ARG> is a plain string
+satisfying Perl module name syntax as described for L</$module_name_rx>.
+
+=cut
+
+sub is_module_name($) { &is_string && $_[0] =~ /\A$module_name_rx\z/o }
+
+=item is_valid_module_name(ARG)
+
+Deprecated alias for L</is_module_name>.
+
+=cut
+
+*is_valid_module_name = \&is_module_name;
+
+=item check_module_name(ARG)
+
+Check whether I<ARG> is a plain string
+satisfying Perl module name syntax as described for L</$module_name_rx>.
+Return normally if it is, or C<die> if it is not.
+
+=cut
+
+sub check_module_name($) {
+	unless(&is_module_name) {
+		die +(&is_string ? "`$_[0]'" : "argument").
+			" is not a module name\n";
+	}
 }
 
 =item require_module(NAME)
 
 This is essentially the bareword form of C<require>, in runtime form.
-The NAME is a string, which should be a valid module name (one or
+The I<NAME> is a string, which should be a valid module name (one or
 more C<::>-separated segments).  If it is not a valid name, the function
 C<die>s.
 
-The module specified by NAME is loaded, if it hasn't been already,
+The module specified by I<NAME> is loaded, if it hasn't been already,
 in the manner of the bareword form of C<require>.  That means that a
 search through C<@INC> is performed, and a byte-compiled form of the
 module will be used if available.
 
 The return value is as for C<require>.  That is, it is the value returned
-by the module itself if the module is loaded anew, or 1 if the module
+by the module itself if the module is loaded anew, or C<1> if the module
 was already loaded.
 
 =cut
 
 sub require_module($) {
+	&check_module_name;
 	my($name) = @_;
-	croak "bad module name `$name'" unless is_valid_module_name($name);
-	eval("local \$SIG{__DIE__}; require $name") || die $@;
+	# This translation to Unix-style filename is correct regardless
+	# of platform.  This is what ck_require() in the Perl core does
+	# with a bareword, and pp_require() translates the Unix-style
+	# filename to whatever is appropriate for the real platform.
+	$name =~ s!::!/!g;
+	$name .= ".pm";
+	return require($name);
 }
 
+=back
+
+=head2 Structured module use
+
+=over
+
 =item use_module(NAME[, VERSION])
 
-This is essentially C<use> in runtime form, but without the "import"
-feature (which is fundamentally a compile-time thing).  The NAME is
+This is essentially C<use> in runtime form, but without the importing
+feature (which is fundamentally a compile-time thing).  The I<NAME> is
 handled just like in C<require_module> above: it must be a module name,
 and the named module is loaded as if by the bareword form of C<require>.
 
-If a VERSION is specified, the "VERSION" method of the loaded module is
-called with the specified VERSION as an argument.  This normally serves to
+If a I<VERSION> is specified, the C<VERSION> method of the loaded module is
+called with the specified I<VERSION> as an argument.  This normally serves to
 ensure that the version loaded is at least the version required.  This is
-the same functionality provided by the VERSION parameter of C<use>.
+the same functionality provided by the I<VERSION> parameter of C<use>.
 
 On success, the name of the module is returned.  This is unlike
-C<require_module>, and is done so that the entire call to C<use_module>
+L</require_module>, and is done so that the entire call to L</use_module>
 can be used as a class name to call a constructor, as in the example in
 the synopsis.
 
@@ -120,7 +218,7 @@ sub use_module($;$) {
 
 =item use_package_optimistically(NAME[, VERSION])
 
-This is an analogue of C<use_module> for the situation where there is
+This is an analogue of L</use_module> for the situation where there is
 uncertainty as to whether a package/class is defined in its own module
 or by some other means.  It attempts to arrange for the named package to
 be available, either by loading a module or by doing nothing and hoping.
@@ -137,17 +235,17 @@ or if it was loaded but didn't create a C<$VERSION> variable, then such a
 variable is automatically created (with value C<undef>) so that repeated
 use of this function won't redundantly attempt to load the module.
 
-This is mostly the same operation that is performed by the C<base>
+This is mostly the same operation that is performed by the L<base>
 pragma to ensure that the specified base classes are available.
-The difference is that C<base> does not allow the C<$VERSION> variable
-to remain undefined: it will set it to "-1, set by base.pm" if it does
+The difference is that L<base> does not allow the C<$VERSION> variable
+to remain undefined: it will set it to "C<-1, set by base.pm>" if it does
 not otherwise have a non-null value.
 
-If a VERSION is specified, the "VERSION" method of the loaded package is
-called with the specified VERSION as an argument.  This normally serves
+If a I<VERSION> is specified, the C<VERSION> method of the loaded package is
+called with the specified I<VERSION> as an argument.  This normally serves
 to ensure that the version loaded is at least the version required.
 On success, the name of the package is returned.  These aspects of the
-function work just like C<use_module>.
+function work just like L</use_module>.
 
 =cut
 
@@ -160,7 +258,7 @@ sub _has_version_var($) {
 
 sub use_package_optimistically($;$) {
 	my($name, $version) = @_;
-	croak "bad module name `$name'" unless is_valid_module_name($name);
+	check_module_name($name);
 	unless(_has_version_var($name)) {
 		eval "local \$SIG{__DIE__}; require $name";
 		die $@ if $@ ne "" && $@ !~ /\ACan't locate .* at \(eval /;
@@ -173,23 +271,49 @@ sub use_package_optimistically($;$) {
 	return $name;
 }
 
-=item is_valid_module_spec(PREFIX, SPEC)
+=back
+
+=head2 Module name composition
 
-Tests whether SPEC is valid input for C<compose_module_name()>.
-See below for what that entails.  Whether a PREFIX is supplied affects
-the validity of SPEC, but the exact value of the prefix is unimportant,
-so this function treats PREFIX as a truth value.
+=over
+
+=item is_module_spec(PREFIX, SPEC)
+
+Returns a truth value indicating
+whether I<SPEC> is valid input for L</compose_module_name>.
+See below for what that entails.  Whether a I<PREFIX> is supplied affects
+the validity of I<SPEC>, but the exact value of the prefix is unimportant,
+so this function treats I<PREFIX> as a truth value.
 
 =cut
 
-sub is_valid_module_spec($$) {
+sub is_module_spec($$) {
 	my($prefix, $spec) = @_;
-	return ($prefix && $spec =~ m{\A
-				      [0-9][0-9a-zA-Z_]*
-				      (?:(?:/|::)[0-9a-zA-Z_]+)*\z}x) ||
-		($spec =~ m{\A(?:/|::)?
-			    [a-zA-Z_][0-9a-zA-Z_]*
-			    (?:(?:/|::)[0-9a-zA-Z_]+)*\z}x);
+	return is_string($spec) &&
+		$spec =~ ($prefix ? qr/\A$sub_module_spec_rx\z/o :
+				    qr/\A$top_module_spec_rx\z/o);
+}
+
+=item is_valid_module_spec(PREFIX, SPEC)
+
+Deprecated alias for L</is_module_spec>.
+
+=cut
+
+*is_valid_module_spec = \&is_module_spec;
+
+=item check_module_spec(PREFIX, SPEC)
+
+Check whether I<SPEC> is valid input for L</compose_module_name>.
+Return normally if it is, or C<die> if it is not.
+
+=cut
+
+sub check_module_spec($$) {
+	unless(&is_module_spec) {
+		die +(is_string($_[1]) ? "`$_[1]'" : "argument").
+			" is not a module specification\n";
+	}
 }
 
 =item compose_module_name(PREFIX, SPEC)
@@ -197,38 +321,33 @@ sub is_valid_module_spec($$) {
 This function is intended to make it more convenient for a user to specify
 a Perl module name at runtime.  Users have greater need for abbreviations
 and context-sensitivity than programmers, and Perl module names get a
-little unwieldy.  SPEC is what the user specifies, and this function
+little unwieldy.  I<SPEC> is what the user specifies, and this function
 translates it into a module name in standard form, which it returns.
 
-SPEC has syntax approximately that of a standard module name: it
+I<SPEC> has syntax approximately that of a standard module name: it
 should consist of one or more name segments, each of which consists
 of one or more identifier characters.  However, C</> is permitted as a
 separator, in addition to the standard C<::>.  The two separators are
 entirely interchangeable.
 
-Additionally, if PREFIX is not C<undef> then it must be a module
+Additionally, if I<PREFIX> is not C<undef> then it must be a module
 name in standard form, and it is prefixed to the user-specified name.
-The user can inhibit the prefix addition by starting SPEC with a
+The user can inhibit the prefix addition by starting I<SPEC> with a
 separator (either C</> or C<::>).
 
 =cut
 
 sub compose_module_name($$) {
 	my($prefix, $spec) = @_;
-	croak "bad module prefix `$prefix'"
-		if defined($prefix) && !is_valid_module_name($prefix);
-	if(defined($prefix) && $spec =~ m{\A[0-9a-zA-Z_]+
-					  (?:(?:/|::)[0-9a-zA-Z_]+)*\z}x) {
-		$spec = $prefix."::".$spec;
-	} elsif($spec =~ m{\A(?:/|::)?
-			   ([a-zA-Z_][0-9a-zA-Z_]*
-			    (?:(?:/|::)[0-9a-zA-Z_]+)*)\z}x) {
-		$spec = $1;
+	check_module_name($prefix) if defined $prefix;
+	&check_module_spec;
+	if($spec =~ s#\A(?:/|::)##) {
+		# OK
 	} else {
-		croak "bad module specification `$spec'";
+		$spec = $prefix."::".$spec if defined $prefix;
 	}
 	$spec =~ s#/#::#g;
-	$spec;
+	return $spec;
 }
 
 =back
@@ -245,7 +364,7 @@ Andrew Main (Zefram) <zefram@fysh.org>
 
 =head1 COPYRIGHT
 
-Copyright (C) 2004, 2006, 2007, 2009
+Copyright (C) 2004, 2006, 2007, 2009, 2010
 Andrew Main (Zefram) <zefram@fysh.org>
 
 =head1 LICENSE
@@ -0,0 +1,9 @@
+package t::Mod0;
+
+{ use 5.006; }
+use warnings;
+use strict;
+
+our $VERSION = 1;
+
+"t::Mod0 return";
@@ -0,0 +1,9 @@
+package t::Mod1;
+
+{ use 5.006; }
+use warnings;
+use strict;
+
+our $VERSION = 1;
+
+"t::Mod1 return";
@@ -1,6 +1,22 @@
-use Test::More tests => 12;
+use Test::More tests => 47;
 
-BEGIN { use_ok "Module::Runtime", qw(is_valid_module_name); }
+BEGIN { use_ok "Module::Runtime", qw(
+	$module_name_rx is_module_name is_valid_module_name check_module_name
+); }
+
+ok \&is_valid_module_name == \&is_module_name;
+
+foreach my $name (
+	undef,
+	*STDOUT,
+	\"Foo",
+	[],
+	{},
+	sub{},
+) {
+	ok(!is_module_name($name), "non-string is bad (function)");
+	eval { check_module_name($name) }; isnt $@, "";
+}
 
 foreach my $name (qw(
 	Foo
@@ -9,7 +25,9 @@ foreach my $name (qw(
 	foo::123::x_0
 	_
 )) {
-	ok(is_valid_module_name($name), "`$name' is good");
+	ok(is_module_name($name), "`$name' is good (function)");
+	eval { check_module_name($name) }; is $@, "";
+	ok($name =~ /\A$module_name_rx\z/, "`$name' is good (regexp)");
 }
 
 foreach my $name (qw(
@@ -20,5 +38,7 @@ foreach my $name (qw(
 	::foo
 	foo::::bar
 )) {
-	ok(!is_valid_module_name($name), "`$name' is bad");
+	ok(!is_module_name($name), "`$name' is bad (function)");
+	eval { check_module_name($name) }; isnt $@, "";
+	ok($name !~ /\A$module_name_rx\z/, "`$name' is bad (regexp)");
 }
@@ -1,6 +1,25 @@
-use Test::More tests => 39;
+use Test::More tests => 140;
 
-BEGIN { use_ok "Module::Runtime", qw(is_valid_module_spec); }
+BEGIN { use_ok "Module::Runtime", qw(
+	$top_module_spec_rx $sub_module_spec_rx
+	is_module_spec is_valid_module_spec check_module_spec
+); }
+
+ok \&is_valid_module_spec == \&is_module_spec;
+
+foreach my $spec (
+	undef,
+	*STDOUT,
+	\"Foo",
+	[],
+	{},
+	sub{},
+) {
+	ok(!is_module_spec(0, $spec), "non-string is bad (function)");
+	eval { check_module_spec(0, $spec) }; isnt $@, "";
+	ok(!is_module_spec(1, $spec), "non-string is bad (function)");
+	eval { check_module_spec(1, $spec) }; isnt $@, "";
+}
 
 foreach my $spec (qw(
 	Foo
@@ -14,8 +33,14 @@ foreach my $spec (qw(
 	/foo/bar
 	::foo/bar
 )) {
-	ok(is_valid_module_spec(0, $spec), "`$spec' is always good");
-	ok(is_valid_module_spec(1, $spec), "`$spec' is always good");
+	ok(is_module_spec(0, $spec), "`$spec' is always good (function)");
+	eval { check_module_spec(0, $spec) }; is $@, "";
+	ok($spec =~ qr/\A$top_module_spec_rx\z/,
+		"`$spec' is always good (regexp)");
+	ok(is_module_spec(1, $spec), "`$spec' is always good (function)");
+	eval { check_module_spec(1, $spec) }; is $@, "";
+	ok($spec =~ qr/\A$sub_module_spec_rx\z/,
+		"`$spec' is always good (regexp)");
 }
 
 foreach my $spec (qw(
@@ -27,14 +52,26 @@ foreach my $spec (qw(
 	::foo::
 	::1foo
 )) {
-	ok(!is_valid_module_spec(0, $spec), "`$spec' is always bad");
-	ok(!is_valid_module_spec(1, $spec), "`$spec' is always bad");
+	ok(!is_module_spec(0, $spec), "`$spec' is always bad (function)");
+	eval { check_module_spec(0, $spec) }; isnt $@, "";
+	ok($spec !~ qr/\A$top_module_spec_rx\z/,
+		"`$spec' is always bad (regexp)");
+	ok(!is_module_spec(1, $spec), "`$spec' is always bad (function)");
+	eval { check_module_spec(1, $spec) }; isnt $@, "";
+	ok($spec !~ qr/\A$sub_module_spec_rx\z/,
+		"`$spec' is always bad (regexp)");
 }
 
 foreach my $spec (qw(
 	1foo
 	0/1
 )) {
-	ok(!is_valid_module_spec(0, $spec), "`$spec' needs a prefix");
-	ok(is_valid_module_spec(1, $spec), "`$spec' needs a prefix");
+	ok(!is_module_spec(0, $spec), "`$spec' needs a prefix (function)");
+	eval { check_module_spec(0, $spec) }; isnt $@, "";
+	ok($spec !~ qr/\A$top_module_spec_rx\z/,
+		"`$spec' needs a prefix (regexp)");
+	ok(is_module_spec(1, $spec), "`$spec' needs a prefix (function)");
+	eval { check_module_spec(1, $spec) }; is $@, "";
+	ok($spec =~ qr/\A$sub_module_spec_rx\z/,
+		"`$spec' needs a prefix (regexp)");
 }
@@ -11,7 +11,7 @@ sub test_require_module($) {
 }
 
 # a module that doesn't exist
-test_require_module("module::that::does::not::exist");
+test_require_module("t::NotExist");
 like($err, qr/^Can't locate /);
 
 # a module that's already loaded
@@ -20,11 +20,11 @@ is($err, "");
 is($result, 1);
 
 # a module that we'll load now
-test_require_module("Math::Complex");
+test_require_module("t::Mod0");
 is($err, "");
-ok($result);
+is($result, "t::Mod0 return");
 
 # re-requiring the module that we just loaded
-test_require_module("Math::Complex");
+test_require_module("t::Mod0");
 is($err, "");
 is($result, 1);
@@ -11,7 +11,7 @@ sub test_use_module($;$) {
 }
 
 # a module that doesn't exist
-test_use_module("module::that::does::not::exist");
+test_use_module("t::NotExist");
 like($err, qr/^Can't locate /);
 
 # a module that's already loaded
@@ -20,9 +20,9 @@ is($err, "");
 is($result, "Test::More");
 
 # a module that we'll load now
-test_use_module("Math::Complex");
+test_use_module("t::Mod0");
 is($err, "");
-is($result, "Math::Complex");
+is($result, "t::Mod0");
 
 # successful version check
 test_use_module("Module::Runtime", 0.001);
@@ -11,9 +11,9 @@ sub test_use_package_optimistically($;$) {
 }
 
 # a module that doesn't exist
-test_use_package_optimistically("module::that::does::not::exist");
+test_use_package_optimistically("t::NotExist");
 is $err, "";
-is $result, "module::that::does::not::exist";
+is $result, "t::NotExist";
 
 # a module that's already loaded
 test_use_package_optimistically("Test::More");
@@ -21,10 +21,10 @@ is $err, "";
 is $result, "Test::More";
 
 # a module that we'll load now
-test_use_package_optimistically("Math::Complex");
+test_use_package_optimistically("t::Mod0");
 is $err, "";
-is $result, "Math::Complex";
-ok defined(${"Math::Complex::VERSION"});
+is $result, "t::Mod0";
+ok defined(${"t::Mod0::VERSION"});
 
 # successful version check
 test_use_package_optimistically("Module::Runtime", 0.001);
@@ -36,10 +36,10 @@ test_use_package_optimistically("Module::Runtime", 999);
 like $err, qr/^Module::Runtime version /;
 
 # don't load module if $VERSION already set, although "require" will
-$Math::Trig::VERSION = undef;
-test_use_package_optimistically("Math::Trig");
+$t::Mod1::VERSION = undef;
+test_use_package_optimistically("t::Mod1");
 is $err, "";
-is $result, "Math::Trig";
-ok !defined($Math::Trig::VERSION);
-require Math::Trig;
-ok defined($Math::Trig::VERSION);
+is $result, "t::Mod1";
+ok !defined($t::Mod1::VERSION);
+require t::Mod1;
+ok defined($t::Mod1::VERSION);