30 Jul 2009

How to generate user documentation from Perl script?

If you want to generate user documentation from POD in Perl should add at the bottom of script this section - after keyword __END__(this is only example - I use this schema for my documentation): i
#!/usr/bin/perl

print "hello world!\n";

# end of script

# TAGS IN PERLDOC:
# *PROGNAME* - replace with program name
# *SHORT_DESCRIPTION* - one sentence description

__END__

=head1 NAME

*PROGNAME* - *SHORT_DESRIPTION*.



=head1 SYNOPSIS

*PROGNAME* 



=head1 EXAMPLES

*PROGNAME*

=head1 REQUIRED ARGUMENTS



=head1 OPTIONS

=over 4

=item B<-v, --verbose>

Be verbose

=item B<-d, --debug>

Be even more verbose - information specifig for debugging

=item B<-h, --help>

Display short usage help and exit

=back




=head1 DESCRIPTION

*PROGNAME* was designed for *PURPOSE*



=head1 DEPENDENCIES

=over 4

=item B<perl 5.6> or newer with standard modules

=back



=head1 BUGS AND LIMITATIONS

You are welcome to send bug reports about *PROGNAME* to my email.

Please attach in a bug report, informations like:

=over 4

=item * Perl version (perl --version)

=item * information what you've expected as a output

=back



=head1 VERSION

This documentation refers to *PROGNAME* version *VERSION*.



=head1 SEE ALSO

B<__>



=head1 AUTHOR

*AUTHOR*



=head1 LICENSE AND COPYRIGHT

*LICENSE*

About licenses

Generating docs

First of all you need to have perldoc.
apt-get install perl-doc

Wiki (syntax) documentation from Perl scripts - pod2wiki

There is an extension for POD which helps creating Wiki like syntax documentation from POD files. On Debian systems it can be installed using:
apt-get install libpod-simple-wiki-perl
Generating documentation is really easy
pod2wiki --style mediawiki file.pl > file.wiki
Possible styles of output are: I've made my own DokuWiki plugin to libpod-simple-wiki installation is easy, copy the contents to file named 'Dokuwiki.pm' and run cp Dokuwiki.pm /usr/share/perl5/Pod/Simple/Wiki/Dokuwiki.pm of course as a root. Porting was only done to step number 3 - for my test file it worked like a charm, but for yours it may not - just test it.
package Pod::Simple::Wiki::Dokuwiki;



# Portme: This module is used as a boiler plate or example of how to create a
# new C<Pod::Simple::Wiki::> module.
#
# Read the Portme section of the documentation below for more information.
#
# Portme. Try to maintain the same code style as this module:
#     4 space indents.
#     No tabs.
#     No trailing whitespace.
#     79 column wrap.
#     Consistency.
#

###############################################################################

#
# Pod::Simple::Wiki::Dokuwiki - A class for creating Pod to Dokuwiki filters.
#
#
# Copyright 2003-2007, John McNamara, jmcnamara@cpan.org
# Copyright 2009 - DokuWiki module, Tomasz Gaweda - http://blog.0x1fff.com/
#
# Documentation after __END__
#

use Pod::Simple::Wiki;
use strict;
use vars qw(@ISA $VERSION);


@ISA     = qw(Pod::Simple::Wiki);
$VERSION = '0.08';

# Portme. Start with these tags.


###############################################################################
#
# The tag to wiki mappings.
#
my $tags = {
            '<b>'    => '** ',
            '</b>'   => ' **',
            '<i>'    => '// ',
            '</i>'   => ' //',
            '<tt>'   => "''",
            '</tt>'  => "''",
            '<pre>'  => '   ',
            '</pre>' => "   \n\n",
            '<h1>'   => "\n===== ",
            '</h1>'  => " =====\n\n",
            '<h2>'   => "\n==== ",
            '</h2>'  => " ====\n\n",
            '<h3>'   => "\n=== ",
            '</h3>'  => " ===\n\n",
            '<h4>'   => "\n== ",
            '</h4>'  => " ==\n\n",
           };

