読者です 読者をやめる 読者になる 読者になる

Plaggerで使われているモジュール一覧を出力する

テストで使われているモジュールとかの一覧を集計するのがなかなか面白そうだったので、それを Plaggerに対してやってみようということでやってみました。

Plaggerのレベルだと使われている回数を出すのはあまり意味がなさそうなので、モジュール一覧だけ。CPAN全体の傾向みるのとかも結構面白いかもしれないですね。

http://gist.github.com/11757

#!/usr/bin/env perl
use strict;
use warnings;
use Carp;
use PPI::Document;
use Path::Class qw(dir);
use File::Find::Rule;
use List::MoreUtils qw(uniq any);
use Perl6::Say;

main();

sub main {
    my $dir = $ARGV[0];
    croak 'module dir must be set.' unless $dir;
    my $perl_files        = find_perl_files($dir);
    my $all_modules       = extract_all_modules($perl_files);
    my $module_name_space = $ARGV[1];
    croak 'module namespace must be set.' unless $module_name_space;
    my $modules_in_plagger
        = used_modules_by_module( $all_modules, $module_name_space );
    print_modules($modules_in_plagger);
}

sub extract_all_modules {
    my $perl_files  = shift;
    my @all_modules = ();
    for my $file ( @{$perl_files} ) {
        my $modules = extract_modules($file);
        push @all_modules, @{$modules};
    }
    \@all_modules;
}

sub find_perl_files {
    my $module_dir = shift;
    my @files      = File::Find::Rule->file()->name('*.pm')->in($module_dir);
    \@files;
}

sub extract_modules {
    my $file = shift;
    croak "File does not exist!" unless -e $file;

    my $document = eval { PPI::Document->new($file) };
    unless ($document) {
        warn "Could not parse file [$file]";
        return;
    }

    my $modules = $document->find( \&is_module_statement );

    my @modules = eval {
        map { $_->module } @{$modules};
    };

    \@modules;
}

sub is_module_statement {
    my $ppi = $_[1];
    return 0 unless ( $ppi->isa('PPI::Statement::Include') );
    return 0 unless $ppi->type eq 'use';
    my @not_modules
        = qw/strict warnings utf8 overload integer mro parent vars constant bytes attributes base/;
    return 0 if any { $ppi->module eq $_ } @not_modules;
    return 1;

}

sub used_modules_by_module {
    my $all_modules      = shift;
    my $module_namespace = shift;
    my @used_modules     = uniq @{$all_modules};
    @used_modules = grep { $_ !~ /^${module_namespace}/ } @used_modules;
    \@used_modules;
}

sub print_modules {
    my $modules        = shift;
    my @sorted_modules = sort @{$modules};
    say join( "\n", @sorted_modules );
}

__END__

実行結果は、以下の通り。

Acme::Lou
Audio::Beep
Carp
Config::INI::Simple
Cwd
DB_File
Data::Dumper
Data::ICal
Data::ICal::Entry::Event
Data::Serializer
Date::Parse
DateTime
DateTime::Duration
DateTime::Event::Cron
DateTime::Format::Epoch
DateTime::Format::ICal
DateTime::Format::Mail
DateTime::Format::Strptime
DateTime::Format::W3CDTF
DateTime::Locale
DateTime::TimeZone
DateTime::TimeZone::OffsetOnly
Digest::MD5
DirHandle
Email::Address
Email::MIME
Encode
Encode::MIME::Header
Feed::Find
File::Basename
File::Copy
File::Copy::Recursive
File::Find
File::Find::Rule
File::Grep
File::Mork
File::Path
File::Spec
File::Spec::Functions
File::Temp
FindBin
Flickr::API
Gungho
Gungho::Request
HTML::Entities
HTML::Parser
HTML::ResolveLink
HTML::Scrubber
HTML::Tagset
HTML::Tidy
HTML::TokeParser
HTML::TreeBuilder::XPath
HTTP::Async
HTTP::Cookies
HTTP::Request
HTTP::Request::Common
Hatena::Keyword
IO::File
IO::Socket::INET
IO::Socket::UNIX
IPC::Run
Image::Info
JSON::Syck
KinoSearch::Analysis::PolyAnalyzer
KinoSearch::Index::Term
KinoSearch::InvIndexer
KinoSearch::Searcher
LWP::Parallel::UserAgent
Lingua::EN::Summarize
Lingua::JA::Summarize::Extract
Lingua::ZH::HanDetect
List::Util
Locale::Country
Locale::Language
MIME::Base64
MIME::Lite
MIME::Type
MIME::Types
MP3::Info
Mac::AppleScript
Mac::Files
Mac::Growl
Mac::Speech
Mac::Tie::PList
Mac::iTunes
Mail::IMAPClient
Mail::SpamAssassin
Module::Pluggable::Fast
Net::Amazon
Net::Amazon::Request::Keyword
Net::DNS::Resolver
Net::Delicious
Net::Google::Calendar
Net::MovableType
Net::NetSend
Net::POP3
Net::Telnet
Net::Twitter
PDF::FromHTML
POE
POE::Component::IKC::ClientLite
POE::Session
POE::Wheel::Run
POSIX
Palm::PalmDoc
Rast
Regexp::Common
SOAP::Transport::HTTP
SVN::Client
SVN::Core
SWF::Builder
Scalar::Util
Search::Estraier
Spreadsheet::WriteExcel
Storable
Template::Plugin::JavaScript
Template::Provider::Encoding
Template::Stash::ForceUTF8
Text::CSV_PP
Text::Emoticon
Text::Hatena
Text::Kakasi
Text::Language::Guess
Text::Markdown
Text::Original
Text::ParseWords
Text::Tags::Parser
Time::HiRes
UNIVERSAL
UNIVERSAL::require
URI
URI::Escape
URI::Fetch
URI::Find
URI::QueryParam
URI::file
URI::http
Unicode::Normalize
WWW::Babelfish
WWW::HatenaDiary
WWW::Mixi
WWW::Mixi::Scraper
WebService::Bloglines
WebService::BuzzurlAPI
WebService::YouTube
Win32::IEFavorites
Win32::Locale
Win32::MCI::Basic
Win32::MSAgent
Win32::OLE
Win32::PowerPoint
Win32::SAPI4
Win32::Sound
XML::Atom
XML::Atom::Client
XML::Atom::Entry
XML::FOAF
XML::Feed
XML::Feed::Entry
XML::Feed::RSS
XML::LibXML
XML::LibXML::SAX
XML::RSS::LibXML
XMLRPC::Lite
Xango::Broker::Push
YAML
YAML::Syck