Better detection of what modules are used by some Perl 5 code Kenichi Ishigaki @charsbar London Perl Workshop 2017 Nov 25, 2017
me • DBD::SQLite • CPANTS • PAUSE on Plack/Mojolicious • JSON
It's annoying if prereqs are not correctly declared
CPANTS has two metrics to warn this issue • prereq_matches_use • build_prereq_matches_use
They usually work, but sometimes don't # CPANTS mistakenly complains my $template =<<'END'; package [% NAME %]; use Foo::Bar; # should be ignored END # CPANTS doesn't complain but... use Shiny::New::Loader; # ok load("Something::Else"); # ignored
Other detectors? • Perl::PrereqScanner (which uses PPI) • Perl::PrereqScanner::Lite (which uses Compiler::Lexer) Limitation: Test::Kwalitee
Perl::PrereqScanner:: NotQuiteLite • (usually) faster than Perl::PrereqScanner • slower than Perl::PrereqScanner::Lite, but more stable Target: lib/Perl/PrereqScanner/NotQuiteLite.pm Rate P::PS P::PS::NQL M::EU P::PS::L P::PS 0.999/s -- -87% -95% -97% P::PS::NQL 7.69/s 670% -- -62% -76% M::ExtractUse 20.3/s 1932% 164% -- -36% P::PS::Lite 31.7/s 3073% 312% 56% --
It recognises not only Moose family use Moose; extends 'Foo::Bar'; # requires with 'Some::Role'; # requires as well
including MooseX::Declare use MooseX::Declare; class MyClass extends Foo::Baz with Role { ... }
but also other major frameworks use Catalyst qw/ My::Module +Fully::Qualified::Plugin::Name /; use Mojo::Base 'Mojo::Base'; use Dancer2::Plugin; extends('Dancer2::Plugin::ParamTypes'); use Plack::Builder; builder { enable_if { ... } 'MyMiddleware'; };
and more... aliased autouse later mixin only prefork superclass unless Class::Accessor Class::Autouse Class::Load Inline Module::Runtime Syntax::Collector Test::Class::Most Test::Requires
and more... App::GHPT::Wrapper::OurMoose App::wmiirc::Plugin Ark Bot::Backbone::Service Bubblegum::Class CatalystX::Declare Cogwheel CPAN::Testers::Backend::Base Data::Object::Class DBICx::Modeler::Model Digital::Driver Elastic::Doc Fey::ORM::Table Form::Factory::Processor Jedi::App Momo Moonshine::Magic Moxie Nile::Base Parse::FixedRecord Pcore Reaction::Class Reaction::UI::WidgetClass Squirrel Statocles::Base TAEB::OO Test::Able Test::Roo Web::Simple XML::Rabbit
It distinguishes requires from recommends and suggests use Foo; # requires require Bar; # requires as well if (eval "require Baz") { # suggests require Quux; # recommends }
It even knows what "plan skip_all" means use Test::More; BEGIN { plan skip_all => "N/A" if $^O ne 'MSWin32'; } use Win32; # recommends
It doesn't really parse Perl but... • it recognises (long) strings including here documents • it accepts utf8 characters as a subroutine name ( sub λ {...} ) • and new keywords introduced by Syntax::Feature family ( qs(...) )
CPANTS will eventually complain if it finds a cheat q{ use strict; use warnings; }
Migration from Perl::PrereqScanner my $pps = Perl::PrereqScanner->new; my $requirements = $pps->scan_file(...); my $nql = Perl::PrereqScanner::NotQuiteLite->new; my $c = $nql->scan_file(...); my $requirements = $c->requires; # or $c->recommends, $c->suggests
Updating cpanfile scan-perl-prereqs-nqlite ¥ --save-cpanfile ¥ --exclude-core ¥ --recommends ¥ --suggests ¥ --develop You might want to move some of the recommends/suggests to requires.
Test::CPANfile • tests if all the used modules are listed in cpanfile • it's ok if cpanfile lists more than used • recognises runtime, test, and configure requirements
Thank you

