perlmeditation
simonflk
<p>
I'd be grateful for some feedback on the naming of two modules that my
<tt>$ORGANISATION</tt> is planning to release to the CPAN. I realise that
we need to change both names - there is already an <tt>assertions.pm</tt>
and neither module is named suitably for CPAN.
</p>
<h3>Tracing.pm</h3>
<p>
A logging/debugging library. Tracing can output to a number of targets:
<ul>
<li><tt>print</tt> to the currently selected filehandle</li>
<li><tt>print</tt> to a user-supplied filehandle</li>
<li><tt>warn</tt> to STDERR </li>
<li>collect trace output in a variable</li>
<li>log the trace output to a file</li>
<li>write to the <tt>syslog(3)</tt></li>
<li>pass trace output to a custom logging function</li>
</ul>
... and in a number of modes: verbose & debug (varying levels of
contextual information) and of course, plain mode. There are other logging
modules on CPAN, e.g.: [cpan://Log::Log4Perl] and [cpan://Log::Agent].
<tt>Tracing</tt>'s usage and interface is most similar to
[cpan://Log::TraceMessages], although <tt>Tracing</tt> offers more
features. It's probably best described by example:
</p>
<readmore>
<code>
#!/usr/bin/perl -w
use strict;
use Tracing 'print';
TRACE("-------- Starting archiver ---------");
TRACEF("We are going to try to archive %d items", scalar @ARGV);
DUMP("List of things to archive", \@ARGV);
archive_em($_) foreach(@ARGV);
sub archive_em {
TRACE_HERE();
my $thing = shift;
unless ($thing =~ /^([\w.\-/]+)$/) {
warn "bad chars in: $thing";
return;
}
rename $thing, $thing.".archive" or warn "Couldn't archive $thing: $!";
TRACE("Tried to archive $thing");
}
</code>
<p>
In this example, Tracing is imported in print mode, so arguments to
<tt>TRACE</tt> will be printed to the currently selected filehandle.
<tt>TRACEF</tt> is the <tt>printf</tt> equivalent of <tt>TRACE</tt>.
<tt>TRACE_HERE</tt> traces contextual information such as filename,
line number, subroutine name, and the current contents of <tt>@_</tt>.
And <tt>DUMP</tt> uses Data::Dumper where available to trace a dump of
a data structure.
</p>
<p>
You can write modules that cooperate with <tt>Tracing</tt> by defining
empty <tt>TRACE</tt> (and optionally, <tt>TRACEF</tt>, <tt>TRACE_HERE</tt>
and <tt>DUMP</tt>) stubs. For example:
</p>
<code>
package MyModule;
sub my_routine {
TRACE("hello");
}
sub my_other_routine {
TRACE_HERE();
}
#Stubs for Tracing
sub TRACE {}
sub TRACE_HERE {}
</code>
<p>
In your main script, you might do something like:
</p>
<code>
use MyModule;
use Tracing;
deep_import Tracing log => '/var/log/myapp.log';
MyModule::my_routine();
MyModule::my_other_routine();
</code>
<p>
<tt>deep_import</tt> searches the symbol table for packages that have a
<tt>TRACE</tt> subroutine defined and installs itself by performing an
import as if called from that package. <tt>deep_import</tt> accepts
additional parameters that give you more control over which packages to
export to, and which to exclude.
</p>
</readmore>
<p>
Possible names: Log::Trace, Debug::Tracing, Devel::Tracing
</p>
<p>
<b>Note: </b> Tracing also supports logging levels and tracing the
execution path of code.
</p>
<h3>Assertions.pm</h3>
<p>
Assertions and testing functions.
<blockquote><i>
An assertion is a boolean expression at a specific point in a program
which will be true unless there is a bug in the program. An assertion
could simply be a comment used by the programmer to think about how the
code works. Or an assertion could document a constraint on the
system. (See also: ExceptionsAsConstraints) However, it is often
possible to actually compile the assertion to code and let it be
executed in context to see if the statment it makes really does
hold. When programmers talk about assertions they usually mean this
kind of executed assertion.
</i></blockquote>
-- [http://c2.com/cgi/wiki?WhatAreAssertions]
</p>
<p>
<tt>Assertions</tt> also operates in a number of modes: <tt>die</tt>,
<tt>warn</tt>, <tt>silent</tt> and <tt>test</tt>. If an assertion fails, it
will die, warn or do nothing. In <tt>test</tt> mode, it will print output
suitable for capture by Test::Harness.
</p>
<p>
Similar modules on CPAN include [cpan://Carp::Assert] and
[cpan://Test::More].
</p>
<p>
Here's a couple of contrived examples:
</p>
<readmore>
<code>
package MyModule;
use Assertions 'die';
sub format_cols {
my ($data, $columns, $width) = @_;
ASSERT(defined ($columns) && $columns > 0, "columns is positive");
ASSERT(defined ($width) && $width > 0);
my $col_width = $width / $columns;
for (1 .. $columns) {
# ...
}
}
</code>
<p>
The first argument to <tt>ASSERT</tt> is a boolean expression. It also
takes an optional comment that will be reported if the assertion fails.
The next example uses <tt>Assertions</tt> in unit test mode, and
demonstrates some of the other helper functions that are available:
</p>
<code>
use Assertions 'test';
plan tests;
ASSERT(1 == 1, "an example test");
my %observed = parse_data("a1b4c6");
ASSERT(EQUAL(\%observed, {a => 1, b => 4, c => 6}), 'parse_data, parsed ok');
my $returned = munge_data(\%observed);
ASSERT(EQUALS_FILE($returned, 'expected.txt'), 'munge_data is good at munging');
ASSERT(DIED(sub { $object_to_test->method(@bad_inputs) }));
</code>
</readmore>
<p>
Possible names: Debug::Assertions, Test::Assertions, Devel::Assertions,
</p>
<p>
I'd appreciate any feedback on the module names, and I should be able to
post the POD if required. Thanks
</p>
<div class="pmsig"><div class="pmsig-153880">
<p>-- simonflk</p>
</div></div>