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

Hi All,

I have two questions. (sorry if the question title doesn't describe this well... I have no clue what this could be called)

I usually write cgi applications, using CGI::Application and CGI::Template. To help me with the debuging I save various tidbits to a $debug var and then before outputting in the end, I add the debug var to the page.
sub do_some_stuff { $debug .= qq(<h5 style="color:#c33;">SUB: do_some_stuff</h5><div sty +le="margin-left:20px;">); my $abc = qq(The foo bar boogie); (my $xyz = $abc) =~ s!foo!bar!; $xyz = &do_something_else($xyz); #pretend &do_some_other_stuff is ba +sically the same as &do_some_stuff $debug .= qq(XYZ: $xyz); $debug .= qq(</div><h5 style="color:#c33;">ENDSUB: do_some_stuff</h5 +>); return($xyz); } my $output = $template->output; $output .= qq(--Debug Info-- <pre>$debug</pre>); return($output);
In the end, I get a nice little summary of every sub routine run, with any sub routine called from that subroutine nested, and any little notes I wanted to see. so it would look like
SUB: do_some_stuff
	XYZ: The bar bar boogie
	SUB: do_some_other_stuff
		NOTE: did some other stuff
	ENDSUB: do_some_other_stuff 
ENDSUB: do_some_stuff
I have two questions.

1) I haven't seem any module that I can use to get the same or similar functionality, but if I am missing something, please let me know.

2) If not, I don't like having to add
$debug .= qq(<h5 style="color:#c33;">SUB: do_some_stuff</h5><div style="margin-left:20px;">);
and
$debug .= qq(</div><h5 style="color:#c33;">ENDSUB: do_some_stuff</h5>);
before and after every sub routine. I dont suppose there is a way I can make a subroutine that will automatically be run in the beginning of every subroutine and before it returns without explicitly calling it each time?

I'm not sure if I have heard of anything like that before, so I am not really expecting that it can be done, but even so, any ideas about a better way to do something close would be helpful.

Replies are listed 'Best First'.
Re: modifying sub routine behaviour
by zengargoyle (Deacon) on Mar 12, 2003 at 09:23 UTC
      Great! That was exactly what I was looking for! Thanks.
Re: modifying sub routine behaviour
by Corion (Patriarch) on Mar 12, 2003 at 09:34 UTC

    As long as you are not doing anything weird/tricky with subroutine references, Hook::LexWrap might be something to give you a start. Hook::LexWrap allows you to install (and remove) wrappers around Perl subroutines (much like the .wrap method on subroutines in Perl 6). So now all you need is a list of your function names within your module - this is possible by looking through the namespace of that module :

    use My::Module; print join ",", sort keys %{My::Module::};

    The special, unnamed hash %My::Module:: (yes, the last two colons are part of the name) contains all the global (and thus still wrappable) names. Now you still have to find out which of these are subroutines and which aren't (*{My::Module::varname}{CODE} is defined) and that should be it. There are some snippets here, that do exactly that, but I couldn't find them quickly ...

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: modifying sub routine behaviour
by robartes (Priest) on Mar 12, 2003 at 09:38 UTC
    Here's an implementation based on AUTOLOAD:
    use strict; use vars q{$AUTOLOAD}; dostuff("One"); dostuff2("Two"); sub AUTOLOAD { no strict "refs"; print "Entering sub $AUTOLOAD.\n"; my $sub=join "::_", split /::/,$AUTOLOAD; &$sub(@_); print "Exiting sub $AUTOLOAD.\n"; } sub _dostuff { print "We're in dostuff: @_.\n"; } sub _dostuff2 { print "We're in dostuff2: @_.\n"; } __END__ Entering sub main::dostuff. We're in dostuff: One. Exiting sub main::dostuff. Entering sub main::dostuff2. We're in dostuff2: Two. Exiting sub main::dostuff2.
    You prepend an underscore to your actual subroutine names, call them by their 'normal' names and have AUTOLOAD add the diagnostic prints and call the underscored versions.

    Note that, although this implementation works, it is probably not the most efficient, as the entire AUTOLOAD system is expensive. But it's the best I could come up with for now. Other people will probably come up with better ways (and probably have in the time it took me to type this :) ).

    CU
    Robartes-

Re: modifying sub routine behaviour
by adrianh (Chancellor) on Mar 12, 2003 at 09:23 UTC
AOP?
by zby (Vicar) on Mar 12, 2003 at 09:18 UTC
    "make a subroutine that will automatically be run in the beginning of every subroutine and before it returns without explicitly calling it each time" looks like some Aspect Oriented Programming.