App-perlimports
view release on metacpan or search on metacpan
script/perlimports view on Meta::CPAN
perlimports -i --libs t/lib,/some/dir/lib foo.pl
Redirect output to a new file:
perlimports foo.pl > foo.new.pl
=head1 DESCRIPTION
This distribution provides the C<perlimports> command line interface (CLI),
which automates the cleanup and maintenance of Perl C<use> and C<require>
statements. Loosely inspired by
L<goimports|https://pkg.go.dev/golang.org/x/tools/cmd/goimports>, this tool
aims to be part of your linting and tidying workflow, in much the same way you
might use L<perltidy> or L<perlcritic>.
For a detailed discussion of the problems this tool attempts to solve, see
this "Conference in the Cloud" talk from June 2021:
L<Where did that Symbol Come From?|https://www.youtube.com/watch?v=fKqxdTbGxYY>.
Slides for the above talk are also available:
curl -O https://raw.githubusercontent.com/oalders/presentations/main/slides/6-perlimports/remark.html && open remark.html
=head1 MOTIVATION
Many Perl modules helpfully export functions and variables by default. These
provide handy shortcuts when you're writing a quick or small script, but they
can quickly become a maintenance burden as code grows organically. When code
increases in complexity, it leads to greater costs in terms of development time.
Conversely, reducing code complexity can speed up development. This tool aims
to reduce complexity to further this goal.
While importing symbols by default or using export tags provides a convenient
shorthand for getting work done, this shorthand requires the developer to
retain knowledge of these defaults and tags in order to understand the code.
C<perlimports> aims to allow you to develop your code as you see fit, while
still giving you a viable option of tidying your imports automatically. In much
the same way as you might use L<perltidy> to format your code, you can now
automate the process of making your imports easier to understand. Let's look at
some examples.
=over
=item Where is this function defined?
You may come across some code like this:
use strict;
use warnings;
use HTTP::Request::Common;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
my $req = $ua->request( GET 'https://metacpan.org/' );
print $req->content;
Where does C<GET> come from? If you're not familiar with
L<HTTP::Request::Common>, you may not realize that the statement C<use
HTTP::Request::Common> has implicitly imported the functions C<GET>, C<HEAD>,
C<PUT>, C<PATCH>, C<POST> and C<OPTIONS> into to this block of code.
What would happen if we used C<perlimports> to import all needed functions
explicitly? It might look something like this:
use strict;
use warnings;
use HTTP::Request::Common qw( GET );
use LWP::UserAgent ();
my $ua = LWP::UserAgent->new;
my $req = $ua->request( GET 'https://metacpan.org/' );
print $req->content;
The code above makes it immediately obvious where C<GET> originates, which in
turn makes it easier for us to look up its documentation. It has the added
bonus of also not importing C<HEAD>, C<PUT> or any of the other functions which
L<HTTP::Request::Common> exports by default. So, those functions cannot
unwittingly be used later in the code. This makes for more understandable code
for present day you, future you and any others tasked with reading your code at
some future point.
Keep in mind that this simple act can save much time for developers who are not
intimately familiar with Perl and the default exports of many CPAN modules.
=item Are we even using all of these imports?
Imagine the following import statement
use HTTP::Status qw(
is_cacheable_by_default
is_client_error
is_error
is_info
is_redirect
is_server_error
is_success
status_message
);
followed by 3,000 lines of code. How do you know if all of these functions are
actually being used? Were they ever used? You can grep all of these function
names manually or you can remove them by trial and error to see what breaks.
This is a doable solution, but it does not scale well to scripts and modules
with many imports or to large code bases with many imports. Having an
unmaintained list of imports is preferable to implicit imports, but it would be
helpful to automate maintaining this list.
L<perlimports> can, in many situations, clean up your import statements and
automate this maintenance burden away. This makes it easier for you to write
clean code, which is easier to understand.
=item Are we even using all of these modules?
In cases where code is implicitly importing from modules or where explicit
imports are not being curated, it can be hard to discover which modules are no
longer being used in a script, module or even a code base. Removing unused
modules from code can lead to gains in performance and decrease in consumption
of resources. Removing entire modules from your code base can decrease the
number of dependencies which you need to manage and decrease friction in your
your deployment process.
C<perlimports> can remove unused modules for you, making dependency management
much easier.
=item Enforcing a consistent style
Having a messy list of module imports makes your code harder to read. Imagine
this:
use Cpanel::JSON::XS;
use Database::Migrator::Types qw( HashRef ArrayRef Object Str Bool Maybe CodeRef FileHandle RegexpRef );
use List::AllUtils qw( uniq any );
use LWP::UserAgent q{};
use Try::Tiny qw/ catch try /;
use WWW::Mechanize q<>;
( run in 0.497 second using v1.01-cache-2.11-cpan-5b529ec07f3 )