http://www.perlmonks.org?node_id=666068

/dev/urandom has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I want to figure out when certain modules are being loaded, and for this reason, I want to override require. So far I've almost managed to achieve what I wanted. I've overridden require, and it is called. The problem is, that it's not called with the module actually required by the user. For instance, if I want to require Net::Ping, I will receive all of its requirements, but I will not receive it. Here is my test script, which illustrates the issue:
#!/usr/bin/perl use strict; *CORE::GLOBAL::require = sub { CORE::require($_[0]); print $_[0], "\n" if $_[0] eq 'Net/Ping.pm'; }; require Net::Ping; my $p = Net::Ping->new;
What am I missing here? Also, if there's a better way of figuring out when modules are loaded (without having to modify the modules themselves), it would be a better solution.

Replies are listed 'Best First'.
Re: Overriding the built-in require function
by moritz (Cardinal) on Feb 04, 2008 at 19:52 UTC
    Wrap your substitution in a BEGIN block, then it works:
    BEGIN { *CORE::GLOBAL::require = sub { CORE::require($_[0]); print $_[0], "\n"; }; }
      excellent. that indeed seemed to work. thank you very much.
Re: Overriding the built-in require function (@INC)
by tye (Sage) on Feb 04, 2008 at 21:09 UTC

    You can also push a code ref (that returns undef) onto the front of @INC:

    BEGIN { unshift @INC, sub { my( $self, $file )= @_; print "Searching for $file...\n"; return; }; } require Net::Ping;

    See require for more details and other options.

    - tye        

      That would not serve my purposes, as any modules in question will not yet be loaded when the subref receives it.
        That's precisely the point: @INC is the list of paths that perl will search when it goes to load your module. If you put a code ref into @INC, perl will recognize it and execute it (rather than treating it as a path to search). By pushing your sub onto the front of @INC, you'll ensure that perl checks it first. By returning undef, you'll cause perl to keep looking until it finds the real path.

        The very end of the doc that tye linked, require, describes this in detail. The same @INC method works for use.

      But this of course fails if someone happens to do

      BEGIN { unshift @INC, sub { ... } } use lib 'somewhere/special'; require Net::Ping; # Resolves to "somewhere/special/Net/Ping.pm".
      as lib also unshifts @INC. This accident may not be obvious if it's a module that uses lib.

      For many purposes it works, but one should be aware of that it's not bullet proof against accidents.

      lodin