# Portme. You can leave new() as it is.

###############################################################################
#
# new()
#
# Simple constructor inheriting from Pod::Simple::Wiki.
#
sub new {
    my $class                   = shift;
    my $self                    = Pod::Simple::Wiki->new('wiki', @_);
       $self->{_tags}           = $tags;
#      $self->{_debug}         = 1;
    bless  $self, $class;
    return $self;
}

# Portme. How Pod "=over" blocks are converted to Dokuwiki wiki lists.
###############################################################################
#
# _indent_item()
#
# Indents an "over-item" to the correct level.
#
sub _indent_item {
    my $self         = shift;
    my $item_type    = $_[0];
    my $item_param   = $_[1];
    my $indent_level = $self->{_item_indent};

    if ($item_type eq 'bullet') {
         $self->_append('  *' x $indent_level . ' ');
    }
    elsif ($item_type eq 'number') {
         $self->_append('  - ' x $indent_level . ' ');
    }
    elsif ($item_type eq 'text') {
         $self->_append('  * ' x $indent_level . ' ');
    }
}

# Portme: Use this is text tokens need to be escaped, such as CamelCase words.
###############################################################################
#
# _handle_text()
#
# Perform any necessary transforms on the text. This is mainly used to escape
# inadvertent CamelCase words.
#
sub _handle_text {
    my $self = shift;
    my $text = $_[0];

    # Only escape words in paragraphs
    if (not $self->{_in_Para}) {
        $self->{_wiki_text} .= $text;
        return;
    }

    # Split the text into tokens but maintain the whitespace
    my @tokens = split /(\s+)/, $text;

    # Portme:
    # Escape any tokens here, if necessary.

    # Rejoin the tokens and whitespace.
    $self->{_wiki_text} .= join '', @tokens;
}

# Portme. How Pod "=over" blocks are converted to Dokuwiki wiki lists.
###############################################################################
#
# Functions to deal with =over ... =back regions for
#
# Bulleted lists
# Numbered lists
# Text     lists
# Block    lists
#

sub _end_item_text     {$_[0]->_output("\n\n")}

# Portme: Probably won't have to change this.
###############################################################################
#
# _start_Para()
#
# Special handling for paragraphs that are part of an "over" block.
#
sub _start_Para {
    my $self         = shift;
    my $indent_level = $self->{_item_indent};

    if ($self->{_in_over_block}) {
        # Do something here is necessary
    }
}

1;

__END__

=head1 NAME

Pod::Simple::Wiki::Dokuwiki - A class for creating Pod to Dokuwiki wiki filters.

=head1 SYNOPSIS

This module isn't used directly. Instead it is called via C<Pod::Simple::Wiki>:

    #!/usr/bin/perl -w
    use strict;
    use Pod::Simple::Wiki;
    my $parser = Pod::Simple::Wiki->new('template');
    ...

Convert Pod to a Dokuwiki wiki format using the installed C<pod2wiki> utility:

    pod2wiki --style template file.pod > file.wiki

=head1 DESCRIPTION

This module is used as a boiler plate or example of how to create a new C<Pod::Simple::Wiki::> module. See the Portme section below.
The C<Pod::Simple::Wiki::Dokuwiki> module is used for converting Pod text to Wiki text.
Pod (Plain Old Documentation) is a simple markup language used for writing Perl documentation.
For an introduction to Dokuwiki see: http://www.portme.org
This module isn't generally invoked directly. Instead it is called via C<Pod::Simple::Wiki>. See the L<Pod::Simple::Wiki> and L<pod2wiki> documentation for more information.

=head1 PORTME

