File Coverage

blib/lib/Formatter/HTML/MPS.pm
Criterion Covered Total %
statement 85 102 83.3
branch 26 34 76.4
condition 7 12 58.3
subroutine 14 18 77.7
pod 5 5 100.0
total 137 171 80.1


line stmt bran cond sub pod time code
1             package Formatter::HTML::MPS;
2              
3             =head1 NAME
4              
5             Formatter::HTML::MPS
6              
7             =head1 DESCRIPTION
8              
9             This module converts MPS input to HTML. MPS is a simple format
10             describing a presentation or a set of slides; it is a combination
11             of the lightweight markup language Markdown and a separate markup
12             language to configure this formatter.
13              
14             The slides are contained in a single HTML file, and should be
15             shown as individual slides using CSS.
16              
17             It conforms with the Formatter API specification, version 0.95.
18              
19             =head1 MPS FORMAT
20              
21             Each slide is formatted using the Markdown format. In addition to
22             that, a simple format is used to set variables and to denote new
23             slides.
24              
25             All MPS directives start with ';', and comments start with
26             ';;'. Neither the MPS directives or comments will appear in the
27             output.
28              
29             To indicate a new slide, use the 'newslide' directive. I.e., start
30             the line with:
31              
32             ; newslide
33              
34             To set a configuration variable, use the 'set' directive. I.e.:
35              
36             ; set VAR = VALUE
37              
38             Currently, supported variables are:
39              
40             * output_format: only 'xhtml1.0_strict' is supported. Example:
41              
42             ; set output_format = xhtml1.0_strict
43              
44             * title: the title of the presentation.
45              
46              
47             =head1 SYNOPSIS
48              
49             use Formatter::HTML::MPS;
50             my $formatter = Formatter::HTML::MPS->format( $mpsdata );
51              
52             =head1 METHODS
53              
54             =cut
55              
56              
57 5     5   3622 use strict;
  5         9  
  5         157  
58 5     5   206 use warnings;
  5         13  
  5         121  
59              
60 5     5   24 use Carp;
  5         11  
  5         480  
61 5     5   28 use Exporter;
  5         6  
  5         183  
62 5     5   3291 use Formatter::HTML::MPS::OutputFormats;
  5         13  
  5         686  
63 5     5   8269 use HTML::LinkExtor;
  5         68793  
  5         250  
64 5     5   14059 use Text::Markdown;
  5         279117  
  5         505  
65 5     5   54 use vars qw( $VERSION @ISA @EXPORT );
  5         10  
  5         8359  
66              
67             @ISA = ('Exporter');
68             $VERSION = '0.4';
69             @EXPORT = ( 'generate' );
70              
71              
72              
73              
74              
75             our $DEFAULT_OUTPUT_FORMAT = 'xhtml1.0_strict';
76              
77             =head2 format ( mpsdata )
78              
79             Initialize the formatter. Returns an instance of this formatter
80             for the specified input.
81              
82             =cut
83             sub format {
84 5     5 1 878 my ( $class, $mpsdata ) = @_;
85              
86 5         16 my $self = {};
87 5         14 bless $self, $class;
88              
89 5         14 my %options = ();
90              
91 5         11 my $slidecount = 0; # Keep track of number of slides
92 5         16 my $html = ''; # This will contain the generated HTML
93            
94 5         48 my @mps = split( "\n", $mpsdata );
95              
96             # Read each line individually
97 5         25 while ( @mps ) {
98 46         64 my $line = shift @mps;
99              
100 46 100       151 if ( $line =~ /^;/ ) {
101             # Line is a comment or directive
102 37 100       193 if ( $line =~ /^;\s*set (\w+)\s*=\s*(.+)/ ) {
    100          
    100          
103             # Set an option:
104 16         113 $options{$1} = $2;
105             }
106             elsif ( $line =~ /^;;/ ) {
107 12         106 next;
108             }
109             elsif ( $line =~ /^;\s*newslide/ ) {
110 6 100       25 if ( ++$slidecount == 1 ) {
111 5         22 $html .= _header( \%options );
112             }
113              
114             # Start a new slide
115 6         30 $html .= _slidestart( \%options );
116              
117            
118             # Read slide data from @mps, until we're out of data
119             # or run into a new slide
120 6         14 my @markdown_data = ();
121 6   100     10 do {
122 15         25 $line = shift @mps;
123 15 100       132 push @markdown_data, $line."\n" unless $line =~ /^;/;
124             }
125             while ( @mps and $line !~ /^;\s*newslide/ );
126              
127             # Unshift the line, so the code will recognize the new slide in next
128             # loop.
129              
130 6 100       29 unshift( @mps, $line ) if ( $line =~ /^;\s*newslide/ );
131              
132             # Pass the Markdown input to Text::Markdown and store
133             # the resulting HTML
134 6         54 my $m = Text::Markdown->new;
135 6         156 $html .= $m->markdown( join( '', @markdown_data ) );
136              
137             # End this slide
138 6         15163 $html .= _slideend( \%options );
139             }
140             }
141             }
142              
143              
144             # A footer is usually needed, so let's append that as well.
145 5         23 $html .= _footer( \%options );
146              
147            
148             # Store misc. data in the object instance.
149 5         35 $self->{options} = \%options;
150 5         21 $self->{html} = $html;
151              
152 5         20 return $self;
153             }
154              
155              
156              
157              
158             =head2 document
159              
160             Returns the HTML formatting of the previously specified input.
161              
162             =cut
163             sub document {
164 5     5 1 29 my ( $self, $charset ) = @_;
165 5         16 return $self->{html};
166             }
167              
168              
169              
170              
171             =head2 title
172              
173             Returns the title of the document.
174              
175             =cut
176             sub title {
177 0     0 1 0 my $self = shift;
178 0         0 return $self->{options}->{title};
179             }
180              
181              
182              
183              
184             =head2 links
185            
186             Return the links in the document... At least that's what it should
187             do when it's implemented.
188              
189             =cut
190             sub links {
191 0     0 1 0 my $self = shift;
192              
193 0         0 my @links = ();
194              
195             my $cb = sub {
196 0     0   0 my($tag, %attr) = @_;
197 0 0       0 return if $tag ne 'a';
198 0         0 push @links, values %attr;
199 0         0 };
200              
201 0         0 my $xtor = HTML::LinkExtor->new( $cb );
202 0         0 $xtor->parse( $self->{html} );
203              
204 0         0 return @links;
205             }
206              
207              
208              
209             =head2 fragment
210              
211             =cut
212             sub fragment {
213 0     0 1 0 my $self = shift;
214 0         0 my ( $fragment ) = ( $self->{html} =~ /(.*)<\/body>/s );
215 0         0 return $fragment;
216             }
217              
218              
219             sub _header {
220             # Return the right header for the specified output format. We only
221             # support one output format for now... This code would perhaps
222             # need some refactoring to support more formats.
223              
224 5     5   11 my $options = shift;
225 5   33     25 my $output_format = $options->{output_format} || $DEFAULT_OUTPUT_FORMAT;
226              
227 5         11 my $header = '';
228 5 50       18 if ( $output_format eq 'xhtml1.0_strict' ) {
229 5         18 $header = $HEADERS{$output_format};
230              
231             # Insert title (if any):
232 5 50       18 if ( exists $options->{title} ) {
233 5         50 $header =~ s/\$title/$options->{title}/;
234             }
235            
236             # Insert CSS, link or inline, default to link:
237 5 100 66     43 if ( exists $options->{csstype} and $options->{csstype} eq 'inline' ) {
    100          
238 1         10 my $css = $CSS{$output_format}->{inline};
239              
240 1 50       3 if ( defined $options->{cssfile} ) {
241             # Slurp file and insert inline:
242 1 50       33 open my $fh, '<', $options->{cssfile} or confess $!;
243 1         31 my $cssdata = join( '', <$fh> );
244            
245 1         16 $css =~ s/\$content/$cssdata/;
246             }
247             else {
248             #$css =~ s/\$content/$options->{css}/;
249 0         0 confess "No CSS file specified. Please set CSS filename with '; set cssfile = '.";
250             }
251            
252 1         5 $header =~ s/\$css/$css/;
253             }
254             elsif ( exists $options->{cssfile} ) {
255             # Insert link to CSS file:
256 2         25 my $css = $CSS{$output_format}->{link};
257 2         18 $css =~ s/\$cssfile/$options->{cssfile}/;
258              
259 2         10 $header =~ s/\$css/$css/;
260             }
261             else {
262             #$header =~ s/\$css/$CSS{$output_format}->{link}/;
263             #confess "No CSS file specified, unable to continue.";
264            
265             # Insert default CSS, inline:
266 2         8 my $css = $CSS{$output_format}->{inline};
267 2         108 my $cssdata = join( '', );
268 2         23 $css =~ s/\$content/$cssdata/;
269              
270 2         27 $header =~ s/\$css/$css/;
271             }
272              
273             }
274             else {
275 0         0 confess "no!";
276             }
277              
278 5 50       29 my $title = ( defined $options->{title} ) ? $options->{title} : '';
279 5 100       24 my $author = ( defined $options->{author} ) ? $options->{author} : '';
280              
281 5         20 $header .=<
282            
283            
$title
284            
$author
285            
 
286            
 
287            
288             END
289              
290 5         35 return $header;
291             }
292              
293              
294             sub _footer {
295 5     5   12 my $options = shift;
296 5   33     22 my $output_format = $options->{output_format} || $DEFAULT_OUTPUT_FORMAT;
297              
298 5 50       19 if ( $output_format eq 'xhtml1.0_strict' ) {
299 5         19 return $FOOTERS{$output_format};
300             }
301             else {
302 0         0 confess "no!";
303             }
304             }
305              
306              
307             sub _slidestart {
308 6     6   14 return "
\n";
309             }
310              
311             sub _slideend {
312 6     6   121 return "\n";
313             }
314              
315              
316             =head1 BUGS
317              
318             Please let me know. :)
319              
320             =head1 COPYRIGHT
321              
322             Copyright 2006 Vetle Roeim
323              
324             This library is free software; you can redistribute it and/or modify
325             it under the same terms as Perl itself, either Perl version 5.8.4 or,
326             at your option, any later version of Perl 5 you may have available.
327              
328             =cut
329              
330             1;
331              
332             __DATA__