Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

pmdesc2 - lists modules with description

by Aristotle (Chancellor)
on Aug 05, 2003 at 22:23 UTC ( [id://281203]=sourcecode: print w/replies, xml ) Need Help??
Category: Utility Scripts
Author/Contact Info /msg Aristotle
Description:

I recently looked at Tom Christiansen's scripts. One of them, called pmdesc, lists any or a subset of the modules you have installed, complete with the version number and a description. Handy! Unfortunately, it has several annoying traits. First of all, it's slow. Which one might live with, except it also picks up modules relative to wrong directories, so Foo::Bar might be reported, f.ex, as i686-linux::Foo::Bar.

No problem, I thought, I'll just hack it. Unfortunately, the source is, well, less than tidy, with several unnecessary-to-be globals and badly distributed responsibilities. For so little code, it is suprisingly confusing to follow.

So what's a hacker to do, eh? Here's a clean version.

I fixed the directory problem by visiting the longest paths first, which ensures we see any subdirectories prior to their ancestors while traversing the trees.

Speed was addressed by using an ExtUtils::MakeMaker utility function. While this imposes restrictions on the $VERSION assignments this script can cope with, CPAN uses the same function, so anything from CPAN is likely to comply anyway. Compared to the old code which had to actually compile each module, this is orders of magnitude faster.

#!/usr/bin/perl -w
use strict;

use Carp;
use ExtUtils::MakeMaker;
use File::Find qw(find);

$|++;

sub get_module_name {
    my ($path, $relative_to) = @_;

    local $_ = $path;
    s!\A\Q$relative_to\E/?!!;
    s! \.p(?:m|od) \z!!x;
    s!/!::!g;

    return $_;
}

sub get_module_description {
    my ($file) = @_;

    open my $pod, "<", $file
        or (warn("\tCannot open $file: $!"), return);

    local $_;
    local $/ = '';
    while (<$pod>) {
        if (/=head\d\s+NAME/) {
            $_ = <$pod>;
            return unless $_; # $_ may be undefined
            chomp;
            s/ \A .*? - \s+ //sx;
            tr/\n/ /;
            return $_;
        }
    }

    return;
}

sub get_module_version {
    local $_;     # MM->parse_version is naughty
    my $vers_code = MM->parse_version($File::Find::name) || '';
    return eval $vers_code || undef;
}

my %visited;

if(@ARGV) {
    if($ARGV[0] eq '-h') {
        print while <DATA>;
        exit;
    }
    shift if $ARGV[0] eq '--';
}
else {
    @ARGV = @INC;
}

for my $inc_dir (sort { length $b <=> length $a } @ARGV) {
    find({
        wanted => sub {
            return unless /\.p(?:m|od)\z/ && -f;

            my $module  = get_module_name($File::Find::name, $inc_dir)
+;
            my $version = get_module_version($_);
            my $desc    = get_module_description($_);

            $version = defined $version ? "($version)" : "";
            $desc    = defined $desc    ? "- $desc"    : "";
            print join (" ", $module, grep $_, $version, $desc), "\n";
        },
        preprocess => sub {
            my ($dev, $inode) = stat $File::Find::dir or return;
            $visited{"$dev:$inode"}++ ? () : @_;
        },
    },
    $inc_dir);
}

__DATA__
Usage:   pmdesc2 [-h] [--] [dir [dir dir ...]]
Options: -h      print this cruft
         If no parameters given, searches @INC
Replies are listed 'Best First'.
Re: pmdesc2 - lists modules with description
by ajdelore (Pilgrim) on Aug 05, 2003 at 23:10 UTC

    You might want to add:

    require 5.6;

    It wouldn't run for me on 5.005. Passing three arguments to open() is a 5.6 idiom, IIRC.

    Otherwise, very cool. ++.

    </ajdelore>

      In fact, you need 5.6.1 - that is the earliest release of Perl to have a version of File::Find that supports preprocess.

      Makeshifts last the longest.

Re: pmdesc2 - lists modules with description
by naChoZ (Curate) on Aug 06, 2003 at 15:11 UTC
    One thing I also did with this just for fun was set up a separate locate database for perl modules. Copied the updatedb to pmupdatedb, changed the find command line to just pmdesc2.pl, changed the locatedb name to pmlocatedb, and then set up an alias, alias pmlocate 'locate -d /usr/local/var/pmlocatedb'.

    (I have a very slow machine at home...)

    --
    "I just read perlman:perlboot," said Tom, objectively.
    naChoZ

Re: pmdesc2 - lists modules with description
by Anonymous Monk on Nov 06, 2004 at 19:07 UTC
    The speed improvement is great, but pmdesc2 has still some flaws:
    (1) Version numbers with more than one separating point (sub-subversion) will be converted into control characters.
    (2) DOS-terminated files are not handled correctly (no description found).
    (3) The extracted description is not limited to a maximal length, so faulty docs are slurped in completely.
    (4) Some modules are split into a pm-file and an accompanying pod-file which leads to double entries.
    I rewrote parts of the script and called it pmdesc3. It overcomes the above mentioned flaws. Output can be sorted and formated. It has a POD included. pmdesc3 is part of the VIM-plugin perl-support.vim (script # 556) and can be found at http://vim.sourceforge.net/scripts/script.php?script_id=556

      I rewrote parts of the script and called it pmdesc3. It overcomes the above mentioned flaws. Output can be sorted and formated. It has a POD included. pmdesc3 is part of the VIM-plugin perl-support.vim (script # 556) and can be found at http://vim.sourceforge.net/scripts/script.php?script_id=556

      Oh dear. Let me quote MJD’s File of Good Advice…

      #11911 You wrote the same thing twice here. The cardinal rule of programming is that you never ever write the same thing twice.

      Copy-pasting bits all over the code is not a good idea.

      In any case, I’ve fixed your complaints and posted a new version at lspm — list names and descriptions of Perl modules in a directory. It doesn’t have sorting, because I don’t see the point of implementing that as an option that won’t work on systems where you can pipe output to another process anyway, but it does address all the problems you brought up and adds a bonus feature too. The output should be more readily parsable, as well, although it doesn’t look the same as in your version.

      Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://281203]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-03-19 04:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found