NAME

Devel::Messenger - Let Your Code Talk to You

SYNOPSIS

use Devel::Messenger qw{note};

# set up localized subroutine
local *note = Devel::Messenger::note {
    output     => 'print',
    level      => 2,
    pkgname    => 1,
    linenumber => 1,
    wrap       => ["<!--", "-->\n"],
};

# print a note
note "This is a sample note\n";

# print a multipart note
note "This is line two. ";
note "continue", "This is still line two.\n";

# print if 'level' is high enough
note \2, "This is debug level two\n";

DESCRIPTION

Do you want your program to tell you what it is doing? Send this messenger into the abyss of your code to bring back to you all the pertinent information you want.

First, set notes in your code, in-line comments that start with note instead of #.

# this is an in-line comment (it is boring)
note "this is a note (things start getting exciting now)\n";

To keep your program from giving you terrible errors about note not being defined, give it something to do.

use subs qw{note};
sub note {}

Or you could import the slightly more powerful note subroutine defined in Devel::Messenger.

use Devel::Messenger qw{note};

By itself, note does not do anything. Right now, all it is doing is making sure Perl doesn't give you an error message and die.

So how do you make Devel::Messenger go and activate these notes?

Specify What You Want Your Messenger to Do

Devel::Messenger wants to help you and your code talk to each other. It will act as a messenger between you both.

First, you tell Devel::Messenger which notes to talk to, and how you want it to return messages to you. Then, it goes off and starts negotiating with your code.

Use Devel::Messenger's own note subroutine to specify your instructions.

local *note = Devel::Messenger::note \%instructions;

Your instructions must be in the form of a HASH reference for Devel::Messenger to understand you. You may wish to use an anonymous HASH reference.

local *note = Devel::Messenger::note {
    output => 'print',
    level  => 2,
};

Here, we have told our messenger to print any notes which are specified as level one or level two, which appear in the current package. When you run your code, Devel::Messenger will look for notes that match your instructions. Any notes that match those criteria will be printed via the Perl function print.

You may also request Devel::Messenger to look for notes in other packages.

local *Other::Module::note = Devel::Messenger::note {
    output => 'print',
    level  => 2,
};

If you are going to search for notes in multiple packages, it might be easier to capture the instructions in a SCALAR, then use the SCALAR in several places.

my $note = Devel::Messenger::note {
    output => 'print',
    level  => 2,
};

local *note = $note;
local *Other::Module::note = $note;

You may have noticed that I have been using the Perl function local in all my GLOB assignments. This is not necessary. In fact, it can be downright annoying at times. Do it anyway.

If you are using the Perl module warnings, or are running Perl with the -w switch, every time you redefine a subroutine, a warning is generated. Using local avoids these errors.

If you are running any of your code under mod_perl, having a globally assigned subroutine for debugging can cause other mod_perl copies of your code to also be sending you debugging information. That gets nasty. Using local avoids this problem.

However, when you use local, you must be careful that your note definition stays in scope for as long as you wish it to. Otherwise, Devel::Messenger will forget what it is doing and go back to sleep. In object-oriented programming, you may wish to store your instructions in your object.

my $self = bless {};
$self->{note} = Devel::Messenger::note {
    output => 'print',
    level  => 2,
};
$self->{note}->("This is my note\n");
local *note = $self->{note};
note "This is also my note\n";

Nitty-Gritty

Your instructions to Devel::Messenger::note must be in a HASH reference. The keys of that HASH instruct Devel::Messenger to do different things.

global

If you want notes from all the modules you are using, and you are not worried about global subroutine definitions or "subroutine redefined" warnings, you may wish to specify that you want to search for all notes.

note { global => 1 };

This will search %INC and replace any defined note subroutine with the new definition. If you have other subroutines named note, they will be overridden.

level

Set how much debugging you want. The bigger the number, the more verbose (except zero, which is unlimited).

A note can specify what level it is.

note "This is level one\n";
note \1, "This is also level one\n";
note \2, "This is level two\n";
note \3, "This is level three\n";

By setting the level you want, Devel::Messenger will know to ignore notes with a higher level than you specified.

linenumber

Sometimes it is useful to know where a note came from. This setting will prepend the linenumber to the messages Devel::Messenger finds for you.

See also pkgname.

output

If you do not tell Devel::Messenger what to do with your messages, it will just ignore them. You can specify where to send them by setting this instruction.

There are several ways Devel::Messenger can try to send you messages. These are described below:

file

Internal use only.

handle

Internal use only.

none

Abandons your note.

print

Sends your note to the perl subroutine 'print'.

return

Returns your note to you (you will have to grab it).

local *note = Devel::Messenger::note { output =>'return' };
$text = note "This is my note\n";
trap

Traps your notes until you set your output to something else, at which time the trapped notes are sent to the newly designated output. Sending to return will abandon any trapped notes.

local *note = Devel::Messenger::note { output => 'trap' };
note "This note is trapped for a while\n";
local *note = note { output => 'print' };

Notice that I did not send instructions to Devel::Messenger when I was finished trapping notes. Any note subroutine created by Devel::Messenger knows how to take new instructions. In this case, the trapped notes will be forgotten unless you give new instructions to the same subroutine that trapped the notes originally.

warn

Sends your note to the perl subroutine 'warn'.

a FILEHANDLE

Prints your note to a filehandle.

open FILE, '>file.txt' or die $!;
local *note = Devel::Messenger::note { output => \*FILE };
note "This is my note\n";
close FILE;
a file name

Appends each note to a file.

local *note = Devel::Messenger::note {output =>'file.txt'};
note "This is my note\n";

Any string specified as a value for output, which is not listed above, is interpretted as a file name. A warning is issued if the file cannot be opened for appending.

pkgname

If you want to know from which package a note is coming, you can have Devel::Messenger prepend the package name to each message. If the note is coming from package "main" (the default package), the filename shall be prepended instead.

If this is not enough information, you may also want to ask for a linenumber to be provided.

quiet

When you instruct Devel::Messenger::note, it tries to send you a message telling you which version of Devel::Messenger you are using. You may not wish to fill up your error log, or other files, with this version information. In this case, you should tell Devel::Messenger to keep quiet about what version it is.

note { quiet => 1 };
wrap

Devel::Messenger likes to give you messages how you like them. With this option, you can specify markup you wish to have wrapped around each note. Accepts an ARRAY reference or a string.

local *note = Devel::Messenger::note { wrap => ["<!--", "-->\n"] };
note "This is an HTML comment\n";
# <!--This is an HTML comment-->\n

local *note = Devel::Messenger::note { wrap => '###' };
note "help!";
# ###help!###

If the second part of the wrapping text ends in a newline (\n), the note is chomped before being wrapped.

Common Debug Levels

As explained above, notes can specify what level they are. The level could theoretically be from one all the way up to your integer limit.

However, levels could become almost meaningless if we allowed so many different levels.

My standard levels are:

  1. Minimal information about what the program is doing.

  2. Database interaction: connections, queries, number of records returned, et cetera.

  3. In depth information about what the program is doing.

  4. In depth information about database interaction.

  5. In depth information about formatting.

  6. In depth information about conversions.

  7. In depth information about everything else.

AUTHOR

Nathan Gray - kolibrie@southernvirginia.edu

COPYRIGHT

Devel::Messenger is Copyright (c) 2001 Nathan Gray. All rights reserved.

You may distribute under the terms of either the GNU General Public License, or the Perl Artistic License.