Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Re: Splitting program into modules

by harangzsolt33 (Chaplain)
on Nov 12, 2018 at 23:52 UTC ( [id://1225672]=note: print w/replies, xml ) Need Help??


in reply to Splitting program into modules

Is there a program that reads a Perl source code and prints out the names of all the subs declared in that file?

Perhaps an even more useful program might also show the dependencies, so at a quick glance you could see all the subs and which one depends on which one. If they are called sub a3e {} then, of course, that won't reveal much. But if they are called "calc_offset" or "getTimeZone" or something that is self-explanatory, then such a program would help a lot in breaking down this huge code into comprehensible chunks.

Is there such a program?

Replies are listed 'Best First'.
Re^2: Splitting program into modules
by stevieb (Canon) on Nov 13, 2018 at 00:45 UTC

    My Devel::Examine::Subs can list subs within files.

    Single file example:

    use warnings; use strict; use Devel::Examine::Subs; my $des = Devel::Examine::Subs->new(file => 'lib/Devel/Examine/Subs.pm +'); my $subs = $des->all; print "$_\n" for @$subs;

    Output:

    BEGIN new all has missing lines module objects search_replace replace inject_after inject remove order backup add_functionality engines pre_procs post_procs run valid_params _cache _cache_enabled _cache_safe _clean_config _clean_core_config _config _file _params _read_file _run_directory _run_end _write_file _core _pre_proc _proc _post_proc _engine _pod

    You can also do entire directory structures:

    use warnings; use strict; use Devel::Examine::Subs; my $des = Devel::Examine::Subs->new(file => '.'); my $data = $des->all; for my $file (keys %$data){ print "$file:\n"; for my $sub (@{ $data->{$file} }){ print "\t$sub\n"; } }

    Snipped example output:

    t/test/files/sample.pm: one one_inner one_inner_two two three four function five six seven eight examples/write_new_engine.pl: dumps lib/Devel/Examine/Subs/Sub.pm: BEGIN new name start end line_count lines code lib/Devel/Examine/Subs/Preprocessor.pm: BEGIN new _dt exists module inject replace remove _vim_placeholder

    The software does a ton of useful things, but these are examples of the most basic functionality. It does not know how to see sub dependencies of other subs. However, I do have another software that does, however, it is intrusive (it actually writes into the Perl files, and you have to run the software to get usable trace information (ie. if you don't call all scenarios, it may not find all flows). I don't have the time at the moment to write a proper scenario for that, but have a look at Devel::Trace::Subs if you're interested. If you don't come up with anything else by morning, I'll create a good example.

      So I've put together a very basic display of how the Devel::Trace::Subs works. Again, it's intrusive; it actually writes into the files you want to capture tracing info from (I wrote this software that another piece of software required, primarily out of sheer curiosity).

      Here's the original Perl file we're working with (./test.pl):

      use warnings; use strict; three(5); sub three { return two(shift); } sub two { return one(_helper(shift)); } sub one { my $num = calc(shift); display($num); } sub calc { my $num = shift; return $num ** 3; } sub display { my $num = shift; print "$num\n"; } sub _helper { my $num = shift; return ++$num; }

      When run, it produces this output:

      216

      Very basic. Now, install Devel::Trace::Subs, and from the command line, tell it to become traceable:

      perl -MDevel::Trace::Subs=install_trace -e 'install_trace(file => "test.pl")'

      ...now the test.pl file looks like this:

      use warnings; use Devel::Trace::Subs qw(trace trace_dump); # injected by Devel::Trac +e::Subs use strict; three(5); sub three { trace() if $ENV{DTS_ENABLE}; # injected by Devel::Trace::Subs return two(shift); } sub two { trace() if $ENV{DTS_ENABLE}; # injected by Devel::Trace::Subs return one(_helper(shift)); } sub one { trace() if $ENV{DTS_ENABLE}; # injected by Devel::Trace::Subs my $num = calc(shift); display($num); } sub calc { trace() if $ENV{DTS_ENABLE}; # injected by Devel::Trace::Subs my $num = shift; return $num ** 3; } sub display { trace() if $ENV{DTS_ENABLE}; # injected by Devel::Trace::Subs my $num = shift; print "$num\n"; } sub _helper { trace() if $ENV{DTS_ENABLE}; # injected by Devel::Trace::Subs my $num = shift; return ++$num; }

      I'd like to point out that the design for this software was to be used within modules not normal scripts, but I digress. In order to get the output from the tracing, you have to add a couple of things to your calling script (in this case, it's the original script itself). We'll pretend we're calling modules infected with the trace software here. Add the trace enabling flag, then after all of your calls have been made you want to get the trace info from, call the dump_trace() function::wq

      $ENV{DTS_ENABLE} = 1; three(5); # this is the original call stack you're running trace_dump();

      Now, you get the original output, but you also get the code flow and stack trace information:

      216 Code flow: 1: main::three 2: main::two 3: main::_helper 4: main::one 5: main::calc 6: main::display Stack trace: in: main::three sub: - file: test.pl line: 7 package: main in: main::two sub: main::three file: test.pl line: 13 package: main in: main::_helper sub: main::two file: test.pl line: 17 package: main in: main::one sub: main::two file: test.pl line: 17 package: main in: main::calc sub: main::one file: test.pl line: 21 package: main in: main::display sub: main::one file: test.pl line: 22 package: main

      You can opt via parameters to trace_dump to display just the code flow or the stack trace or both (as is the default as shown above), in text or HTML output formats.

      This is a *very* basic example of how I've used this software. Again, we're using it in a single file here. Normally I'd have a test script using external modules, so the command to return your original code is this:

      perl -MDevel::Trace::Subs=remove_trace -e 'remove_trace(file => "test.pl")'

      ...which returns the script back to default, except for the manual lines (which wouldn't normally be in an original .pl file). Delete these lines manually:

      $ENV{DTS_ENABLE} = 1; trace_dump();

      I'll try to put together a much better example of how I really use it in the coming days.

        > Again, it's intrusive;

        I wonder why you prefer it that way, there are at least two alternatives

        • running under the debugger and activating the trace option
        • inspecting the stash of the included packages and dynamically monkey patching the subs with tracing wrappers.

        Am I missing something?

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      > It does not know how to see sub dependencies of other subs.

      From what I can see it also doesn't show dependencies from "outer" variables (globals or closure), right?

      update

      which is relevant in this thread

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re^2: Splitting program into modules
by Anonymous Monk on Nov 14, 2018 at 06:24 UTC
    Is there a program that reads a Perl source code and prints out the names of all the subs declared in that file?

    Devel::NYTProf generates an HTML report with sortable lists of subs that you can click to view the code with full timing information:

    perl -d:NYTProf script.or.module.pl; nytprofhtml --open

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1225672]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (3)
As of 2024-04-19 17:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found