Daizu
view release on metacpan or search on metacpan
lib/Daizu/Plugin/PodArticle.pm view on Meta::CPAN
package Daizu::Plugin::PodArticle;
use warnings;
use strict;
use Pod::Parser;
use Daizu::Util qw( add_xml_elem );
# TODO - according to the perlpodspec I have to insert an HTML comment
# containing the name and version number of my POD translator.
=head1 NAME
Daizu::Plugin::PodArticle - a plugin for publishing Perl POD documentation on websites
=head1 DESCRIPTION
This plugin adds the ability for Daizu CMS to load content from POD files
(or Perl code containing POD documentation). Once this module has parsed
the file it provides Daizu with the content in XHTML format (as a DOM
structure), and from then on it can be treated as a normal article.
With this module loaded it should be possible to publish Perl documentation
simply by adding the files containing POD to the repository, marking them
as being articles like any other, and giving them a C<svn:mime-type>
property with the value 'text/x-perl'.
=head1 CONFIGURATION
To turn on this plugin, include the following in your Daizu CMS configuration
file:
=for syntax-highlight xml
<plugin class="Daizu::Plugin::PodArticle" />
=head1 POD EXTENSIONS
This module understands the following non-standard POD features, which
will be ignored by all other POD processeors:
=over
=item Syntax highlighting
If you want an indented block of text to be syntax highlighted (showing
colour-coding to make code samples or whatever easier to read), you can
include a command like the following before the indented block:
=for syntax-highlight pod
=for syntax-highlight perl
my $foo = 'this perl code will be syntax colored.'
This requires the L<Daizu::Plugin::SyntaxHighlight> plugin to be
enabled too.
Each of these C<=for> commands will only affect a single indented
block (whichever one is found next). Blank lines in blocks won't
break them up; the syntax highlighting will last up until the next
thing which isn't indented (a command or a normal paragraph).
=item The fold
You can get the same effect as the special C<daizu:fold> element gives
in XHTML articles using the following markup:
=for syntax-highlight pod
=for daizu-fold
This is not likely to be useful unless you're writing blog articles
in POD, in which case the content above the fold will be shown in
index pages (and possibly feeds, depending on how they're configured).
=item Page breaks
You can get the same effect as the special C<daizu:page> element gives
in XHTML articles using the following markup:
=for syntax-highlight pod
=for daizu-page
Occurances of this will separate pages of content, allowing a long
document to be split into multiple pages for web publication.
=back
=head1 LINKS
TODO - describe the awful hackiness of the module-links.txt file, and
whatever other incompatibilities might be a problem.
=head1 METHODS
=over
=item Daizu::Plugin::PodArticle-E<gt>register($cms, $whole_config, $plugin_config, $path)
Called by Daizu CMS when the plugin is registered. It registers the
L<load_article()|/$self-E<gt>load_article($cms, $file)> method as
an article loader for the MIME type 'text/x-perl'.
The configuration is currently ignored.
=cut
sub register
{
my ($class, $cms, $whole_config, $plugin_config, $path) = @_;
my $self = bless {}, $class;
$cms->add_article_loader('text/x-perl', '', $self => 'load_article');
}
=item $self-E<gt>load_article($cms, $file)
Does the actual parsing of the POD content of C<$file> (which should
be a L<Daizu::File> object), and returns the approriate content and metadata.
Never rejects a file, and therefore always returns true.
=cut
sub load_article
{
my ($self, $cms, $file) = @_;
# Use .html URL for the actual article.
# TODO - this is mostly or exactly the same as the code in PictureArticle.
# TODO - it's also rather inefficient, because we're doing base_url when
# saving the article anyway, in Daizu::File.
my $article_url = '';
my $base_url = $file->generator->base_url($file);
if ($base_url !~ m!/$!) {
$article_url = $file->{name};
$article_url =~ s!\.[^./]+$!.html!
or $article_url .= '.html';
}
# Publish the source code too, and link to it from the article.
# Currently this is only done for .pm files, since that's useful for
# documentation of Perl modules, but you don't necessarily want it for
# general purpose documents.
my @extra_url;
my @extra_template;
if ($file->{name} =~ /\.pm$/i) {
push @extra_url, {
url => $file->{name},
type => 'text/x-perl',
generator => 'Daizu::Gen',
method => 'unprocessed',
};
push @extra_template, 'plugin/podarticle_extras.tt';
}
my $parser = Daizu::Plugin::PodArticle::Parser->new;
$parser->{daizu_lists} = [];
$parser->{first_cmd} = 1;
my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');
my $body = $doc->createElementNS('http://www.w3.org/1999/xhtml', 'body');
$doc->setDocumentElement($body);
$parser->{daizu_curelem} = $body;
open my $fh, '<', $file->data
or die "error opening memory file: $!";
$parser->parse_from_filehandle($fh);
my ($title, $short_title);
if (defined $parser->{doc_title}) {
$title = $parser->{doc_title};
$short_title = $1
if $title =~ /^\s*(\S+)\s+-+\s/;
}
return {
content => $doc,
title => $title,
short_title => $short_title,
pages_url => $article_url,
extra_urls => \@extra_url,
extra_templates => \@extra_template,
};
}
=back
=head1 Daizu::Plugin::PodArticle::Parser
This class is the subclass of L<Pod::Parser> used for parsing POD documents
into XHTML DOM documents. It overrides the methods
L<command()|Pod::Parser/command()>,
L<textblock()|Pod::Parser/textblock()>, and
L<verbatim()|Pod::Parser/verbatim()>.
=cut
package Daizu::Plugin::PodArticle::Parser;
use base 'Pod::Parser';
use XML::LibXML;
use HTML::Entities qw( decode_entities );
use Carp::Assert qw( assert DEBUG );
use Daizu::Util qw( trim daizu_data_dir );
use Daizu;
sub _list_type
{
my ($s) = @_;
return 'ul' if $s eq '' || $s eq '*';
return 'ol' if $s =~ /^1\.?$/;
return 'dl';
}
{
my $module_links;
sub _module_links
{
if (!defined $module_links) {
my $filename = daizu_data_dir('pod')->file('module-links.txt');
open my $fh, '<', $filename
or die "error loading '$filename': $!";
$module_links = {};
while (<$fh>) {
next unless /\S/;
next if /^\s*#/;
my ($module, $url) = split ' ', $_;
$module_links->{$module} = $url;
}
}
return $module_links;
}
}
sub _do_heading
{
my ($self, $line_num, $level, @content) = @_;
# Convert all-uppercase titles to title case.
if (@content == 1 && $content[0] !~ /[a-z]/) {
$content[0] = join ' ',
map { ucfirst lc $_ }
split ' ', $content[0];
}
my $elem = 'h' . ($level + 2);
die "$line_num: heading 'head$level' missing title"
( run in 0.767 second using v1.01-cache-2.11-cpan-d01c6094234 )