App-perlimports
view release on metacpan or search on metacpan
script/perlimports view on Meta::CPAN
#!perl
use strict;
use warnings;
use App::perlimports::CLI ();
use Try::Tiny qw( catch try );
my $exit_code = 0;
try {
$exit_code = App::perlimports::CLI->new->run;
}
catch {
print STDERR $_;
$exit_code = 1;
};
exit($exit_code);
# PODNAME: perlimports
# ABSTRACT: A command line utility for cleaning up imports in your Perl code
__END__
=pod
=encoding UTF-8
=head1 NAME
perlimports - A command line utility for cleaning up imports in your Perl code
=head1 VERSION
version 0.000060
=head1 SYNOPSIS
Create a config file called C<perlimports.toml> at the top level of your
application or repository:
perlimports --create-config-file perlimports.toml
You can also have a config file with a leading C<.>.
perlimports --create-config-file .perlimports.toml
For system-wide defaults, you can create a file in C<$XDG_HOME>. Something like:
perlimports --create-config-file ~/.config/perlimports/perlimports.toml
After you have set up the config file to your liking, you can do away with most
command line switches, other than C<-i>, C<--lint> or C<--read-stdin>.
Now, let's update a file in place. (Make sure you can revert the file if you
need to, as C<perlimports> will not make a backup.)
perlimports -i foo.pl
Lint a file:
perlimports --lint foo.pl
In-place edits on directories:
perlimports -i lib t xt
Lint directories:
perlimports --lint lib t xt
In-place edits on files and directories
perlimports -i foo.pl lib t xt
Run C<perlimports> on a file and only print the results to STDOUT.
perlimports foo.pl
If some of your imported modules are in local directories, you can give some
hints as to where to find them:
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
script/perlimports view on Meta::CPAN
is equivalent to
perlimports path/to/file
You may also pass multiple file and dir names.
perlimports path/to/file path/to/other/file lib t xt
=head2 --ignore-modules
A comma-separated list of module names which should be ignored by this script.
Any modules in this list should remain unchanged after processing.
--ignore-modules Foo,Foo::Bar
=head2 --ignore-modules-filename
The absolute or relative path to a file which contains a lost of module names
to ignore. (See above for behaviour). The pattern is one module name per line.
Foo
Foo::Bar
=head2 --ignore-modules-pattern
A regular expression to match module names which should be ignored by this
script. Any modules matched by this regular expression remain unchanged after
processing.
--ignore-modules-pattern '^(Foo|Foo::Bar)'
=head2 --ignore-modules-pattern-filename
The absolute or relative path to a file which contains a list of regular
expression that matches modules that should be ignored. (See above for behaviour).
The pattern is one regular expression per line.
^Foo
^Foo::Bar
=head2 --never-export-modules
A comma-separated list of module names which should never export symbols. If
these modules are found, we will ensure that they have an empty import list.
So, C<use Foo;> becomes C<use Foo ();>.
--never-export-modules Foo,Foo::Bar
=head2 --never-export-modules-filename
The absolute or relative path to a file which contains a lost of module names
which should never export symbols. (See above for behaviour). The pattern is
one module name per line.
Foo
Foo::Bar
=head2 --inplace-edit|-i
Edit the file in place rather than printing the result to STDOUT. Make sure you
have a backup copy first.
--inplace--edit
-i
Edit the file in place rather than printing the result to STDOUT. Make sure you
have a backup copy first.
=head2 --json
(Experimental). If enabled, linting errors will be emitted as JSON objects with
one object per error. This is intended to make it easier for editors to parse
line numbers and column numbers as well as the error message. This flag can
only be used in tandem with C<--lint>.
=head2 --lint
If this argument is passed, C<perlimports> will act as a linter, rather than a
tidier. Failure (and success) messages will be reported on STDERR. Failures
will also return a non-zero exit code.
This is still a bit experimental, so the output format and exit codes could
change in a subsequent release.
This cannot be combined with tidying. So, passing C<--lint --inplace-edit> will
generate an error.
=head2 --indent
Sets the indent width in spaces for C<qw()> import lists that are split across
multiple lines. Defaults to the value of perltidy's C<indent-columns> setting
(read from C<.perltidyrc> if present), or 4 if unset.
# --indent 2
use Foo qw(
bar
baz
);
=head2 --[no-]pad-brackets
When enabled, adds whitespace inside the square brackets of test builder import
lists. Defaults to disabled.
# --pad-brackets
use Test::More import => [ qw( ok ) ];
# --no-pad-brackets
use Test::More import => [qw( ok )];
=head2 --[no-]padding
C<--padding> is enabled by default, so you only need to pass this arg if you
want to be explicit. This setting adds whitespace inside the parentheses.
# --padding
use Foo qw( bar baz );
The C<--no-padding> arg allows you to disable the additional padding inside
parentheses.
# --no-padding
use Foo qw(bar baz);
=head2 --[no-]tidy-whitespace
C<--tidy-whitespace> is enabled by default. This means that use statements will
script/perlimports view on Meta::CPAN
The above statement will allow you to visually select one or more lines of code
and have them updated in place by C<perlimports>. Once you have selected the
code enter C<im> to have your imports (re)formatted.
=head2 VIM and ALE
If you use ALE with vim, you can add something like this to your C<vim>
configuration. Note that this function will save your buffer before running
C<perlimports>.
function! Perlimports(buffer) abort
write
return {
\ 'command': 'perlimports --read-stdin -f %s'
\}
endfunction
let ale_fixers.perl = ['perlimports', 'perltidy']
execute ale#fix#registry#Add('perlimports', 'Perlimports', ['perl'], 'Tidy Perl imports')
=head2 Emacs and Flycheck
L<Flycheck|https://www.flycheck.org/> 35 and newer will suggest changes
from C<perlimports> automatically if it finds that it is installed.
=head2 precious
If you're a L<https://github.com/houseabsolute/precious> user, your
configuration might look something like this:
exclude = [
# Used by Dist::Zilla
".build",
"App-perlimports-*",
"blib",
"inc",
"test-data",
# All of these are generated by Dist::Zilla
"t/00-*",
"t/author-*",
"t/release-*",
"xt/author",
"xt/release",
]
[commands.perlimports]
type = "both"
include = [ "**/*.{pl,pm,t,psgi}" ]
cmd = [ "perlimports" ]
lint_flags = [ "--lint"]
tidy_flags = [ "-i"]
ok_exit_codes = 0
expect_stderr = true
[commands.perltidy]
type = "both"
include = [ "**/*.{pl,pm,t,psgi}" ]
cmd = [ "perltidy", "--profile=$PRECIOUS_ROOT/perltidyrc" ]
lint_flags = [ "--assert-tidy", "--no-standard-output", "--outfile=/dev/null" ]
tidy_flags = [ "--backup-and-modify-in-place", "--backup-file-extension=/" ]
ok_exit_codes = 0
lint_failure_exit_codes = 2
expect_stderr = true
Note that L<https://github.com/houseabsolute/precious> runs plugins in order,
so we've placed a L<perltidy> config after L<perlimports>. This is handy
because L<perlimports> could introduce changes which will later be reverted by
L<perltidy>. By running them sequentially we can avoid false positives which
might be generated by L<perlimports> changing an include which L<perltidy>
might revert.
For an up to date example, see the config file which this repository uses:
L<https://github.com/oalders/App-perlimports/blob/main/precious.toml>
=head2 Code::TidyAll
If you're a L<Code::TidyAll> user, you can configure C<perlimports> as a
GenericTransformer. Your configuration might look something like this:
[GenericTransformer perlimports]
select = **/*.{pl,pm,t,psgi}
ignore = .build/**/*
ignore = App-perlimports-*/**/*
ignore = blib/**/*
ignore = fatlib/**/*
ignore = inc/**/*
ignore = t/00-*
ignore = t/author-*
ignore = t/release-*
ignore = t/zzz-*
ignore = test-data/**/*
ignore = xt/**/*
ignore = xt/author/{pod-coverage,pod-spell,tidyall}.t
argv = --libs lib,t/lib --no-preserve-duplicates --no-preserve-unused --log-filename /tmp/perlimports.txt --log-level debug
cmd = perlimports
file_flag = -f
ok_exit_codes = 0
weight = 1
Note that in this case we've set the lowest possible weight. This is because we
want C<perlimports> to run before any other plugin which may transform the
file. For example, you'll want L<perltidy> to run after C<perlimports> to avoid
having to re-tidy files after your use statements have been rewritten.
If you want to use C<tidyall> to run just C<perlimports> you'll need to do
something like:
tidyall --plugin "GenericTransformer perlimports" -a
For an up to date example, see the config file which this repository uses:
L<https://github.com/oalders/App-perlimports/blob/main/tidyall.ini>
=head1 RECIPES
Included are some examples to use if you want to employ your own file finding
logic or prefer not to use config files. If this does not apply to you, you can
safely skip this section.
Running perlimports on test files
( run in 0.626 second using v1.01-cache-2.11-cpan-63c85eba8c4 )