develooper Front page | perl.qa | Postings from August 2000

RFC 11 (v1) Examples encoded with =also for|begin|en

From:
Perl6 RFC Librarian
Date:
August 2, 2000 21:19
Subject:
RFC 11 (v1) Examples encoded with =also for|begin|en
Message ID:
20000803040946.20133.qmail@tmtowtdi.perl.org
=head1 TITLE

Examples encoded with =also for|begin|end POD commands

=head1 VERSION

  Maintainer: Barrie Slaymaker <barries@slaysys.com>
  Date: 02 Aug 2000
  Version: 1
  Mailing List: perl-qa@perl.org
  Number: 11

=head1 ABSTRACT

I<Note: written in the present tense, though =also, Pod::Tests, and
pod2tests are not yet implemented>.

The C<=also for|begin|end> commands are shorthand having two copies
of a section of POD (typically an example), one normal copy, and one
delimited by C<=for> or C<=begin> ...C<=end>.  This supports
semi-literate programming techniques, allowing examples in POD to be
extracted and tested.  It does not affect normal compilation of
the source code, though older POD parsers may emit warnings.

=head1 DESCRIPTION

Many existing programs and modules include POD examples demostrating
how too use the command or API provided.  These examples are rarely
tested or maintained, and can lead to lost time on the part of the
module's or program's users.

Extracting these examples using Pod::Tests (usually by running
pod2tests) on the source file and emitting them as test scripts
provides a service both to the POD user and to the code 
maintainer.

The C<=also> tag allows extractors like Pod::Tests to select
exactly the same text that the POD user sees, so that the
code maintainer can be sure that the documentation is at least
partially correct.

Technically, a feature like this could be used to support literate
programming of a modules' source code, but that is not the intent
of the C<=also> tag.

=head2 Example

The C<=also> tag, in combination with special purpose parsers,
allows a Pod::Parser based pod2text to process POD like:

  =item run

  =for test run.t
     #!perl -w
     use Test ;
     use IPC::Run qw( run ) ;
     $cmd = $^X ;
     @args = ( '-e', 'print "hello world\n"' ) ;
     ( $in, $out, $err ) = ('') x 3 ;
     plan tests => 2 ;

  =also for test run.t
     $r = run( [$cmd, @args], \$in, \$out, \$err ) ;

  =for test run.t
     ok( $out, "hello world\n" ) ;
     ok( $err, "" ) ;

  The run() method blah, blah, blah...

  =cut

  sub run {
     ...
  }

and provide output like:

    run
    
       $r = run( [$cmd, @args], \$in, \$out, \$err ) ;
    
    The run() method blah, blah, blah...
    
.  It also allows pod2tests to process the same POD and produce a test
script t/run.t containing code like

  #!perl -w
     use Test ;
     use IPC::Run qw( run ) ;
     $cmd = $^X ;
     @args = ( '-e', 'print "hello world\n"' ) ;
     ( $in, $out, $err ) = ('') x 3 ;
     plan tests => 2 ;
     $r = run( [$cmd, @args], \$in, \$out, \$err ) ;
     ok( $out, "hello world\n" ) ;
     ok( $err, "" ) ;

The '#line' directives are not shown in this example script for clarity.

=for __EDITORIAL__
Really, it's because I didn't feel like faking them ;-) - RBS

=head1 IMPLEMENTATION

The C<=also> command is implemented in Pod::Parser in a process
called "=also mangling". This process passes the
marked regions to the Pod::Parser handlers twice, once in
"plain POD" mode, which looks to the handlers exactly as
though the lines
beginning with C<=also> weren't present, and then a second time
in "C<=for>/C<=begin>" mode, as
though they were enclosed by C<=for>, C<=begin>, and C<=end>
commands.

This means that each paragraph marked as C<=also for foo>
results in two calls, the first to verbatim() or textblock(),
and the second to command(), with a command value of '=for'.

Paragraph sequences bounded by C<=also begin foo> and C<=also
end foo> are passed when parsed to verbatim() or textblock()
as they are parsed.

They are also accumulated until the C<=also end foo>
tag is found.  The command() handler is then called with a
command value of "=begin", followed by a duplicate series
of calls to verbatim() and textblock(), followed by a
call to command() with a command value of "=end".

If needed at some future point, an option can be added to
Pod::Parser to make it treat C<=also> as a normal command,
as can a "mangle_also" property to discover if C<=also> mangling
is supported (via can()) and  to query or set the mangling
option.

Pod::Parser based translators that generate documentation
(all "normal" pod translators)
ignore the second "C<=for>/C<=begin>" version of the C<=also>
paragraphs and only emit output for the "as plain POD" calls.
See below for why using C<=also> to direct paragraphs to such
processors is a Bad Idea.

Pod::Parser based processors that extract only those POD segments
C<=for> them ignore anything not intended for them, so they
ignore the first "plain POD" set of calls generated by C<=also>
sections and only see the second "C<=for>/C<=begin>" version.

This duplicitous subterfuge is a bit awkward, but it was designed
to allow the "=also" command handling to be added only to Pod::Parser
and to not affect existing parsers.

=head2 Compatibility with =for html, =for text, etc.

Using C<=also> to flag sections for documentation translators is
a mistake.  For example,
a command C<=also for html E<lt>PE<gt>blah> will cause POD to HTML
translators to output something like "&lt;P&gt;blah<P>blah",
which makes for confusing reading.

=head2 Backwards Compatibility

Using the =also tag can cause older parser to emit "unrecognized
directive" warnings and possibly may cause them to exit
prematurely.

The solution is to upgrade to Pod::Parser based translators if
possible, or to ignore the warnings if not.  If the translator
in question exits prematurely and an upgrade is not possible,
it will need to be patched.

=head1 REFERENCES

  RFC ??: "=for test and pod2test"
  perlpod manpage
  Pod::Parser





nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About