exodist has asked for the wisdom of the Perl Monks concerning the following question:

How would I obtain a list of subs defined ina specific file?

Lets say I have scrip.pl, inside it has the line:
require 'file.pm';
file.pm basically has a lot of sub declarations.

I need a list of all the subs brought in by the file, not all the subs in the current or main package, and file.pm does not conatin any package declarations.

I know I can read in the file and use a regex like '/sub (\w)/g' obviously it would need to be a bit more, but frankly if I can do this w/o parsing perl myself it would be better.

--------------------------------------

I would rather take 30 minutes to re-invent the wheel then take 30 days to learn how to use someone else's. Before pestering me about my re-invention prepare to defend yourself with a way of learning how to use the wheel in less time than it takes for me to make one, one that I might add is specialized to my specific task!

Replies are listed 'Best First'.
Re: List of subs defined by a file?
by zentara (Cardinal) on Dec 20, 2008 at 20:28 UTC
Re: List of subs defined by a file?
by almut (Canon) on Dec 20, 2008 at 22:13 UTC
    I need a list of all the subs brought in by the file, not all the subs in the current or main package

    You could compare the list of functions before and after requiring the file:

    ### file.pm sub funcC { } sub funcD { } sub funcE { } 1; ### main script #!/usr/bin/perl use strict; use warnings; use Devel::Symdump; sub funcA { } sub funcB { } sub get_functions { return Devel::Symdump->functions("main"); } my %before = map {$_ => 1} get_functions(); require 'file.pm'; print "$_\n" for sort grep !$before{$_}, get_functions(); __END__ main::funcC main::funcD main::funcE
Re: List of subs defined by a file?
by shmem (Chancellor) on Dec 20, 2008 at 23:30 UTC
    I need a list of all the subs brought in by the file, not all the subs in the current or main package, and file.pm does not conatin any package declarations.

    You can require that file in an ad-hoc package and inspect its symbol table:

    #!/usr/bin/perl # file.pm use strict; our ($baz, $quux); sub blorf; $quux = sub { 3 }; sub foo { 1 } sub bar { 2 }
    #!/usr/bin/perl # main script use strict; { package Query; require "file.pm"; } print "in package ", __PACKAGE__, $/; for my $sym ( keys %Query:: ) { no strict 'refs'; print "file.pm: $sym\n" if defined *{'Query::'.$sym}{CODE}; print "file.pm: subref \$$sym\n" if ref ${*{'Query::'.$sym}{SCALAR}} + eq 'CODE'; }

    Output:

    in package main file.pm: sub bar file.pm: subref $quux file.pm: sub blorf file.pm: sub foo
      I tried to generalize your script by substituting $file for file.pm, and when I ran it on a regular script it runs the script in require (so that would need to be suppressed somehow) and when I ran it on a perl module like Tie::Scalar (path supplied by perldoc -l) it gave me nothing, since the module doesn't export globals.

      My code, for what it's worth:

      #!/usr/bin/perl # listsubs - display list of subroutines in a package or script use strict; my $file=shift @ARGV; { package Query; require $file; } for my $sym ( keys %Query:: ) { no strict 'refs'; print "Query::$sym\n" if defined *{'Query::'.$sym}{CODE}; print "$file: subref \$$sym\n" if ref ${*{'Query::'.$sym}{SCALAR}} e +q 'CODE'; }

      I think the right answer to this is to simply grep the file for /^sub/, unless you're trying to get a list of dynamically generated coderefs??

      SSF

        and when I ran it on a perl module like Tie::Scalar (path supplied by perldoc -l) it gave me nothing, since the module doesn't export globals.

        Well, the script I provided is for the case you mentioned - just a file with subs in it, without any package declaration whatsoever (and inspecting the symbol table hasn't anything to do with what is exported - the ad-hoc package Query doen't export anything, either). Now, Tie::Scalar has a package declaration - package Tie::Scalar; - and the script isn't suitable for that case. You would have to inspect %Tie::Scalar. I'd reach for something else for the general case, maybe even PPI.

        I think the right answer to this is to simply grep the file for /^sub/, unless you're trying to get a list of dynamically generated coderefs??

        That heavily depends on what is "right" for you and the task at hand. More general would be grepping for /^\s*sub/. But that won't give you not only dynamically generated subrefs, but also typeglob-bound code generated at module use, such as generated by Class::Accessor:

        package Foo; BEGIN { our ($VERSION, @ISA, @METHODS); @METHODS = qw(foo bar quux); for my $field (@METHODS) { *{__PACKAGE__.'::'.$field} = sub { my $self = shift @_; if (@_) { return $self->set($field, @_); } else { return $self->get($field); } }; } for (qw(set get)) { *{__PACKAGE__.'::'.$_} = sub { my $self = shift @_; if (@_ == 1) { return $$self{$_[0]}; } elsif (@_ > 1) { return $self->{$_[0]} = $_[1]; } else { $self->_croak('Wrong number of arguments received'); } }; } }
Re: List of subs defined by a file?
by graff (Chancellor) on Dec 21, 2008 at 03:25 UTC