Skip to content

Commit

Permalink
Merge pull request #102 from nyrdz/main
Browse files Browse the repository at this point in the history
Allow PPI::Statement::Expression in hash key
  • Loading branch information
oalders committed Aug 19, 2023
2 parents 33a3136 + c568fe7 commit 8c5d75c
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 15 deletions.
46 changes: 31 additions & 15 deletions lib/App/perlimports/Document.pm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use PPIx::Utils::Classification qw(
is_hash_key
is_method_call
);
use Ref::Util qw( is_plain_arrayref is_plain_hashref );
use Ref::Util qw( is_plain_arrayref is_plain_hashref );
use Scalar::Util qw( refaddr );
use Sub::HandlesVia;
use Text::Diff ();
use Try::Tiny qw( catch try );
Expand Down Expand Up @@ -396,21 +397,9 @@ sub _build_possible_imports {
# sub any {}
next if $self->is_sub_name("$word");

my $isa_symbol = $word->isa('PPI::Token::Symbol');
next if !$word->isa('PPI::Token::Symbol') && is_method_call($word);

next if !$isa_symbol && is_method_call($word);

# A hash key might, for example, be a variable.
if (
!$isa_symbol
&& !(
$word->statement
&& $word->statement->isa('PPI::Statement::Variable')
)
&& is_hash_key($word)
) {
next;
}
next if $self->_is_word_interpreted_as_string($word);

push @after, $word;
}
Expand Down Expand Up @@ -1138,6 +1127,33 @@ sub _maybe_cache_inspectors {
return;
}

sub _is_word_interpreted_as_string {
my ( $self, $word ) = @_;

return unless $word->statement && $word->isa('PPI::Token::Word');
my @children = $word->statement->schildren;

# https://perldoc.perl.org/perlref#Not-so-symbolic-references
return 1 if is_hash_key($word) && @children == 1;

# The => operator (sometimes pronounced "fat comma") is a synonym for
# the comma except that it causes a word on its left to be interpreted
# as a string if it begins with a letter or underscore and is composed
# only of letters, digits and underscores. This includes operands that
# might otherwise be interpreted as operators, constants, single number
# v-strings or function calls.
# https://perldoc.perl.org/perlop#Comma-Operator
return unless $word->content =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/;

while ( my $current = shift @children ) {
last if refaddr($current) == refaddr($word);
}
return unless ( my $current = shift @children );
return 1
if $current->isa('PPI::Token::Operator')
&& $current->content eq '=>';
}

1;

# ABSTRACT: Make implicit imports explicit
Expand Down
25 changes: 25 additions & 0 deletions t/hash-key-expression.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env perl

use strict;
use warnings;

use lib 't/lib';

use TestHelper qw( file2includes source2pi );
use Test::More import => [qw( done_testing is )];
use Test::Needs qw( HTTP::Status );

my @includes = file2includes('test-data/hash-key-expression.pl');

my $e = source2pi(
'test-data/hash-key-expression.pl', undef,
{ include => $includes[2] }
);

is(
$e->formatted_ppi_statement,
'use HTTP::Status qw( is_info );',
'recognizes is_info as an imported symbol'
);

done_testing;
25 changes: 25 additions & 0 deletions t/hash-unquoted-key.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env perl

use strict;
use warnings;

use lib 't/lib';

use TestHelper qw( file2includes source2pi );
use Test::More import => [qw( done_testing is )];
use Test::Needs qw( HTTP::Status );

my @includes = file2includes('test-data/hash-unquoted-key.pl');

my $e = source2pi(
'test-data/hash-unquoted-key.pl', undef,
{ include => $includes[2] }
);

is(
$e->formatted_ppi_statement,
'use HTTP::Status ();',
'recognizes is_info as a word representing a string'
);

done_testing;
8 changes: 8 additions & 0 deletions test-data/hash-key-expression.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use strict;
use warnings;

use HTTP::Status qw(is_info);

my %foo;
my $code = 100;
$foo{ is_info $code } = 'bar';
7 changes: 7 additions & 0 deletions test-data/hash-unquoted-key.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use strict;
use warnings;

use HTTP::Status ();

my %foo;
$foo{is_info} = 1;

0 comments on commit 8c5d75c

Please sign in to comment.