Taming Pod::Weaver, part 2
Taming Pod::Weaver, part 2
In our last episode, we began our journey into the wonderful and only slightly
scary world of Pod::Weaver. By the end of the blog entry, we victorously
managed to, hum, mimic perldoc -u
. Not terribly impressive, maybe, but
a necessary baseline for the upcoming niftiness.
Niftiness that begins with today’s installment, as we are going to take a closer look at all the Pod::Weaver gnomes and fairies that we can enlist to help create our POD.
The Weaver’s Bestiary: Plugins, Sections and Bundles
All actions performed to the POD are gone via plugin modules that
are (typically) invoked via the weaver.ini
configuration file.
While the extent of what a plugin module will do is ultimately determined by the role it implements (more on that in a future blog entry), they are typically classified by their functionality: section modules insert pieces of documentation in the generated POD, plugin modules transforms the input POD, and pluginbundle modules are handy aggregates of individual plugins.
All three kinds of module are invoked similarily in the configuration file. For example, the configuration
[@YANICK]
[-NormalizeCapitalization]
skip_headers = head2, head3
[Generic / DESCRIPTION ]
has the bunle YANICK, the straight plugin NormalizeCapitalization and the section plugin Generic. Each of them can be given parameters (NormalizeCapitalization has the parameter skip_headers), as well as a name (in the example, DESCRIPTION for Generic). The name, as we will soon see, is typically used as a shortcut for one of the parameters.
Section Plugins
The most common plugins you’ll likely use, they are the ones
that insert pieces of documentation in the generated POD.
They exist under the namespace Pod::Weaver::Section::*
.
Pod::Weaver::Section::Generic
The most basic of the bunch is undubitously Pod::Weaver::Section::Generic
,
which takes the section of the original POD corresponding to its name and drops it
in the generated POD. For example, using the configuration
[Generic / SYNOPSIS]
required = 1
[Generic / DESCRIPTION]
required = 1
[Generic / BUGS]
[Generic / SEE ALSO]
and the original POD
=head1 SEE ALSO
* L<Pod::Weaver>
=head1 DESCRIPTION
Yadah yadah
=head1 SYNOPSIS
...
=head1 IRRELEVANT
This section is not that important, after all.
we would get
Err.. Nothing?
… I’ll spare you the details of the head-scratching and sleuthing that went on to discover it, but as it turns out two base plugins have to be included in the configuration if we want anything to happen. I’ll explain in more details in the next section, but for the time being just trust me and add two lines to the configuration:
[-EnsurePod5]
[-H1Nester]
[Generic / SYNOPSIS]
required = 1
[Generic / DESCRIPTION]
required = 1
[Generic / BUGS]
[Generic / SEE ALSO]
and then, tadah:
=pod
=head1 SYNOPSIS
...
=head1 DESCRIPTION
Yadah yadah
=head1 SEE ALSO
* L<Pod::Weaver>
=cut
The sections are generated in the order that we picked them. The IRRELEVANT section, as it has not been explicitly picked, is not there. On the flip side, there is no BUGS section in the original POD, so nothing appears in the generated POD. If we wanted that section to be mandatory and have the weaver to throw a fit if it’s not present, we could set its required parameter to true, like we did for the SYNOPSIS and DESCRIPTION sections. the document without it.
Of course, this is only the beginning. Some of the section plugins will inject boilerplate text (Pod::Weaver::Section::Bugs, Pod::Weaver::Section::License), and yet others, like Pod::Weaver::Section::Collect, will either introspect the code or use custom pod commands to generate their given sections.
Straight-forward plugins
Those are the plugins that live under the namespace Pod::Weaver::Plugin::*
,
and are prefixed by a minus sign in the configuration file. They
typically will inspect or groom the input POD.
For example,
Pod::Weaver::Plugin::EnsureUniqueSections is doing exactly what it says on
the can, it will issue warnings if duplicate sections are found in the
generated POD, and Pod::Weaver::Plugin::Encoding will add an
explicit ’=encoding
’
command to the generated POD if none is already present.
As mentioned in the previous section, there is also the two core
plugins
Pod::Weaver::Plugin::EnsurePod5
and
Pod::Weaver::Plugin::H1Nester
that should always be invoked in the configuration. The first one sanitizes the
input POD, whereas the second change the internal Pod::Elemental representation of the POD
DOM such that its elements are all contained by the ’=head1
’ sections of the
document. Yes, this is slightly confusing. It’s all related to the
Pod::Elemental guts of the underlying POD DOM, which should be transparent to
Pod::Weaver end-users, and should be automatically dealt with
behind the scene. But, for the time being, it is what it is,
so just take my word for it: add the two magic lines
[-EnsurePod5]
[-H1Nester]
to all your weaver.ini
files, and happiness will ensue.
Plugin Bundles
And then there are plugin bundles, living under the namespace
Pod::Weaver::PluginBundle::*
, and prefixed by an ’@’ in the configuration.
Just like their Dist::Zilla cousins, they are a handy way to aggregate
many plugins together and turn a 30-section configuration file into:
[@YANICK]
The Other Plugins
Did I say that there was three kinds of plugins?
I lied.
It’s also possible to user plugins that live outside of the three namespaces mentioned above, by prefixing their names with an equal sign in the configuration, like so:
[=YANICK::Pod::Weaver::Plugins::Foo]
Of course, for clarity’s sake it’s a better idea to stick to the official namespaces. But still, it’s nice to know that we have this extra-flexibility, in case a special case would ever pop up.
In Out Next Episode…
Now that we can can recognize our beasties from the outside, it’s time to see what makes them tick from the inside. Next time, we build ourselves a nice, shiny new Section plugin.