#!perl

our $DATE = '2014-09-17'; # DATE
our $VERSION = '0.02'; # VERSION

use 5.010;
use strict;
use warnings;

use App::PMUtils;
use Perinci::CmdLine::Any -prefer_lite=>1;

our %SPEC;
$SPEC{pluse} = {
    v => 1.1,
    summary => 'List required modules (via use()/require()) in a Perl script (or module)',
    description => <<'_',



_
    args => {
        module => {
            schema => 'str*',
            completion => $App::PMUtils::_complete_module,
            cmdline_aliases => {m=>{}},
        },
        file => {
            summary => 'Specify file instead of module',
            schema  => 'str*',
            pos     => 0,
        },
        detail => {
            schema => 'bool',
        },
    },
    result_naked=>1,
};
sub pluse {
    require Compiler::Lexer;
    require SHARYANTO::Module::Path;

    my %args = @_;
    my $path;
    if (defined $args{module}) {
        my $mod = $args{module};
        $mod =~ s/\.pm$//; $mod =~ s!/!::!g; # convenience
        $path = SHARYANTO::Module::Path::module_path(module=>$mod);
        die "Can't find module '$mod'" unless $path;
    } elsif (defined $args{file}) {
        $path = $args{file};
        (-f $path) or die "No such file '$path'\n";
    } else {
        die "Please specify file or module (-m)\n";
    }

    my $lexer = Compiler::Lexer->new($path);
    my $ct = do {
        undef $/;
        open my $fh, "<", $path or die "Can't open '$path': $!\n";
        <$fh>;
    };
    my $tokens = $lexer->tokenize($ct);
    my @res;
    for my $i (0..@$tokens-1) {
        my $t = $tokens->[$i];
        my $mod;
        if ($i < @$tokens-1 && (
            $t->{name} eq 'UseDecl' || $t->{name} eq 'RequireDecl')) {
            my $t2 = $tokens->[$i+1];
            if ($t2->{name} eq 'UsedName' || $t2->{name} eq 'RequiredName') {
                $mod = $t2->{data};
            } elsif ($t2->{name} eq 'Namespace') {
                my $j = $i+1;
                my $s = "";
                while ($t2 && $t2->{name} =~ /^Namespace(Resolver)?$/) {
                    $s .= $t2->{data};
                    $j++;
                    $t2 = $tokens->[$j];
                }
                $mod = $s;
            } else {
                next;
            }
            if ($args{detail}) {
                push @res, {
                    module=>$mod,
                    line=>$t->{line},
                    method=>$t->{name} eq 'UseDecl' ? 'use' : 'require',
                };
            } else {
                push @res, $mod;
            }
        }
    }
    \@res;
}

Perinci::CmdLine::Any->new(
    url => '/main/pluse',
)->run;

# ABSTRACT: List required modules (via use()/require()) in a Perl script (or module)
# PODNAME: pluse

__END__

=pod

=encoding UTF-8

=head1 NAME

pluse - List required modules (via use()/require()) in a Perl script (or module)

=head1 VERSION

This document describes version 0.02 of pluse (from Perl distribution App-PlUtils), released on 2014-09-17.

=head1 SYNOPSIS

 % pluse Some/script.pl
 % pluse --module Some::Module

Sample output:

 % cat 1.pl
 require A::B;
 use C;

 % pluse 1.pl
 +------+
 | A::B |
 | C    |
 +------+

 % pluse 1.pl --detail
 +------+---------+--------+
 | line | method  | module |
 | 1    | require | A::B   |
 | 2    | use     | C      |
 +------+---------+--------+

To active bash completion:

 % complete -C pluse pluse; # can be put in bash startup file e.g. .bashrc
 % pluse -m MIME/<tab>
 % pluse -m "MIME::B<tab> ; # use quote (' or ") if you want to use :: as separator

=head1 TODO

Currently very limited, only detects:

 use BARE::WORD;
 require BARE::WORD;

should perhaps be extended to detect:

 require "Foo/Bar.pm";
 load("Foo"); # Module::Load
 load_class("Foo"); # Class::Load

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/App-PlUtils>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-App-PlUtils>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-PlUtils>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by perlancar@cpan.org.

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
