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

Preview:

Citation preview

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

Recommended