Many thanks!
I think this is pretty much what I need. I also need the fully qualified subroutine name e.g. main::foo or File::Basename::dirname, but that is easily added. To wit:
#!/usr/bin/perl -w use PPI; use strict; use Cwd 'abs_path'; my $filename = shift || die "Give me a doc!"; my $doc = PPI::Document->new($filename); my $subs = $doc->find("PPI::Statement::Sub"); my $packages = $doc->find('PPI::Statement::Package'); my @pkg_info = (['main', 0]); if ($packages ne "") { for my $pkg ( @$packages ) { my $start = $pkg->line_number; my $pkg_name = $pkg->{children}[2]; push @pkg_info, [$pkg_name, $start]; } } sub enclosing_pkg($$) { my ($start, $end) = @_; my $pkg_name = 'main'; foreach my $pkg_info (@pkg_info) { if ($pkg_info->[1] > $start) { # fn start and end can't span a "package" statement. die "Bolixed package parsing" if $pkg_info->[1] < $end; last; } $pkg_name = $pkg_info->[0]; } $pkg_name; } print abs_path($filename), ":", $/; for my $fn ( @$subs ) { my $start = $fn->line_number; my $lines = $fn =~ y/\n//; my $end = $start + $lines; my $pkg_name = enclosing_pkg($start, $end); printf "\t%s::%s: %d-%d\n", $pkg_name, $fn->name, $start, $end; }
The only remaining piece is getting a list of files that need to get loaded, but I think I can get that via %INC.
Finally to the question of is this perfect, or is there's a better way? Possibly.
But I'd like to start out with something that is pretty good as this is, and then improve or even rewrite as we understand better ways. In my experience, if you wait for the perfect solution, you'll never get anywhere.
In reply to Re^2: How to get line ranges of subroutines from Perl source code
by rockyb
in thread How to get line ranges of subroutines from Perl source code
by rockyb
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |