#!/usr/bin/perl use strict; use warnings; # # the view that turns pod into S5 # package Pod::POM::View::MyHTML; use base 'Pod::POM::View::HTML::Filter'; sub view_pod { my ( $self, $pod ) = @_; $pod->content->present($self); } sub view_head1 { my ( $self, $pod ) = @_; qq'
\n

' . $pod->title->present($self) . qq'

\n
\n' . $pod->content->present($self) . qq'
\n'; } # add support for ul classes (incremental style, etc.) my @OVER; # because @OVER is a private variable in Pod::POM::View::HTML, # I had to copy view_item() verbatim, in addition to the slightly # modified view_over() :-( sub view_over { my ($self, $over) = @_; my ($start, $end, $strip); my $items = $over->item(); return "" unless @$items; my $first_title = $items->[0]->title(); my $style = $over->indent =~ /^incremental/ ? ' class="' . $over->indent . '"' : ''; if ($first_title =~ /^\s*\*\s*/) { # '=item *' => \n"; $strip = qr/^\s*\*\s*/; } elsif ($first_title =~ /^\s*\d+\.?\s*/) { # '=item 1.' or '=item 1 ' =>
    $start = "\n"; $end = "
\n"; $strip = qr/^\s*\d+\.?\s*/; } else { $start = "\n"; $end = "\n"; $strip = ''; } my $overstack = ref $self ? $self->{ OVER } : \@OVER; push(@$overstack, $strip); my $content = $over->content->present($self); pop(@$overstack); return $start . $content . $end; } # this block is straight from Pod::POM::View::HTML :-( sub view_item { my ($self, $item) = @_; my $over = ref $self ? $self->{ OVER } : \@OVER; my $title = $item->title(); my $strip = $over->[-1]; if (defined $title) { $title = $title->present($self) if ref $title; $title =~ s/$strip// if $strip; if (length $title) { my $anchor = $title; $anchor =~ s/^\s*|\s*$//g; # strip leading and closing spaces $anchor =~ s/\W/_/g; $title = qq{$title}; } } return '
  • ' . "$title\n" . $item->content->present($self) . "
  • \n"; } # # the actual spod5 script # package main; use Pod::POM 'meta'; use Pod::POM::View::HTML::Filter; use Getopt::Long; use Template; use File::Spec; use File::Basename; our $VERSION = '0.02'; # usage message my $usage = << "USAGE"; Available options: --quiet : be silent --force : clobber existing html files --exec : enables =exec lines --base : directory containing the S5 .css and .js files --slides : alternate slides.css (relative to --base) --debug : print the intermediate pod to STDOUT --multi : create one HTML file per slide USAGE # basic command-line params my %conf = ( quiet => 0, force => 0, debug => 0, base => File::Spec->catfile( 'ui', 'default' ), slides => 'slides.css', exec => 0, multi => 0, ); GetOptions( \%conf, "quiet!", "force!", "debug!", "base=s", "exec!", "slides=s", "multi!", "help!", "version!" ) or die $usage; # information print STDERR "spod5 version $VERSION\n" if $conf{version}; print STDERR $usage if $conf{help}; exit if $conf{help} || $conf{version}; # all the useful stuff here my $parser = Pod::POM->new(); my $tt = Template->new(); my @template = split /^EOT\n/m, join( '', ); $|++; # helper sub sub include { my ($src, $inc) = @_; $inc = File::Spec->catfile( dirname($src), $inc ) if !File::Spec->file_name_is_absolute($inc); open my $fh, "<", $inc or do { my $err = "$inc: $!"; warn $err; return $err }; my $t = join "\n", <$fh>; close $fh; $t; } my @files = @ARGV; for my $file (@files) { @ARGV = ($file); ( my $new = $file ) =~ s/(?:\.pod)?$/.html/; print STDERR "$file... " unless $conf{quiet}; next if !$conf{force} && -e $new && ( stat $new )[9] > ( stat $file )[9] && !$conf{quiet} && print STDERR "skipped (use --force)\n"; my $text = join '', <>; next unless $text; # convert text shortcuts back to pod # ain't that plain ugly? $text =~ s/^(=+) +/=head@{[length $1]} /gm; $text =~ s/^\* +/\n=item *\n\n/gm; $text =~ s/^# +/\n=item 1\n\n/gm; $text =~ s/^\+\s*$/\n=over 4\n/gm; $text =~ s/^\+>\s*$/\n=over incremental show-first\n/gm; $text =~ s/^\+>>\s*$/\n=over incremental\n/gm; $text =~ s/^\-\s*$/\n=back\n\n/gm; $text =~ s/\A\s*//; # Pod::POM does not likes newlines at the beginning $text =~ s!^{{(.*?)^}}!=for html
    \n\n$1\n=for html
    \n\n!gms; $text =~ s!^=img\s+(\S+)!=for html \n\n!gm; $text =~ s{^=include\s+(\S+)}{include($file, $1)}egm; $text =~ s{^=exec\s+(.+)}{`$1`}egm if $conf{exec}; # debug the intermediate pod print STDOUT "\n$text" if $conf{debug}; # parse the pod my $pom = $parser->parse_text($text); $pom->metadata( base => $conf{base} ); $pom->metadata( slides => $pom->metadata('slides') || $conf{slides} ); if( $conf{multi} ) { # file name $new = basename($new); $new =~ s/\.html$/%04d.html/; # print table of contents using each =head1 title my $n = 0; my $zero = sprintf( $new, $n ); my $total =()= $pom->head1(); $total--; # counting from 0 for my $slide ($pom->head1()) { my $prev = $n > 0 ? sprintf( $new, $n - 1 ) : ''; my $next = $n < $total ? sprintf( $new, $n + 1 ) : ''; $tt->process( \$template[1], { pom => $slide, slide => { total => $total, number => $n, zero => $zero, next => $next, prev => $prev, }, view => Pod::POM::View::MyHTML->new(), meta => $pom->metadata, }, sprintf( $new, $n ) ) || warn $tt->error; $n++; } } else { # produce the HTML in a single file $tt->process( \$template[0], { pom => $pom, view => Pod::POM::View::MyHTML->new(), meta => $pom->metadata, }, $new ) || warn $tt->error; } print STDERR "done\n" unless $conf{quiet}; } =pod =head1 NAME spod5 - Turn pod into S5 =head1 SYNOPSIS B [--I] [--I] [--I] [I<--base> F] [--I F] [--I] [--I] [--I] file.pod [ ... ] =head1 DESCRIPTION B is a I tool, that uses C to add syntax coloring to your slides. =head2 Command-line options B supports the following options: =over 4 =item --I Do not print information messages. =item I<--force> Clobber existing F<.html> files. =item --I F Directory where the S5 CSS and JavaScript files are to be found. Default is F. =item --I F Provide a replacement for the standard F file found in F. This allows one to define their own styles. See also the C<=meta slides> directive in the source file. =item --I Use an alternative template to create an HTML file per slide. (This is still beta.) =item --I Execute the commands in C<=exec> directives. =item --I Provide the list of available options and exit. =item --I Print version information and exit. =back =head1 WRITING A SPOD5 DOCUMENT Writing a presentation with B is rather easy: all the C<=head1> headers mark the beginning of a new slide. The rest of the pod mark-up is converted as usual. B add several shortcuts and features: =over 4 =item * C<=begin filter> / C<=end filter> sections allow support for syntax highlighting as done by C. Several shortcuts are recognised: =item * convert into a bulleted list (can be nested): + * bam * powie * kapow - =item * support the C and C classes, by using an explicit C<=over I
    [% meta.title_top %]

    [% meta.title %]

    [% meta.author %]

    [% meta.company %]

    [% meta.title_bottom %]
    [% pom.present(view) %]
    EOT [% meta.title %]
    [% IF slide.number != 0 %][% slide.number %]/[% slide.total %][% END %]

    [% pom.present(view) %]