Hannibal
Hannibal

Reputation: 445

How can I get the list of modules required by a package?

I'm writing an extension for Mo*se class system and I need to get the list, from inside a package, of all modules required by the package using the "use" statement. I tried to inspect the %INC data struct, but I get the list of ALL modules loaded at compile time, and I cannot filter out the modules loaded by my package. I guess I have to deal with the Perl debugger, but any suggestion will be really appreciated :-)

Eg:

package MyApp 0.001 ;
use Module1 ;
use Module2 ;
...
sub list_requested_modules {
    ...HOW TO DO IT ???
}

Upvotes: 1

Views: 318

Answers (2)

stevieb
stevieb

Reputation: 9296

Another option, if you're only interested in knowing what modules the current file will load/has loaded would be PPI:

use warnings;
use strict;

use Data::Dumper;
use PPI;
require Mock::Sub;

my $ppi_doc  = PPI::Document->new(__FILE__);
my $ppi_deps = $ppi_doc->find('PPI::Statement::Include');

for (@$ppi_deps){
    print $_->module . "\n";
}

Output:

warnings
strict
Data::Dumper
PPI
Mock::Sub

Upvotes: 1

Grinnz
Grinnz

Reputation: 9231

You can't distinguish between modules loaded in the current file or modules that were already loaded. Consider if you have "use Module1;" but Module1 was already loaded, so all that does is import to the current package from the already-loaded module. Where would you then consider that module was loaded from?

Two things you can do depending what you are trying to figure out: you can parse a file to guess what modules it requires (though it doesn't guarantee they'll be loaded from there, they could be already loaded as I mentioned before). A good tool for this is Perl::PrereqScanner::Lite. You can use the __FILE__ literal to get the name of the current file.

use Perl::PrereqScanner::Lite;
my @required = Perl::PrereqScanner::Lite->new->scan_file(__FILE__)->required_modules;

The other option is to track what modules are loaded yourself. At the very beginning of the file put this:

my %original_inc;
BEGIN { %original_inc = %INC }

Then either immediately afterward, to find any modules loaded during compile time (including use statements), or in a later subroutine, you can compare how %INC changed:

my @newly_loaded = grep { !exists $original_inc{$_} } keys %INC;

In addition to the previously mentioned caveat that modules may have already been previously required and thus already present in %INC, modules you load may load other modules in turn, so the difference is probably not going to exactly match what use statements are in the file.

EDIT: Personally I would avoid both of these methods by obviating the need for such logic in the first place. Instead of loading your modules with use, write a subroutine that loads them using Module::Runtime and keeps track of what you load with it in some manner, and call that for each module in a BEGIN block. But note that this would defeat automated prereq scanning such as the PrereqScanner module I mentioned above.

Upvotes: 3

Related Questions