Day 10 – Perl 6 Pod

来源:互联网 时间:2015-12-10

Whenever you write code, you also write documentation, right? Wait, don’t answer that! Let me just pretend that you said “yes”.

As with Perl 5, Perl 6 has a built-in documentation format called Pod. In Perl 5, POD was short for “Plain Ol’ Documentation”, but in Perl 6 we just call it Pod and there’s no acronym. One of the great things about Pod in Perl 6 is that the compiler parses Pod for you. The resulting structure is essentially a tree (really, an Array of trees).

Let’s take a look at a few examples …

use v6;=begin pod=head1 NAMEexample1.p6 - It's a script to show you how Pod works in Perl 6!=end podsub MAIN { say $=pod.WHAT; say $=pod[0].WHAT;}

When I run this script I get:

$ perl6 ./bin/example1.p6 (Array)(Named)

The $=podvariable is a reference to the parsed Pod from the current file.

From the code above we can see that the $=podvariable contains an Array. Each element of that array is a Pod node of some sort, and those nodes in turn will usually contain more Pod nodes, and so on. Essentially, Pod is parsed into a tree that you can recursively descend and examine.

The $=podvariable is an array is because you can have several distinct chunks of Pod in a single file …

use v6;=begin pod=head1 NAMEexample2.p6 - It's a script to show you how Pod works in Perl 6!=end podsub MAIN { say $=pod.elems; say $=pod[0].WHAT; say $=pod[1].WHAT;}=begin pod=head1 DESCRIPTIONThis is where I'd put some more stuff about the script if it did anything.=end pod

When we run this script we get:

$ perl6 ./bin/example2.p6 2(Named)(Named)

So there are now twoelements in $=pod, one for each chunk of Pod delimited by our =begin pod/ =end podpairs.

Pod Syntax in Perl 6

Up until this point I’ve shown you some Pod without actually explaining what it is. Let’s take a look at some valid Pod constructs in Perl 6 so you can get a better sense of how it looks, both when you write it and when you’re writing code to process it.

Perl 6 Pod is purely semantic. In other words, you describe whatsomething is, rather than howto present it. It’s left up to code that turns Pod into something else (HTML, Markdown, man pages) to decide how to present any given construct.

Perl 6 Pod has quite a bit more to it than we can cover here, so see Synopsis 26for all the details. We’ll cover some of the highlights and then look more closely at how to process Pod programmatically.

Blocks

Pod supports several different ways to declare a block. You can use =beginand =endmarkers …

=begin head1Heading Goes Here=end head1

Or you can use a =formarker …

=for head1Heading Goes Here

These block styles allow you to include configuration information:

=begin head3 :include-in-tocThis will show up in TOC=end head3=for head4 :!include-in-tocNot in the TOC

With a =forblock, only the lines immediately following the =foris part of that block. Once there is an empty line, anything that follows is separate.

You can use an “abbreviated” block …

=head1 Heading Goes Here

… but abbreviated blocks don’t allow for configuration information. Like =forblocks, abbreviated blocks end at the first empty line.

There are manytypes of blocks, including table, code, I/O blocks ( inputand output), lists, and more.

Paragraphs

Text that isn’t explicitly part of a block is considered to be a paragraph block …

use v6;=begin pod=begin head1NAME=end head1This is a paragraph block.=end podsub MAIN { say $=pod[0].contents[1].WHAT;}

The output will be (Para), because the second element of contentsis a plain paragraph.

Lists

Lists are much simpler in Perl 6 than they were in Perl 5 …

=begin pod=item1 The first item=item1 The second item=item2 This is a sub-item of the second item=item1 The third item

Of course, you can also use the =forand =begin/ =endform with list items too.

Formatting Codes

There are a variety of formatting codes available …

See L<http://design.perl6.org/S26.html> for details.Some times you need to mark some text as C<code>,B<being the basis of the sentence>,or I<important>. And More

There are a lot of new things with Perl 6 Pod, and if you want to learn more I encourage you to read Synopsis 26for all of the gory details.

Processing Pod with Perl 6

As I said before, the Perl 6 compiler parses Pod in your program and makes it available to you via various variables. We already saw the use of $=pod, which contains all of the Pod in the current file. That pod is an array of Pod::Blockobjects. In future versions of Rakudo, you will also be able to get at specific types of Pod blocks by name with variables such as $=head1or $=TITLE, but this is not yet implemented.

Let’s write a simple program to show us an outline of the Pod in a given file. For example, given some Pod like this …

=head1 NAME...=head1 DESCRIPTION...=head1 METHODS...=METHOD $obj.foo...=METHOD $obj.bar...

… we want to print this output …

NAMEDESCRIPTIONMETHODS $obj.foo (METHOD) $obj.bar (METHOD)

Here’s the code to do just that …

use v6;sub MAIN { for $=pod.kv -> $i, $block { say "Block $i"; recurse-blocks($block); print "/n"; }}sub recurse-blocks (Pod::Block $block) { given $block { when Pod::Block::Named { if $block.name eq 'pod' { for $block.contents.values -> $b { recurse-blocks($b); } } else { my $output = $block.contents[0].contents[0] ~ " ({$block.name})"; depth-say( 2, $output ); } } when Pod::Heading { depth-say( $block.level, $block.contents[0].contents[0] ); } }}sub depth-say (Int $depth, Str $thing) { print ' ' x $depth; say $thing;}

This code takes some shortcuts wherever it uses $block.contents[0].contents[0]by making the very big assumption that a block contains one element which is a single Pod::Block::Para. It then assumes that the Para block contains one element which is plain text.

In practice, blocks may contain arbitrarily nested blocks because of things like formatting codes, but this gives you an idea of how you might walk through the Pod tree.

Of course, because Perl 6 is still Perl, there’s a module for that! I’ve sketched out a preliminary module called Pod::TreeWalkerthat will do the tree walking for you, generating events as it finds different nodes. You provide a listener object that is called for each event.

GitHub Repo

All of the code shown in these examples is on GitHub. I’ve also written an additional scriptthat uses Pod::TreeWalkerto implement the outlining I demonstrate above.

相关阅读:
Top