Last active
June 6, 2016 14:43
-
-
Save briandfoy/b1409e5ee06bd38200d8 to your computer and use it in GitHub Desktop.
Find all the environment variables you might use in Perl. There are are false positives here, but so what.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use File::Find; | |
use List::MoreUtils qw(uniq); | |
use v5.22; | |
use feature qw(postderef signatures); | |
no warnings qw(experimental::postderef experimental::signatures); | |
use Data::Dumper; | |
use PPI::Document; | |
use PPI::Dumper; | |
my %Results; | |
my $wanted = sub { | |
return unless /\.(?:pod|pm|pl)\z/; | |
my $data = do { local( @ARGV, $/ ) = $File::Find::name; <> }; | |
my @vars = extract_env( $data ); | |
push @{ $Results{$_} }, $File::Find::name for @vars; | |
}; | |
find( { wanted => $wanted, no_chdir => 1 }, @ARGV ); | |
say "===Key Count Report==="; | |
foreach my $key ( sort { @{ $Results{$a} } <=> @{ $Results{$b} } } keys %Results ) { | |
say "$key: " . @{ $Results{$key} }; | |
} | |
say "===File Report==="; | |
foreach my $key ( keys %Results ) { | |
next if $key =~ / \A [A-Z0-9_]+ \z /x; | |
say "$key: " . @{ $Results{$key} }; | |
} | |
sub extract_env ( $data ) { | |
my @keys = | |
map { # some PPI trees may contain many types, so try all of them | |
my @words = | |
handle_words( $_->[1] ), | |
handle_double_quoted( $_->[1] ), | |
handle_double_qq( $_->[1] ); | |
} | |
map { [ $_, PPI::Document->new( \$_ ) ] } | |
$data =~ / | |
[ \$%\@ ] # sigil | |
\s* | |
ENV # var name | |
\s* | |
\{ # starting key list | |
( | |
.*? | |
) | |
} # ending key list | |
/xg; | |
@keys; | |
} | |
sub handle_words ( $ppi ) { | |
my $nodes = $ppi->find( sub { | |
( | |
$_[1]->isa('PPI::Token::Word') || | |
$_[1]->isa('PPI::Token::Quote') || | |
$_[1]->isa('PPI::Token::QuoteLike::Words') | |
) | |
&& | |
not_next_to_operator( $_[1] ) | |
&& | |
$_[1]->can( 'literal' ) | |
&& | |
$_[1]->literal | |
} ); | |
return unless $nodes; | |
my @words = map { $_->literal } @$nodes; | |
@words; | |
} | |
sub handle_double_quoted ( $ppi ) { | |
my $nodes = $ppi->find( sub { | |
( | |
$_[1]->isa('PPI::Token::Quote::Double') | |
) | |
&& | |
! $_[1]->interpolations | |
&& | |
$_[1]->can( 'string' ) | |
&& | |
$_[1]->string | |
} ); | |
return unless $nodes; | |
my @words = map { $_->string } @$nodes; | |
@words; | |
} | |
sub handle_double_qq ( $ppi ) { | |
my $nodes = $ppi->find( sub { | |
( | |
$_[1]->isa('PPI::Token::Quote::Interpolate') | |
) | |
&& | |
$_[1]->can( 'string' ) | |
&& | |
$_[1]->string | |
} ); | |
return unless $nodes; | |
my @words = map { $_->string } @$nodes; | |
@words; | |
} | |
sub not_next_to_operator ( $ppi ) { | |
my $next_to_operator = | |
eval { $ppi->snext_sibling->isa( 'PPI::Token::Operator' ) } | |
|| | |
eval { $ppi->sprevious_sibling->isa( 'PPI::Token::Operator' ) }; | |
# if we aren't next to an operator, who cares? | |
return 1 unless $next_to_operator; | |
return 0 if( | |
eval { | |
$ppi->snext_sibling | |
&& | |
$ppi->snext_sibling->content ne ',' | |
} | |
); | |
return 0 if( eval { | |
$ppi->sprevious_sibling | |
&& | |
$ppi->sprevious_sibling->content ne ',' | |
} | |
); | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment