Glory to Pod in the Highest
Glory? To Pod?
Oh, I don't know. I have really mixed feelings about Pod. It's really easy to write, most of the time, and the toolchain for it is pretty fantastic. You can convert Pod to text, man pages, HTML, LaTeX, PDF, and all kinds of other formats. Then again, there's too much vertical whitespace. Lists are a colossal pain to write. Beyond the annoyances of Pod itself, the Pod of Perl modules uploaded to the CPAN is expected to contain a bunch of boring filler that gets copied around.
A number of other documentation systems tempted me with the idea of writing less and getting information, like "this bit of documentation associates with this method," giving you things like Python's help
builtin. I set about finding a way to write a lot less Pod that would tell me a lot more about my code and look indistinguishable to consumers. There were a few stops and starts and a lot of spun-off code, and a very motivating grant from The Perl Foundation. The end result was Pod::Weaver, which is something like a templating system for Pod.
Pod Templates with Pod::Weaver
Like Email::MIME::Kit, though, Pod::Weaver doesn't just take a document and fill in strings. It takes a description of the goal output and tries to build something matching that description. For example, here's roughly the default template for Pod::Weaver:
1: | [@CorePrep] |
This describes the document to be created; every section of the configuration will try to produce a section in the output Pod, except for @CorePrep
, which is a plugin bundle, which could provide a bunch of sections or other kinds of plugins. In the case of CorePrep, we're adding plugins to ensure that we have an object tree that's something like what we expect from a Pod document, as Pod::Elemental starts with a very bare-bones structure that can be tedious to work with.
After that, we try to make sure there are NAME and VERSION sections, then we look for prelude region, and so on. The input document might look like this:
1: | package Tree::Christmas; |
If we want to include things like a name, version, license, and author in the output, we'll need to provide those. We'll do that with something like this:
1: | my $input_pod = Pod::Elemental->read_string( $the_sample_above ); |
That gets us a new Pod::Elemental::Document which, when turned into a Pod stirng, looks something like this:
1: | =head1 NAME |
Not bad! We avoid typing nearly half of the output document, by lines -- and that's only part of the benefit. If we have five modules in our distribution, all that boilerplate is added everywhere for us, so multiply that savings across all our modules. Then, if ever we want to change our license or add an author or even change the overall layout of the output document, we only need to change our configuration in one place.
If you're wondering about the ppi_document
input above, it's there because some sections can be built by analyzing the Perl content of the document, so you can automatically document things like included packages, defined subroutines, and so on. (You could also write something to compile the code and look at the symbol table or meta layer, although no one has done that yet!) Because "load a .pm file, break it into Pod and Perl, rewrite the Pod, and write it back out" is such a common pattern, there's even Pod::Elemental::PerlMunger, which takes care of everything but the "rewrite the Pod" step for you, leaving you free to focus on configuring your weaver or other rewriting tool.
That's the interface on which Dist::Zila::Plugin::PodWeaver is built. It gets all its inputs from your Dist::Zilla configuration and then rewrites all your Perl modules with Pod::Weaver. If you're using Dist::Zilla, all you need to do to get all the rewriting seen above is add the line [PodWeaver]
into your dist.ini.
Extending Pod::Weaver
Pod::Weaver tries to make it easy to add new behavior. For example, a simple plugin to add an "Acknowledgements" section is only about a dozen lines of code. A plugin to integrate Pod::Weaver with Pod::WikiDoc is only about six lines of code. This allows the transformation of the easy to type:
1: | =for wikidoc |
...into the grumble-inducing:
1: | =over 2 |
A recurring theme of this set of articles has been my hatred for needless typing and boilerplate content, and Pod::Weaver has gone a long way to letting me avoid both. Hopefully you can use it to avoid them now, too, and spend more time solving problems.
See Also
Pod::Elemental - the Pod object model on which Weaver is built
Pod::Eventual - the event-based parser behind Pod::Elemental
Dist::Zilla::Plugin::PodPurler - a pale imitation/prototype of PodWeaver
Pod::Elemental::PerlMunger - for writing your own Pod-in-Perl rewriter
Pod::WikiDoc - David Golden's excellent wiki-like Pod dialect
Pod::Weaver::PluginBundle::RJBS - how I weave my Pod
what is pod weaver, Part 1, Part 2 - blog post about Pod::Weaver