[oak perl] listing modules

Steve Fink sfink at reactrix.com
Tue Sep 14 16:27:56 CDT 2004


Belden Lyman wrote:
> On Tue, 2004-09-14 at 12:54, Steve Fink wrote:
> 
>>>On Tue, 2004-09-14 at 09:49, David Fetter wrote:
>>>
>>>
>>>>On Tue, Sep 14, 2004 at 08:39:24AM -0700, Belden Lyman wrote:
>>>>
>>>>>That only tells you the modules installed by whomever has write
>>>>>permission on perllocal.pod.
>>>>
>>>>True.  Short of find / or locate, is there some other way to find
>>>>the rest?
>>
>>Well, they all have to be findable through @INC, so would this get you 
>>something close enough?
>>
>>  perl -le 'print foreach map { glob("$_/*.pm") } @INC'
> 
> 
> No, that's not true. lib.pm, -I switch to perl, and installation of 
> modules into home directories can all yield modules findable by a
> particular instance of the perl interpreter, yet not located anywhere
> within @INC.

Those are not installed modules. I certainly wouldn't want it to find 
modules that I had downloaded but never installed, so I also wouldn't 
want it to find modules in places like that.

> Even if that were the case, your one-liner wouldn't work for modules
> such as IO::Socket::INET, because $_ would never be IO/Socket. A
> different approach would be:
> 
>     perl -MFile::Find -le'find(sub{/\.pm$/ and print
> $File::Find::name}, at INC)'

Good point! Yes, that is much better. It still isn't guaranteed to be 
complete (it doesn't search the rarely-used .pmc files, nor does it 
handle CODE refs stuck into @INC by some installed module that then 
allow you to find other modules), and it will probably contain more than 
you want (my @INC contains . by default, which I've never liked, and 
therefore finds all kinds of uninstalled modules depending on where I 
run it from), but it seems about right.

The one problem I have with that script is that it is only giving me the 
basename of each file, which makes it hard to figure out what A.pm is 
(it's Net::FTP::A, or perhaps Net::DNS::RR::A). I never use File::Find, 
but from the docs I don't understand why not. At any rate, you can get 
the full path with

  perl -MFile::Find -le 'find({wanted=>sub{/\.pm$/ and print 
$File::Find::name}, no_chdir=>1}, at INC)'

but I'm sure there must be a better solution (especially one that gets 
rid of the @INC entry from the beginning of the path!). Oh, and get rid 
of the stupid current directory:

  perl -MFile::Find -le 'find({wanted=>sub{/\.pm$/ and print 
"$File::Find::name $File::Find::dir"}, no_chdir=>1},grep{$_ ne "."}@INC)'

Are we recreating the script from perlmonks? I already deleted that 
message, so I can't go back and check.

With my bias against File::Find (and for glob()), I'd probably do the 
whole thing like

  perl -le '@d=map {[$_,$_]} sort {length($b)<=>length($a)} grep
{!/^\./} @INC; while(@d) {($_,$d)=@{shift @d}; next if $e{$_}++; print 
substr($_, 1+length($d)) if /\.pm$/; push @d, map {[$_,$d]} glob("$_/*") 
if -d $_}'

but that took me a while to come up with, and has gone way over the 
one-liner threshold. :-) I just prefer doing the search explicitly, 
because I always find myself wanting more control and not wanting to try 
to track down some oddly-named configuration setting to do half of what 
I want.

Back to work. No email checking for a while.


More information about the Oakland mailing list