This module is used as a boiler plate or example of how to create a new C<Pod::Simple::Wiki::> module.
If you are thinking of creating a new C<Pod::Simple::Wiki::> you should use this module as a basis.
B<Portme>. Any comments in the code or documentation that begin with or contain the word C<portme> are intended for the C<porter>, the person who is creating the new module. You should read all of the C<portme> comments and eventully delete them when the module is finished.

The following are some suggested steps in porting the module. For the sake of example say we wish to convert Pod to a format called C<portmewiki>. Also for the sake of this example we will assume that you know how to install and work on a module or work on it in a local source tree using C<-I./lib> or C<-Mblib>.


=head2 Portme Step 1

Copy the C</lib/Pod/Simple/Wiki/Dokuwiki.pm> to a new module C</lib/Pod/Simple/Wiki/Portmewiki.pm>.

The module name should have the first letter capitalised and all others lowercase, i.e, the same as returned by C<ucfirst()>.

=head2 Portme Step 2

Edit the module and replace all instances of C<Dokuwiki> with C<Portmewiki> (case sensitive).

Then replace all instances of C<template> with C<portmewiki> (case sensitive).


=head2 Portme Step 3

The module should now work and can now be called as follows:

    use Pod::Simple::Wiki;
    my $parser = Pod::Simple::Wiki->new('portmewiki');

The default output format, in this configuration is Kwiki.


=head2 Portme Step 4

Write some tests.

Copy the tests in the C</t> directory for one of formats that is similar to the format that you are porting.


=head2 Portme Step 5

Modify the source of C<Portmewiki.pm> until all the tests pass and you are happy with the output format.
Start by modifying the C<tags> and then move on to the other methods.

If you encounter problems then you can turn on internal debugging:

    my $parser = Pod::Simple::Wiki->new('portmewiki');
    $parser->_debug(1);

    Or for more debug information that you can deal with:

    # At the start of your program and before anything else:
    use Pod::Simple::Debug (5);
    ...
    $parser->_debug(0);


If you find yourself with a difficult porting issue then you may also wish to read L<Pod::Simple::Methody> and L<Pod::Simple::Subclassing>.
Try to maintain the code style of this module. See the source for more information.


=head2 Portme Step 6


Remove or replace all C<portme> comments.


=head2 Portme Step 7

Send it to me the tarred directory with libs and tests and I'll release it to CPAN.


=head1 METHODS

Pod::Simple::Wiki::Dokuwiki inherits all of the methods of C<Pod::Simple> and C<Pod::Simple::Wiki>. See L<Pod::Simple> and L<Pod::Simple::Wiki> for more details.


=head1 Dokuwiki Specific information

Portme: Add some information specific to the Dokuwiki format or this module here. If required.


=head1 SEE ALSO

This module also installs a C<pod2wiki> command line utility. See C<pod2wiki --help> for details.


=head1 ACKNOWLEDGEMENTS

Thanks to Portme McPortme and Portme O'Portme for patches, documentation or bugfixes.

=head1 DISCLAIMER OF WARRANTY

Please refer to the DISCLAIMER OF WARRANTY in L<Pod::Simple::Wiki>.


=head1 AUTHORS

John McNamara jmcnamara@cpan.org

Portme McPortme portme@portme.org


=head1 COPYRIGHT

(C) MMIII-MMVII, John McNamara.

All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
Source of this module is also available on Google code. After instalation there is a simple way to invoke this:
pod2wiki --style dokuwiki file.pl > file.dokuwiki.txt
By the way, this helps publishing Perl code at Blogger - it changes some characters to proper HTML entities.

RTF documentation from Perl scripts - pod2rtf

First of all if you need to use Polish characters in your manual, you should convert source from UTF-8 to ISO-8859-2 and later run command:
perldoc -ortf file.pl > file_pod.rtf

LaTeX documentation from Perl scripts - pod2latex

perldoc -oLaTeX file.pl > file_pod.tex
or
pod2latex file.pl -out file_pod.tex
Both commands do the same.

PDF documentation from Perl scripts - pod2pdf

