|
Pod::Snippets - Extract and reformat snippets of POD so as to use them in a unit test |
_number_of_newlines_in($string)
Pod::Snippets - Extract and reformat snippets of POD so as to use them in a unit test (or other Perl code)
Version 0.12
use Pod::Snippets;
my $snips = load Pod::Snippets($file_or_handle,
-markup => "test");
my $code_snippet = $snips->named("synopsis")->as_code;
# ... Maybe borg $code_snippet with regexes or something...
my $result = eval $code_snippet; die $@ if $@;
like($result->what_happen(), qr/bomb/);
The Perl code that we want to extract snippets from might look like this:
package Zero::Wing;
=head1 NAME
Zero::Wing - For great justice!
=head1 SYNOPSIS
=for test "synopsis" begin
use Zero::Wing;
my $capitain = Zero::Wing->capitain;
=for test "synopsis" end
=cut
# ...
1;
This class is a very simple extension of the Pod::Parser manpage that extracts POD snippets from Perl code, and pretty-prints it so as to make it useable from other Perl code. As demonstrated above, Pod::Snipets is immediately useful to test-driven-development nutcases who want to put every single line of Perl code under test, including code that is in the POD (typically a SYNOPSIS section). There are other uses, such as storing a piece of information that is both human- and machine-readable (eg an XML schema) simultaneously as documentation and code.
The SYNOPSIS demonstrates how to use Pod::Snippets to grab a piece of POD and execute it with eval in the perlfunc manpage. This can readily be done using your usual unit testing methodology, without too much ajusting if any. This approach has some advantages over other code-in-POD devices such as the Pod::Tested manpage and the Test::Inline manpage:
#line if
possible, so you can single-step through your POD (yow!).
The Pod-Snippets CPAN distribution consists of a single Perl file, and has no dependencies besides what comes with a standard Perl 5.8.x. It is therefore easy to embed into your own module so that your users won't need to install Pod::Snippets by themselves before running your test suite. All that remains to do is to select the right options to pass to load as part of an appropriately named wrapper function in your test library.
Pod::Snippets only deals with verbatim portions of the POD (that
is, as per the perlpod manpage, paragraphs that start with whitespace at the
right) and custom markup starting with =for test, =begin test or
=end test; it discards the rest (block text, actual Perl code,
character markup such as B<>, =head's and so on). The keyword
``test'' in =for test and =begin test can be replaced with
whatever one wants, using the -markup argument to load.
Actually the default value is not even ``test''; nonetheless let's
assume you are using ``test'' yourself for the remainder of this
discussion. The following metadata markup is recognized:
=for test.
=for test ignore directive.
=for test "foo" begin and
=for test "foo" end, except that other POD formatters will not see
the contents of the block.
Parses the POD from $source and returns an object of class Pod::Snippets that holds the snippets found therein. $source may be the name of a file, a file descriptor (glob reference) or any object that has a getline method.
Available named options are:
#line lines in as_code. The default behavior is to use
the filename passed as the $source argument, or if it was not a
filename, use the string ``pod snippet'' instead.
=for, =begin or =end to indicate that the directive is
to be processed by Pod::Snippets (see Snippet Syntax. Default
is ``Pod::Snippets''.
$sub->($severity, $text, $file, $line);
where $severity is either ``WARNING'' or ``ERROR''. By default the standard Perl warn in the perlfunc manpage is used.
Regardless of the number of errors, the constructor tries to load the whole file; see below.
=for test "foobar" begin
my $foobar = foobar();
=head1 And now something completely different...
=for test "foobar" end
In other words, only verbatim blocks may intervene between the =for test ``foobar'' begin and =for test ``foobar'' end markups.
=for test "foobar" begin
my $foobar = foobar();
=for test "foobar" end
=for test "foobar" begin
$foobar->quux_some_more();
=for test "foobar" end
warn_ counterparts above, but cause errors instead of
warnings.
-named_snippets => "warn_bad_pairing" and
ignore the rest.
(-named_snippets => "error_overlap", -named_snippets
=> "error_impure", -named_snippets => "error_multiple",
-named_snippets => "error_bad_pairing").
Note that the correctness of the POD to be parsed is a prerequisite; in other words, Pod::Snippets won't touch the error management knobs of the underlying the Pod::Parser manpage object.
Also, note that the parser strictness options such as -named_snippets have no effect on the semantics; they merely alter its response (ignore, warning or error) to the aforementioned dubious constructs. In any case, the parser will soldier on until the end of the file regardless of the number of errors seen; however, it will disallow further processing of the snippets if there were any errors (see errors).
Same as load, but works from a Perl string instead of a file
descriptor. The named options are the same as in load(), but
consider using -filename as parse() is in no position to
guess it.
Returns the name of the file to use for #line lines in as_code.
The default behavior is to use the filename passed as the $source
argument, or if it was not a filename, use the string ``pod snippet''
instead.
Returns the number of warnings that occured during the parsing of the POD.
Returns the number of errors that occured during the parsing of the POD. If that number is non-zero, then all accessors described below will throw an exception instead of performing.
Returns the snippets in ``data'' format: that is, the return value is ragged to the left by suppressing a constant number of space characters at the beginning of each snippet. (If tabs are present in the POD, they are treated as being of infinite length; that is, the ragging algorithm does not eat them or replace them with spaces.)
A snippet is defined as a series of subsequent verbatim POD paragraphs with only Pod::Snippets markup, if anything, intervening in between. That is, as_data(), given the following POD in input:
my $a = new The::Brain;
=begin test
# Just kidding. We can't do that, it's too dangerous.
$a = new Pinky;
=end test
=for test ignore
system("/sbin/reboot");
and all of a sudden, we have:
=for test
if ($a->has_enough_cookies()) {
$a->conquer_world();
}
would return (in list context)
(<<'FIRST_SNIPPET', <<'SECOND_SNIPPET'); my $a = new The::Brain;
# Just kidding. We can't do that, it's too dangerous.
$a = new Pinky;
FIRST_SNIPPET
if ($a->has_enough_cookies()) {
$a->conquer_world();
}
SECOND_SNIPPET
Notice how the indentation is respected snippet-by-snippet; also, notice that the FIRST_SNIPPET has been padded with an appropriate number of carriage returns to replace the Pod::Snippets markup, so that the return value is line-synchronized with the original POD. However, leading and trailing whitespace is trimmed, leaving only strings that starts with a nonblank line and end with a single newline.
In scalar context, returns the blocks joined with a single newline character (``\n''), thus resulting in a single piece of text where the blocks are joined by exactly one empty line (and which as a whole is no longer line-synchronized with the source code, of course).
Returns the snippets formatted as code, that is, like as_data,
except that each block is prepended with an appropriate #line
statement that Perl can interpret to renumber lines. For instance,
these statements would cause Perl to Do The Right Thing if one
compiles the snippets as code with eval in the perlfunc manpage and then runs it
under the Perl debugger.
Returns a clone of this Pod::Snippet object, except that it only
knows about the snippet (or snippets) that are named $name. In the
most lax settings for the parser, this means: any and all snippets
where an =for test "$name" begin (or =begin test "$name") had
been open, but not yet closed with =for test "$name" end (or =end
test "$name"). Returns undef if no snippet named $name was seen at
all.
the Test::Pod::Snippets manpage
Dominique QUATRAVAUX, <domq@cpan.org>
Please report any bugs or feature requests to
bug-pod-snippet@rt.cpan.org, or through the web interface at
http://rt.cpan.org/NoAuth/ReportBug.html.
I will be notified, and then you'll automatically be notified of progress on
your bug as I make changes.
Yanick Champoux <yanick@CPAN.org> is the author of the Test::Pod::Snippets manpage which grandfathers this module.
Copyright 2007 Dominique QUATRAVAUX, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
|
Pod::Snippets - Extract and reformat snippets of POD so as to use them in a unit test |