问题
I have a directory structure that looks like:
Foo::Bar::Baz::1 Foo::Bar::Baz::2 etc
Can I list the packages from something like:
use Foo::Bar::Baz;
Thanks!
Edit: Made it more clear what the modules are.
回答1:
Just to be clear, are you looking at random packages in random Perl code?
Or for Perl modules, e.g. "a/b/c/d1.pm" with module "a::b::c::d1"?
In either case, you can not use a single "use" statement to load them all.
What you need to do is to find all the appropriate files, using either glob
or File::Find
.
In the first case (modules), you can then load them either by require
-ing each file, OR by converting filename into module name (s#/#::#g; s#\.pm$##;
) and calling use
on each module individually.
As far as actual packages nested in random Perl files, those packages can be:
Listed by grepping each file (again, found via
glob
orFile::Find
) for/^package (.*);/
Actually loaded by executing
require $file
for each file.In this case, please note that the package name for each of those packages in
a/b/c/1.pl
will NOT need to be related to "a::b::c" - e.g. they CAN be named by the file author "p1", "a::p1" or "a::b::c::p1_something".
回答2:
If you want to load all modules in your include path with a certain prefix (e.g. everything under a::b::c
, you can use Module::Find.
For example:
use Module::Find 'useall';
my @loaded = useall 'Foo::Bar::Baz'; # loads everything under Foo::Bar::Baz
This depends on your @INC
path being set up with the necessary directories, so do any required manipulation (e.g. with use lib
) first.
回答3:
Normally a script such as a/b/c.pl won't have a namespace other than main
. Perhaps you are thinking of discovering modules with names such as a/b/c.pm (which is a bad name, since lower-cased package names are generally reserved for Perl internals).
However, given a directory path, you can look for potential Perl modules using File::Find:
use strict;
use warnings;
use File::Find;
use Data::Dumper;
my @modules;
sub wanted
{
push @modules, $_ if m/\.pm$/
}
find(\&wanted, 'A/B');
print "possible modules found:\n";
print Dumper(\@modules)'
回答4:
This might be overkill, but you can inspect the symbol table before and after loading the module and see what changed:
use strict; use warnings;
my %original = map { $_ => 1 } get_namespaces("::");
require Inline;
print "New namespaces since 'require Inline' call are:\n";
my @new_namespaces = sort grep !defined $original{$_}, get_namespaces("::");
foreach my $new_namespace (@new_namespaces) {
print "\t$new_namespace\n";
}
sub get_namespaces {
# recursively inspect symbol table for known namespaces
my $pkg = shift;
my @namespace = ();
my %s = eval "%" . $pkg;
foreach my $key (grep /::$/, keys %s) {
next if $key eq "main::";
push @namespace, "$pkg$key", get_namespaces("$pkg$key");
}
return @namespace;
}
New namespaces since 'require Inline' call are: ::AutoLoader:: ::Config:: ::Digest:: ::Digest::MD5:: ::Dos:: ::EPOC:: ::Exporter:: ::Exporter::Heavy:: ::File:: ::File::Spec:: ::File::Spec::Cygwin:: ::File::Spec::Unix:: ::File::Spec::Win32:: ::Inline::Files:: ::Inline::denter:: ::Scalar:: ::Scalar::Util:: ::Socket:: ::VMS:: ::VMS::Filespec:: ::XSLoader:: ::vars:: ::warnings::register::
来源:https://stackoverflow.com/questions/2976075/how-do-i-dynamically-discover-packages-from-a-partial-namespace-in-perl