MetaCPAN FTW!

Posted in: Technical Track

Right now, Galuga has a widget that lists my CPAN distributions. But it’s a boring old static affair that is updated manually. Surely in this age of the Web 2.0, I can do better than that.

My first instinct that to go straight for my CPAN author page and extract the information off the HTML:

sub distributions {
    my $self = shift;
    my $page = get $self->author_cpan_url;
    my $dists = pQuery($page)->find('table:eq(1) tr');
    my @dists;
    $dists->each(
        sub {
            return unless shift;    # first one is headers
            my $row  = pQuery($_);
            my $name = $row->find('td:eq(0) a')->text();
            $name =~ s/-v?([\d._]*)$//;    # remove version
            my $version = $1;
            my $url = "https://search.cpan.org/dist/$name";
            $name =~ s/-/::/g;
            my $desc = $row->find('td:eq(1)')->text();
            my $date = DateTime::Format::Flexible->parse_datetime(
                $row->find('td:eq(3)')->text );
            push @dists,
              { name    => $name,
                url     => $url,
                desc    => $desc,
                date    => $date,
                version => $version,
              };
        } );
    return @dists;
}

Not too painful, all in all. Mind you, it’d be nicer not to have to fiddle with HTML tables, but short of having a bona fide API…

And that’s when Olaf’s blog reminds me of search.metacpan.org and the CPAN-API project. After a few minutes of peering at what they have to offer, the code above got simplified to:

sub distributions {
    my $self = shift;
    my $page =
      get sprintf 'https://api.metacpan.org/dist/_search?q=author:"%s"',
      $self->author_id;
    my $json = from_json($page);
    return map { {
            name    => $_->{name},
            version => $_->{version},
            url     => 'https://search.cpan.org/dist/' . $_->{name},
            date    => DateTime::Format::Flexible->parse_datetime(
                $_->{release_date}
            ), } }
           map { $_->{_source} }
               @{ $json->{hits}{hits} };
}

Sweet, isn’t?

(The code for both variants of the widget is available at my WWW-Widget GitHub repo.)

email
Want to talk with an expert? Schedule a call with our team to get the conversation started.

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *