davido has asked for the wisdom of the Perl Monks concerning the following question:

This morning I was re-reading require to refresh my memory on an issue unrelated to this question. While reading, I stumbled across something that I hadn't noticed in previous reads:

You can also insert hooks into the import facility, by putting directly Perl code into the @INC array. There are three forms of hooks: subroutine references, array references and blessed objects.

After reading the rest of the document I think I understand that the execution of the coderef held in @INC should return a filehandle to a file that is to be included, and it also looks like the rest of @INC will not be used unless the code returns undef instead of a filehandle.

Of course I've also read the examples given in the POD for require, but I guess I'm just not quite seeing it. perlvar's brief mention of the @INC and %INC hooks didn't really contribute to settling my curiosity. What is this feature for, and how is it correctly used? It seems that it must be used for runtime decisions on what files get included. Am I close to being on the right track? Can anyone provide an example of this feature at work?

Thanks for any comments!

UPDATE: I found the first mention of the @INC coderef feature in perl573delta, with the following line (in the Changes section: "21. document the coderef-in-@INC feature." That implies it's been around since before 5.7.3, but first documented in 5.7.3.


Dave

Replies are listed 'Best First'.
Re: How to use @INC coderef hooks
by bsb (Priest) on Jun 01, 2004 at 04:52 UTC
    I played with it briefly, producing the following. It just ignores all but the last element of the package name and looks in the cwd (for our local namespace SD::)
    # Hack for sketching use lib '/home/bsb/sb/lib'; BEGIN { # look in cwd first unshift @INC => sub { $_[1] =~ m!^SD/(?:.*/)?(.*)! || return; #print STDERR "Loading $_[1] $1\n"; open my($f), $1; #$INC{$_[1]} = "./$1"; $f; }; }
    More generally I think subs in @INC allow for remote or database calls to load your code.

    Brad

Re: How to use @INC coderef hooks
by Zaxo (Archbishop) on Jun 01, 2004 at 06:53 UTC

    One possible use would be to interpose a PerlIO::via layer or other translation mechanism in reading module files. For instance, suppose we think we can save disk IO time by storing gzipped versions of our modules. A sub to read and unzip the file might be written like this (completely untested):

    use Compress::Zlib qw/gzopen gzeof gzread gzclose gzerror/; unshift @INC, sub { my ($cref, $filename) = @_; $filename = "/path/to/compressed/libs/${filename}.gz"; return unless -f $filename; my $text; { my $gz = gzopen( $filename, 'rb') or warn $gz->gzerror() and return; while ( !$gz->gzeof() ) { my $buffer; my $bytes = $gz->gzread($buffer); warn $gz->gzerror() and return if $bytes == -1; $text .= $buffer; } $gz->gzclose(); } require 5.008; open my $fh, '<', \$text or return; $fh; }
    I haven't seen an implemented PerlIO::via layer for gzip/gunzip, or I would have used it. That seems to be one that is talked about a lot, but CPAN does not appear to have it.

    Other uses come to mind. The sub could check md5sum for the requested module, returning undefined for good ones and dieing for bad. A source filter could be waved over the module. Decryption could be done much like the gzip example.

    It might be fun to generate modules on the fly with Template Toolkit.

    After Compline,
    Zaxo

Re: How to use @INC coderef hooks
by chromatic (Archbishop) on Jun 01, 2004 at 05:28 UTC

    You have the gist of it correct. Acme::Inc provides a (counterproductive) example of use.

Re: How to use @INC coderef hooks
by gmpassos (Priest) on Jun 01, 2004 at 06:13 UTC
    This resource is here since Perl 5.6.1 (as I know), but wasn't documented until 5.7+.

    If you really want to see some module that uses that, take a look in PAR

    Graciliano M. P.
    "Creativity is the expression of the liberty".

Re: How to use @INC coderef hooks (perldoc wrong)
by LanX (Saint) on Apr 04, 2014 at 12:30 UTC
    same case, tried fiddling around with it and the documentation seems wrong.

    it says

    If there is no filehandle (previous item), then this subroutine is expected to generate one line of source code per call, writing the line into $_ and returning 1, then returning 0 at "end of file".

    but this is never the case, passing undef doesn't help.

    The "previous item" always has to be a filehandle.

    Otherwise the generator-callback "this subroutine" is never called.

    Passing a dummy filehandle helps.

    update

    DARN! looking at this example Re: Cancel/no-op a require reveals the problem with the documentation.

    In the hook you can either return FILEHANDLE, CODEREF; or return CODEREF; but the docs imply return undef, CODEREF; for the second case.

    Cheers Rolf

    ( addicted to the Perl Programming Language)