App-perlimports
view release on metacpan or search on metacpan
lib/App/perlimports/Document.pm view on Meta::CPAN
next if $word eq 'package' && $word == $first;
}
elsif ( $stm->isa('PPI::Statement::Include') ) {
if ( my $packname = $stm->module ) {
$pack{$packname} ||= 1; # even if its a pragma
if ( $packname eq 'constant' ) {
next unless my @data = $self->_parse_constant($stm);
$const{ $_->{name} } ||= $_ for @data;
next if any { $word == $_->{token} } @data;
}
my $package_bareword = $stm->schild(1);
next if $word == $package_bareword;
}
next if $word eq 'use' && $word == $first;
next if $stm->pragma && $word eq 'no' && $word == $first;
}
}
next
if $const{"$word"}
&& ( is_hash_key($word) || is_function_call($word) );
next if $pack{"$word"} && is_class_name($word); # class method calls
push @after, $word;
}
# safe to assume our search encountered every 'use constant' statement
if ( %const && !$self->_has_constants ) {
$self->_set_constants(%const);
$self->logger->debug("constants found: @{[sort keys %const]}");
}
return \@after;
}
## use critic
sub _build_ppi_document {
my $self = shift;
return PPI::Document->new( $self->_filename );
}
# Create a key for every included module.
# use Carp;
# use Data::Dumper qw( Dumper );
# use POSIX ();
#
# becomes:
#
# {
# Carp => undef,
# 'Data::Dumper' => ['Dumper'],
# POSIX => [],
# }
#
# In lint mode, it never changes. In edit mode, it starts out as a list of
# original imports, but with each include that gets processed, this list gets
# updated. We do this so that we can keep track of what previous modules
# are really importing, avoiding duplicate imports.
sub _build_found_imports {
my $self = shift;
# We're missing requires which could be followed by an import.
my $found = $self->ppi_document->find(
sub {
$_[1]->isa('PPI::Statement::Include')
&& !$_[1]->pragma # no pragmas
&& !$_[1]->version # Perl version requirement
&& $_[1]->type
&& $_[1]->type eq 'use';
}
) || [];
my %imports;
for my $include ( @{$found} ) {
my $pkg = $include->module;
$imports{$pkg} = undef unless exists $imports{$pkg};
# this is probably wrong
#next if $self->_is_ignored($pkg);
# If a module has been included multiple times, we want to have a
# cumulative tally of what has been explicitly imported.
my $found_for_include = _imports_for_include($include);
if ($found_for_include) {
if ( $imports{$pkg} ) {
my %catalog = map { $_ => 1 } @{ $imports{$pkg} },
@{$found_for_include};
$imports{$pkg} = [ sort keys %catalog ];
}
else {
$imports{$pkg} = $found_for_include;
}
}
}
return \%imports;
}
sub _build_sub_exporter_export_list {
my $self = shift;
my $sub_ex = $self->ppi_document->find(
sub {
$_[1]->isa('PPI::Statement::Include')
&& $_[1]->module eq 'Sub::Exporter';
}
) || [];
return [] unless @{$sub_ex};
my @found;
for my $include ( @{$sub_ex} ) {
my @arguments = $include->arguments;
for my $arg (@arguments) {
if ( $arg->isa('PPI::Structure::Constructor') ) {
## no critic (BuiltinFunctions::ProhibitStringyEval)
lib/App/perlimports/Document.pm view on Meta::CPAN
upon by anything else.
=head2 inspector_for( $module_name )
Returns an L<App::perlimports::ExporterInspector> object for the given module.
=head2 linter_success
Returns true if document was linted without errors, otherwise false.
=head2 tidied_document
Returns a serialized PPI document with (hopefully) tidy import statements.
=head1 ATTRIBUTES
=over 4
=item constants
Hashref catalog of detected constants in the document. So the line:
use constant FIRST_IDX => 0;
results in a corresponding entry in the constants hashref:
FIRST_IDX => {
name => 'FIRST_IDX', # (plain string)
token => 'FIRST_IDX', # (PPI::Token::Word usually)
definition => [ PPI::Token.. ],
end => { line => 9, column => 32 },
},
The C<end> is the (line, character) position of the last character of the
constant import statement. This might be useful since the constant is only
defined (at compile time!) after this statement.
(Note: locations can become stale!)
The C<name> field is useful when the constant was defined using atypical
syntax (no fat arrow), since the token doesn't stringify the same:
use constant 'FIRST_IDX', 0;
# token eq "'FIRST_IDX'", # (PPI::Token::Quote::Single)
# name eq 'FIRST_IDX', # same as $token->string
=item includes
An arrayref of L<PPI::Statement::Include> statements found in the document,
excluding pragmas, ignored modules, and 'use VERSION' statements.
=item found_imports
A hashref catalog of symbols imported from each package by a use statement,
e.g.
{ Carp => ['croak', ..], ... }
In lint mode, this attribute is never altered.
In edit mode, when L<tidied_document> is called, with each include that gets
processed, this list gets updated to what we think it should be. We do this
so that we can keep track of what previous modules are really importing, to
avoid duplicate imports (same symbol name from different packages).
=back
=head1 AUTHOR
Olaf Alders <olaf@wundercounter.com>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2020 by Olaf Alders.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
( run in 0.864 second using v1.01-cache-2.11-cpan-e93a5daba3e )