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 )