Better detection of what modules are used by some Perl 5 code

  • 1.
    Better detection of whatmodules are used by some Perl 5 code Kenichi Ishigaki @charsbar London Perl Workshop 2017 Nov 25, 2017
  • 2.
    me • DBD::SQLite • CPANTS •PAUSE on Plack/Mojolicious • JSON
  • 3.
    It's annoying if prereqsare not correctly declared
  • 4.
    CPANTS has twometrics to warn this issue • prereq_matches_use • build_prereq_matches_use
  • 5.
    They usually work, butsometimes don't # CPANTS mistakenly complains my $template =<<'END'; package [% NAME %]; use Foo::Bar; # should be ignored END # CPANTS doesn't complain but... use Shiny::New::Loader; # ok load("Something::Else"); # ignored
  • 6.
    Other detectors? • Perl::PrereqScanner (whichuses PPI) • Perl::PrereqScanner::Lite (which uses Compiler::Lexer) Limitation: Test::Kwalitee
  • 7.
    Perl::PrereqScanner:: NotQuiteLite • (usually) fasterthan Perl::PrereqScanner • slower than Perl::PrereqScanner::Lite, but more stable Target: lib/Perl/PrereqScanner/NotQuiteLite.pm Rate P::PS P::PS::NQL M::EU P::PS::L P::PS 0.999/s -- -87% -95% -97% P::PS::NQL 7.69/s 670% -- -62% -76% M::ExtractUse 20.3/s 1932% 164% -- -36% P::PS::Lite 31.7/s 3073% 312% 56% --
  • 8.
    It recognises not onlyMoose family use Moose; extends 'Foo::Bar'; # requires with 'Some::Role'; # requires as well
  • 9.
    including MooseX::Declare use MooseX::Declare; classMyClass extends Foo::Baz with Role { ... }
  • 10.
    but also othermajor frameworks use Catalyst qw/ My::Module +Fully::Qualified::Plugin::Name /; use Mojo::Base 'Mojo::Base'; use Dancer2::Plugin; extends('Dancer2::Plugin::ParamTypes'); use Plack::Builder; builder { enable_if { ... } 'MyMiddleware'; };
  • 11.
    and more... aliased autouselater mixin only prefork superclass unless Class::Accessor Class::Autouse Class::Load Inline Module::Runtime Syntax::Collector Test::Class::Most Test::Requires
  • 12.
    and more... App::GHPT::Wrapper::OurMoose App::wmiirc::Plugin ArkBot::Backbone::Service Bubblegum::Class CatalystX::Declare Cogwheel CPAN::Testers::Backend::Base Data::Object::Class DBICx::Modeler::Model Digital::Driver Elastic::Doc Fey::ORM::Table Form::Factory::Processor Jedi::App Momo Moonshine::Magic Moxie Nile::Base Parse::FixedRecord Pcore Reaction::Class Reaction::UI::WidgetClass Squirrel Statocles::Base TAEB::OO Test::Able Test::Roo Web::Simple XML::Rabbit
  • 13.
    It distinguishes requiresfrom recommends and suggests use Foo; # requires require Bar; # requires as well if (eval "require Baz") { # suggests require Quux; # recommends }
  • 14.
    It even knowswhat "plan skip_all" means use Test::More; BEGIN { plan skip_all => "N/A" if $^O ne 'MSWin32'; } use Win32; # recommends
  • 15.
    It doesn't really parsePerl but... • it recognises (long) strings including here documents • it accepts utf8 characters as a subroutine name ( sub λ {...} ) • and new keywords introduced by Syntax::Feature family ( qs(...) )
  • 16.
    CPANTS will eventually complainif it finds a cheat q{ use strict; use warnings; }
  • 17.
    Migration from Perl::PrereqScanner my $pps= Perl::PrereqScanner->new; my $requirements = $pps->scan_file(...); my $nql = Perl::PrereqScanner::NotQuiteLite->new; my $c = $nql->scan_file(...); my $requirements = $c->requires; # or $c->recommends, $c->suggests
  • 18.
    Updating cpanfile scan-perl-prereqs-nqlite ¥ --save-cpanfile¥ --exclude-core ¥ --recommends ¥ --suggests ¥ --develop You might want to move some of the recommends/suggests to requires.
  • 19.
    Test::CPANfile • tests ifall the used modules are listed in cpanfile • it's ok if cpanfile lists more than used • recognises runtime, test, and configure requirements
  • 20.