There is a module which provides pdf pod writer and whole project pod2pdf. This projects require libpdf-api2-perl and lib argvfile.
apt-get install libpdf-api2-perl libgetopt-argvfile-perl
General usage od pod2pdf is:
pod2pdf file.pl > file_pod.pdf
For more specific istructions reffer to author site or to polish "man page"

HTML documentation from Perl scripts - pod2html

First of all we need libpod-xhtml-perl - translate POD to Xhtml.
apt-get install libpod-xhtml-perl
General usage of pod2html package:
pod2html file.pl > file_pod.html

Manpage documentation from Perl scripts - pod2man

pod2man file.pl > file_pod.man

Summary of generating user documentation in Perl

#!/bin/bash

if [ $# -lt 1 ] ; then
 echo "usage: "$0" file1.pl file2.pl ... fileN.pl"
 exit;
fi

for file in $@ ; do
 out=`basename $file .pl`
 if [ ! -d $out ] ; then 
  mkdir $out
 fi
 echo "Generating perldoc for file $file in $out"
 outName="${out}/${out}_man_"`date -I`
 
 # here do character conversion
 tmpName=`mktemp /tmp/perlDocAll.XXXXXXX`
 tmpNamePl=$tmpName".pl"
 #iconv -f UTF-8 -t ISO-8859-2 $file > $tmpNamePl
 cat $file > $tmpNamePl

 perldoc -ortf $tmpNamePl > $outName.rtf
 pod2latex $tmpNamePl -out $outName.tex
 pod2pdf $tmpNamePl > $outName.pdf
 pod2html $tmpNamePl > $outName.html
 pod2man $tmpNamePl > $outName.man
 pod2wiki --style dokuwiki $tmpName > $outName.dokuwiki.txt

 rm $tmpName $tmpNamePl
done
This simple scripts converts documentation from .pl files into all formats described in this article :) have fun.

Documentation generators in other languages

4 comments:

  1. Each Perl script can use standard man pages headings like:

    * NAME contains the module or script name, a dash and a short description.
    * SYNOPSIS means "see together" and shows example usage.
    * DESCRIPTION contains a long description of what the module does and lists functions.
    * BUGS or CAVEATS tells about bugs or issues the user should know about.
    * ACKNOWLEDGEMENTS is where you thank bug fixers, testers and you parents.
    * COPYRIGHT or LICENSE mentions copyright restrictions. Don't put the entire GPL there, though :)
    * AVAILABILITY says where newer versions can be pulled from.
    * AUTHOR explains who made it, if COPYRIGHT didn't already do so.
    * SEE ALSO refers to additional documentation.

    (http://www.perlmonks.org/?node_id=252477)

    ReplyDelete
  2. You explained how to put the POD code in the ending of the sources code. That's good, but may be you know how to put it inside the sources(for example in the beginning of the function).
    Thank you in advance.

    ReplyDelete
  3. Hello Anonymous ;),

    I can write, but I prefer to have user doc on the bottom of script - because it is in one place.

    If you want docs near functions, you have to use =pod and =cut commands like this:

    Info from: http://perldoc.perl.org/perlpod.html#Verbatim-Paragraph - I hope it will be readable.

    =pod

    The "=pod" command by itself doesn't do much of anything, but it signals to Perl (and Pod formatters) that a Pod block starts here. A Pod block starts with any command paragraph, so a "=pod" command is usually used just when you want to start a Pod block with an ordinary paragraph or a verbatim paragraph. For example:

    1. =item stuff()
    2.
    3. This function does stuff.
    4.
    5. =cut
    6.
    7. sub stuff {
    8. ...
    9. }
    10.
    11. =pod
    12.
    13. Remember to check its return value, as in:
    14.
    15. stuff() || die "Couldn't do stuff!";
    16.
    17. =cut

    ReplyDelete
  4. thanks a lot about it. I'll try such way soon.
    dziękuję :)

    ReplyDelete