File Coverage

blib/lib/Pod/WikiDoc.pm
Criterion Covered Total %
statement 184 202 91.0
branch 94 106 88.6
condition 23 32 71.8
subroutine 24 26 92.3
pod 4 4 100.0
total 329 370 88.9


line stmt bran cond sub pod time code
1             package Pod::WikiDoc;
2 24     24   966914 use strict;
  24         61  
  24         1057  
3 24     24   135 use warnings;
  24         51  
  24         1326  
4             # ABSTRACT: Generate Pod from inline wiki style text
5             our $VERSION = '0.20'; # VERSION
6              
7             $Pod::WikiDoc::VERSION ||= '999';
8              
9 24     24   1152 use 5.006;
  24         83  
  24         1172  
10 24     24   143 use Carp;
  24         54  
  24         2277  
11 24     24   40092 use IO::String 1.06;
  24         132676  
  24         1244  
12 24     24   531 use Scalar::Util 1.02 qw( blessed );
  24         710  
  24         3274  
13 24     24   89855 use Pod::WikiDoc::Parser;
  24         162  
  24         122760  
14              
15             #--------------------------------------------------------------------------#
16             # PREAMBLE DOCUMENTATION
17             #--------------------------------------------------------------------------#
18              
19              
20             #--------------------------------------------------------------------------#
21             # PUBLIC METHODS
22             #--------------------------------------------------------------------------#
23              
24              
25             my %default_args = (
26             comment_blocks => 0,
27             comment_prefix_length => 3,
28             keywords => {},
29             );
30              
31             sub new {
32 28     28 1 8486 my ( $class, $args ) = @_;
33              
34 28 100       296 croak "Error: Class method new() can't be called on an object"
35             if ref $class;
36              
37 27 100 100     375 croak "Error: Argument to new() must be a hash reference"
38             if $args && ref $args ne 'HASH';
39              
40 26         211 my $self = { %default_args };
41              
42             # pick up any specified arguments;
43 26         2644 for my $key ( keys %default_args ) {
44 78 100       281 if ( exists $args->{$key} ) {
45 8         22 $self->{$key} = $args->{$key};
46             }
47             }
48              
49             # load up a parser
50 26         325 $self->{parser} = Pod::WikiDoc::Parser->new();
51              
52 26         528 return bless $self, $class;
53             }
54              
55              
56             sub convert {
57 22     22 1 21016 my ($self, $input_string) = @_;
58              
59 22 100       279 croak "Error: Argument to convert() must be a scalar"
60             if ( ref \$input_string ne 'SCALAR' );
61              
62 21         190 my $input_fh = IO::String->new( $input_string );
63 21         1345 my $output_fh = IO::String->new();
64 21         669 _filter_podfile( $self, $input_fh, $output_fh );
65              
66 21         37 return ${ $output_fh->string_ref() };
  21         101  
67             }
68              
69              
70             sub filter {
71 27     27 1 80029 my ( $self, $args_ref ) = @_;
72              
73 27 100 66     523 croak "Error: Argument to filter() must be a hash reference"
74             if defined $args_ref && ref($args_ref) ne 'HASH';
75             # setup input
76 26         53 my $input_fh;
77 26 50 66     386 if ( ! $args_ref->{input} ) {
    100 66        
    100 66        
78 0         0 $input_fh = \*STDIN;
79             }
80             elsif ( ( blessed $args_ref->{input} && $args_ref->{input}->isa('GLOB') )
81             || ( ref $args_ref->{input} eq 'GLOB' )
82             || ( ref \$args_ref->{input} eq 'GLOB' ) ) {
83             # filehandle or equivalent
84 13         290 $input_fh = $args_ref->{input};
85             }
86             elsif ( ref \$args_ref->{input} eq 'SCALAR' ) {
87             # filename
88 12 100       472 open( $input_fh, "<", $args_ref->{input} )
89             or croak "Error: Couldn't open input file '$args_ref->{input}': $!";
90             }
91             else {
92 1         97 croak "Error: 'input' parameter for filter() must be a filename or filehandle"
93             }
94              
95             # setup output
96 24         56 my $output_fh;
97 24 50 66     280 if ( ! $args_ref->{output} ) {
    100 66        
    100 66        
98 0         0 $output_fh = \*STDOUT;
99             }
100             elsif ( ( blessed $args_ref->{output} && $args_ref->{output}->isa('GLOB') )
101             || ( ref $args_ref->{output} eq 'GLOB' )
102             || ( ref \$args_ref->{output} eq 'GLOB' ) ) {
103             # filehandle or equivalent
104 11         190 $output_fh = $args_ref->{output};
105             }
106             elsif ( ref \$args_ref->{output} eq 'SCALAR' ) {
107             # filename
108 12 100       701 open( $output_fh, ">", $args_ref->{output} )
109             or croak "Error: Couldn't open output file '$args_ref->{output}': $!";
110             }
111             else {
112 1         106 croak "Error: 'output' parameter for filter() must be a filename or filehandle"
113             }
114              
115 22         97 _filter_podfile( $self, $input_fh, $output_fh );
116 22         2014 return;
117             }
118              
119              
120             sub format { ## no critic
121 117     117 1 108084 my ($self, $wikitext) = @_;
122              
123 117 100       815 croak "Error: Argument to format() must be a scalar"
124             if ( ref \$wikitext ne 'SCALAR' );
125              
126 116         1435 my $wiki_tree = $self->{parser}->WikiDoc( $wikitext ) ;
127 116         2431 for my $node ( @$wiki_tree ) {
128 193 50       812 undef $node if ! ref $node;
129             }
130              
131 116         673 return _wiki2pod( $wiki_tree, $self->{keywords} );
132             }
133              
134             #--------------------------------------------------------------------------#
135             # PRIVATE METHODS
136             #--------------------------------------------------------------------------#
137              
138             #--------------------------------------------------------------------------#
139             # _comment_block_regex
140             #
141             # construct a regex dynamically for the right comment prefix
142             #--------------------------------------------------------------------------#
143              
144             sub _comment_block_regex {
145 101     101   170 my ( $self ) = @_;
146 101         235 my $length = $self->{comment_prefix_length};
147 101         1027 return qr/\A#{$length}(?:\s(.*))?\z/ms;
148             }
149              
150             #--------------------------------------------------------------------------#
151             # _input_iterator
152             #
153             # return an iterator that streams a filehandle. Action arguments:
154             # 'peek' -- lookahead at the next line without consuming it
155             # 'next' and 'drop' -- synonyms to consume and return the next line
156             #--------------------------------------------------------------------------#
157              
158             sub _input_iterator {
159 55     55   115 my ($self, $fh) = @_;
160 55         93 my @head;
161             return sub {
162 1433     1433   1804 my ($action) = @_;
163 1433 100 66     4228 if ($action eq 'peek') {
    50          
164 810 100       3520 push @head, scalar <$fh> unless @head;
165 810         8898 return $head[0];
166             }
167             elsif ( $action eq 'drop' || $action eq 'next' ) {
168 623 50       2577 return shift @head if @head;
169 0         0 return scalar <$fh>;
170             }
171             else {
172 0         0 croak "Unrecognized iterator action '$action'\n";
173             }
174             }
175 55         414 }
176              
177             #--------------------------------------------------------------------------#
178             # _exhaust_iterator
179             #
180             # needed to help abort processing
181             #--------------------------------------------------------------------------#
182              
183             sub _exhaust_iterator {
184 0     0   0 my ($self, $iter) = @_;
185 0         0 1 while $iter->();
186 0         0 return;
187             }
188              
189             #--------------------------------------------------------------------------#
190             # _output_iterator
191             #
192             # returns an output "iterator" that streams to a filehandle. Inputs
193             # are array refs of the form [ $FORMAT, @LINES ]. Format 'pod' is
194             # printed to the filehandle immediately. Format 'wikidoc' is accumulated
195             # until the next 'pod' then converted to wikidoc and printed to the file
196             # handle
197             #--------------------------------------------------------------------------#
198              
199             sub _output_iterator {
200 55     55   99 my ($self, $fh) = @_;
201 55         79 my @wikidoc;
202             return sub {
203 473     473   632 my ($chunk) = @_;
204 473 100       1148 if ($chunk eq 'flush') {
205 55 100       144 print {$fh} $self->format( join(q{}, splice(@wikidoc,0) ) )
  16         133  
206             if @wikidoc;
207 55         657 return;
208             }
209 418 50       904 return unless ref($chunk) eq 'ARRAY';
210 418         626 my ($format, @lines) = grep { defined $_ } @$chunk;
  868         1902  
211 418 100       943 if ( $format eq 'wikidoc' ) {
    50          
212 211         328 push @wikidoc, @lines;
213             }
214             elsif ( $format eq 'pod' ) {
215 207 100       401 print {$fh} $self->format( join(q{}, splice(@wikidoc,0) ) )
  35         275  
216             if @wikidoc;
217 207         1678 print {$fh} @lines;
  207         555  
218             }
219 418         3461 return;
220             }
221 55         325 }
222              
223             #--------------------------------------------------------------------------#
224             # _filter_podfile()
225             #
226             # extract Pod from input and pass through to output, converting any wikidoc
227             # markup to Pod in the process
228             #--------------------------------------------------------------------------#
229              
230             my $BLANK_LINE = qr{\A \s* \z}xms;
231             my $NON_BLANK_LINE = qr{\A \s* \S }xms;
232             my $FORMAT_LABEL = qr{:? [-a-zA-Z0-9_]+}xms;
233             my $POD_CMD = qr{\A =[a-zA-Z]+}xms;
234             my $BEGIN = qr{\A =begin \s+ ($FORMAT_LABEL) \s* \z}xms;
235             my $END = qr{\A =end \s+ ($FORMAT_LABEL) \s* \z}xms;
236             my $FOR = qr{\A =for \s+ ($FORMAT_LABEL) [ \t]* (.*) \z}xms;
237             my $POD = qr{\A =pod \s* \z}xms;
238             my $CUT = qr{\A =cut \s* \z}xms;
239              
240             sub _filter_podfile {
241 55     55   19634 my ($self, $input_fh, $output_fh) = @_;
242              
243             # open output with tag and Pod marker
244 55         421 print $output_fh
245             "# Generated by Pod::WikiDoc version $Pod::WikiDoc::VERSION\n\n";
246 55         825 print $output_fh "=pod\n\n";
247              
248             # setup iterators
249 55         745 my $in_iter = $self->_input_iterator( $input_fh );
250 55         255 my $out_iter = $self->_output_iterator( $output_fh );
251              
252             # starting filter mode is code
253 55         237 $self->_filter_code( $in_iter, $out_iter );
254 55         147 $out_iter->('flush');
255              
256 55         1069 return;
257             }
258              
259             #--------------------------------------------------------------------------#
260             # _filter_code
261             #
262             # we need a "cutting" flag -- if we got here from a =cut, then we return to
263             # caller ( pod or format ) when we see pod. Otherwise we're just starting
264             # and need to start a new pod filter when we see pod
265             #
266             # perlpodspec says starting Pod with =cut is an error and that we
267             # *must* halt parsing and *should* issue a warning. Here we might be
268             # far down the call stack and don't want to just return where the caller
269             # might continue processing. To avoid this, we exhaust the input first.
270             #--------------------------------------------------------------------------#
271              
272             sub _filter_code {
273 89     89   190 my ($self, $in_iter, $out_iter, $cutting) = @_;
274 89         302 my $CBLOCK = _comment_block_regex($self);
275 89         342 CODE: while ( defined( my $peek = $in_iter->('peek') ) ) {
276 111 100       612 $peek =~ $CBLOCK && do {
277 12         150 $self->_filter_cblock( $in_iter, $out_iter );
278 12         38 next CODE;
279             };
280 99 50       434 $peek =~ $CUT && do {
281 0         0 warn "Can't start Pod with '$peek'\n";
282 0         0 $self->_exhaust_iterator( $in_iter );
283 0         0 last CODE;
284             };
285 99 100       536 $peek =~ $POD_CMD && do {
286 44 100       124 last CODE if $cutting;
287 43         186 $self->_filter_pod( $in_iter, $out_iter );
288 43         146 next CODE;
289             };
290 55         69 do { $in_iter->('drop') };
  55         105  
291             }
292 89         262 return;
293             }
294              
295             #--------------------------------------------------------------------------#
296             # _filter_pod
297             #
298             # Pass through lines to the output iterators, but flag wikidoc lines
299             # differently so that they can be converted on output
300             #
301             # If we find an =end that is out of order, perlpodspec says we *must* warn
302             # and *may* halt. Instead of halting, we return to the caller in the
303             # hopes that an earlier format might match this =end.
304             #--------------------------------------------------------------------------#
305              
306             sub _filter_pod {
307 43     43   80 my ($self, $in_iter, $out_iter) = @_;
308 43         99 my @format = (); # no format to start
309             # process the pod block -- recursing as necessary
310 43         100 LINE: while ( defined( my $peek = $in_iter->('peek') ) ) {
311 508 100       1928 $peek =~ $POD && do {
312 13         48 $in_iter->('drop');
313 13         46 next LINE;
314             };
315 495 100       1905 $peek =~ $CUT && do {
316 34         88 $in_iter->('drop');
317 34         180 $self->_filter_code( $in_iter, $out_iter, 1 );
318 34         112 next LINE;
319             };
320 461 100       1487 $peek =~ $FOR && do {
321 21         423 $self->_filter_for( $in_iter, $out_iter );
322 21         76 next LINE;
323             };
324 440 100       1465 $peek =~ $END && do {
325 38 50       209 if ( ! @format ) {
    50          
    100          
326 0         0 warn "Error: '$peek' doesn't match any '=begin $1'\n";
327 0         0 $in_iter->('drop');
328 0         0 next LINE;
329             }
330             elsif ( $format[-1] ne $1 ) {
331 0         0 warn "Error: '$peek' doesn't match '=begin $format[-1]'\n";
332 0         0 pop @format; # try an earlier format
333 0         0 redo LINE;
334             }
335             elsif ( $format[-1] eq 'wikidoc' ) {
336 25         40 pop @format;
337 25         57 $in_iter->('drop');
338 25         72 next LINE;
339             }
340             else {
341 13         27 pop @format;
342             # and let it fall through to the output iterator
343             }
344             };
345 415 100       1297 $peek =~ $BEGIN && do {
346 39 100       128 if ( $1 eq 'wikidoc' ) {
347 26         60 push @format, 'wikidoc';
348 26         71 $in_iter->('drop');
349 26         88 next LINE;
350             }
351             else {
352 13         35 push @format, $1;
353             # and let it fall through to the output iterator
354             }
355             };
356 389         383 do {
357 389 100 100     1966 my $out_type =
358             ( @format && $format[-1] eq 'wikidoc' ) ? 'wikidoc' : 'pod' ;
359 389         689 $out_iter->( [ $out_type, $in_iter->('next') ] )
360             };
361             }
362 43         106 return;
363             }
364              
365             #--------------------------------------------------------------------------#
366             # _filter_for
367             #--------------------------------------------------------------------------#
368              
369             sub _filter_for {
370 21     21   51 my ($self, $in_iter, $out_iter) = @_;
371 21         52 my $for_line = $in_iter->('next');
372 21         142 my ($format, $rest) = $for_line =~ $FOR;
373 21   50     67 $rest ||= "\n";
374              
375 21 100       80 my @lines = ( $format eq 'wikidoc' ? $rest : $for_line );
376              
377 21         54 LINE: while ( defined( my $peek = $in_iter->('peek') ) ) {
378 25 100       160 $peek =~ $BLANK_LINE && do {
379 16         42 last LINE;
380             };
381 9         14 do {
382 9         26 push @lines, $in_iter->('next');
383             };
384             }
385 21 100       62 if ($format eq 'wikidoc' ) {
386 8         20 $in_iter->('drop'); # wikidoc will append \n
387             }
388             else {
389 13         34 push @lines, $in_iter->('next');
390             }
391 21 100       66 my $out_type = $format eq 'wikidoc' ? 'wikidoc' : 'pod' ;
392 21         74 $out_iter->( [ $out_type, @lines ] );
393 21         73 return;
394             }
395              
396             #--------------------------------------------------------------------------#
397             # _filter_cblock
398             #--------------------------------------------------------------------------#
399              
400             sub _filter_cblock {
401 12     12   32 my ($self, $in_iter, $out_iter) = @_;
402 12 50       80 my @lines = ($1 ? $1 : "\n"); ## no critic
403 12         37 $in_iter->('next');
404 12         34 my $CBLOCK = _comment_block_regex($self);
405 12         40 LINE: while ( defined( my $peek = $in_iter->('peek') ) ) {
406 27 100       223 last LINE if $peek !~ $CBLOCK;
407 18 100       98 push @lines, ($1 ? $1 : "\n");
408 18         106 $in_iter->('next');
409             }
410 12 100       84 $out_iter->( [ 'wikidoc', @lines ] ) if $self->{comment_blocks};
411 12         51 return;
412             }
413              
414              
415             #--------------------------------------------------------------------------#
416             # Translation functions and tables
417             #--------------------------------------------------------------------------#
418              
419             #--------------------------------------------------------------------------#
420             # Tables for formatting
421             #--------------------------------------------------------------------------#
422              
423             # Used in closure for counting numbered lists
424             my $numbered_bullet;
425              
426             # Text to print at start of entity from parse tree, or a subroutine
427             # to generate the text programmatically
428             my %opening_of = (
429             Paragraph => q{},
430             Unordered_List => "=over\n\n",
431             Ordered_List => sub { $numbered_bullet = 1; return "=over\n\n" },
432             Preformat => q{},
433             Header => sub {
434             my $node = shift;
435             my $level = $node->{level} > 4
436             ? 4 : $node->{level};
437             return "=head$level "
438             },
439             Bullet_Item => "=item *\n\n",
440             Numbered_Item => sub {
441             return "=item " . $numbered_bullet++
442             . ".\n\n"
443             },
444             Indented_Line => q{ },
445             Plain_Line => q{},
446             Empty_Line => q{ },
447             Parens => "(",
448             RegularText => q{},
449             EscapedChar => q{},
450             WhiteSpace => q{},
451             InlineCode => "C<<< ",
452             BoldText => 'B<',
453             ItalicText => 'I<',
454             KeyWord => q{},
455             LinkContent => 'L<',
456             LinkLabel => q{},
457             LinkTarget => q{},
458             );
459              
460             # Text to print at end of entity from parse tree, or a subroutine
461             # to generate the text programmatically
462             my %closing_of = (
463             Paragraph => "\n",
464             Unordered_List => "=back\n\n",
465             Ordered_List => "=back\n\n",
466             Preformat => "\n",
467             Header => "\n\n",
468             Bullet_Item => "\n\n",
469             Numbered_Item => "\n\n",
470             Indented_Line => "\n",
471             Plain_Line => "\n",
472             Empty_Line => "\n",
473             Parens => ")",
474             RegularText => q{},
475             EscapedChar => q{},
476             WhiteSpace => q{},
477             InlineCode => " >>>",
478             BoldText => ">",
479             ItalicText => ">",
480             KeyWord => q{},
481             LinkContent => q{>},
482             LinkLabel => q{|},
483             LinkTarget => q{},
484             );
485              
486             # Subroutine to handle actual raw content from different node types
487             # from the parse tree
488             my %content_handler_for = (
489             RegularText => \&_escape_pod,
490             Empty_Line => sub { q{} },
491             KeyWord => \&_keyword_expansion,
492             );
493              
494             # Table of character to E<> code conversion
495             my %escape_code_for = (
496             q{>} => "E",
497             q{<} => "E",
498             q{|} => "E",
499             q{/} => "E",
500             );
501              
502             # List of characters that need conversion
503             my $specials = join q{}, keys %escape_code_for;
504              
505             #--------------------------------------------------------------------------#
506             # _escape_pod()
507             #
508             # After removing backslash escapes from a text string, translates characters
509             # that must be escaped in Pod <, >, |, and / to their Pod E<> code equivalents
510             #
511             #--------------------------------------------------------------------------#
512              
513             sub _escape_pod {
514              
515 674     674   1114 my $node = shift;
516              
517 674         1051 my $input_text = $node->{content};
518              
519             # remove backslash escaping
520 674         1120 $input_text =~ s{ \\(.) }
521             {$1}gxms;
522              
523             # replace special symbols with corresponding escape code
524 674         3006 $input_text =~ s{ ( [$specials] ) }
525             {$escape_code_for{$1}}gxms;
526              
527 674         1866 return $input_text;
528             }
529              
530             #--------------------------------------------------------------------------#
531             # _keyword_expansion
532             #
533             # Given a keyword, return the corresponding value from the keywords
534             # hash or the keyword itself
535             #--------------------------------------------------------------------------#
536              
537             sub _keyword_expansion {
538 8     8   12 my ($node, $keywords) = @_;
539 8         18 my $key = $node->{content};
540 8         20 my $value = $keywords->{$key};
541 8 100       103 return defined $value ? $value : q{%%} . $key . q{%%} ;
542             }
543              
544              
545             #--------------------------------------------------------------------------#
546             # _translate_wikidoc()
547             #
548             # given an array of wikidoc lines, joins them and runs them through
549             # the formatter
550             #--------------------------------------------------------------------------#
551              
552             sub _translate_wikidoc {
553 0     0   0 my ( $self, $wikidoc_ref ) = @_;
554 0         0 return $self->format( join q{}, @$wikidoc_ref );
555             }
556              
557             #--------------------------------------------------------------------------#
558             # _wiki2pod()
559             #
560             # recursive function that walks a Pod::WikiDoc::Parser tree and generates
561             # a string with the corresponding Pod
562             #--------------------------------------------------------------------------#
563              
564             sub _wiki2pod {
565 388     388   1020 my ($nodelist, $keywords, $insert_space) = @_;
566 388         5159 my $result = q{};
567 388         1064 for my $node ( @$nodelist ) {
568             # XXX print "$node\n" if ref $node ne 'HASH';
569 1597         4031 my $opening = $opening_of{ $node->{type} };
570 1597         3091 my $closing = $closing_of{ $node->{type} };
571              
572 1597 100       4881 $result .= ref $opening eq 'CODE' ? $opening->($node) : $opening;
573 1597 100       3776 if ( ref $node->{content} eq 'ARRAY' ) {
574 272 100       1877 $result .= _wiki2pod(
575             $node->{content},
576             $keywords,
577             $node->{type} eq 'Preformat' ? 1 : 0
578             );
579             }
580             else {
581 1325         2365 my $handler = $content_handler_for{ $node->{type} };
582 1325 100       6155 $result .= defined $handler
583             ? $handler->( $node, $keywords ) : $node->{content}
584             ;
585             }
586 1597 50       4758 $result .= ref $closing eq 'CODE' ? $closing->($node) : $closing;
587             }
588 388         10837 return $result;
589             }
590              
591             1; #this line is important and will help the module return a true value
592              
593              
594             =pod
595              
596             =head1 NAME
597              
598             Pod::WikiDoc - Generate Pod from inline wiki style text
599              
600             =head1 VERSION
601              
602             version 0.20
603              
604             =head1 SYNOPSIS
605              
606             In a source file, Pod format-block style:
607              
608             =begin wikidoc
609            
610             = POD FORMAT-BLOCK STYLE
611            
612             Write documentation with *bold*, ~italic~ or {code}
613             markup. Create a link to [Pod::WikiDoc].
614             Substitute for user-defined %%KEYWORD%%.
615            
616             Indent for verbatim paragraphs
617            
618             * bullet
619             * point
620             * list
621            
622             0 sequentially
623             0 numbered
624             0 list
625            
626             =end wikidoc
627              
628             In a source file, wikidoc comment-block style:
629              
630             ### = WIKIDOC COMMENT-BLOCK STYLE
631             ###
632             ### Optionally, [Pod::WikiDoc] can extract from
633             ### specially-marked comment blocks
634              
635             Generate Pod from wikidoc, programmatically:
636              
637             use Pod::WikiDoc;
638             my $parser = Pod::WikiDoc->new( {
639             comment_blocks => 1,
640             keywords => { KEYWORD => "foo" },
641             } );
642             $parser->filter(
643             { input => "my_module.pm", output => "my_module.pod" }
644             );
645              
646             Generate Pod from wikidoc, via command line:
647              
648             $ wikidoc -c my_module.pm my_module.pod
649              
650             =head1 DESCRIPTION
651              
652             Pod works well, but writing it can be time-consuming and tedious. For example,
653             commonly used layouts like lists require numerous lines of text to make just
654             a couple of simple points. An alternative approach is to write documentation
655             in a wiki-text shorthand (referred to here as I) and use Pod::WikiDoc
656             to extract it and convert it into its corresponding Pod as a separate C<<< .pod >>>
657             file.
658              
659             Documentation written in wikidoc may be embedded in Pod format blocks, or,
660             optionally, in specially marked comment blocks. Wikidoc uses simple text-based
661             markup like wiki websites to indicate formatting and links. (See
662             L, below.)
663              
664             Pod::WikiDoc processes text files (or text strings) by extracting both
665             existing Pod and wikidoc, converting the wikidoc to Pod, and then writing
666             the combined document back to a file or standard output.
667              
668             Summary of major features of Pod::WikiDoc:
669              
670             =over
671              
672             =item *
673              
674             Extracts and converts wikidoc from Pod format blocks or special
675             wikidoc comment blocks
676              
677             =item *
678              
679             Extracts and preserves existing Pod
680              
681             =item *
682              
683             Provides bold, italic, code, and link markup
684              
685             =item *
686              
687             Substitutes user-defined keywords
688              
689             =item *
690              
691             Automatically converts special symbols in wikidoc to their
692             Pod escape equivalents, e.g. EEltE, EEgtE
693              
694             =item *
695              
696             Preserves other Pod escape sequences, e.g. EEeuroE
697              
698             =back
699              
700             In addition, Pod::WikiDoc provides a command-line utility, L,
701             to simplify wikidoc translation.
702              
703             See the L for more detailed usage examples,
704             including how to automate C<<< .pod >>> generation when using L.
705              
706             =head1 INTERFACE
707              
708             =head2 C<<< new >>>
709              
710             $parser = Pod::WikiDoc->new( \%args );
711              
712             Constructor for a new Pod::WikiDoc object. It takes a single, optional
713             argument: a hash reference with the following optional keys:
714              
715             =over
716              
717             =item *
718              
719             C<<< comment_blocks >>>: if true, Pod::WikiDoc will scan for wikidoc in comment
720             blocks. Default is false.
721              
722             =item *
723              
724             C<<< comment_prefix_length >>>: the number of leading sharp (#) symbols to
725             denote a comment block. Default is 3.
726              
727             =item *
728              
729             C<<< keywords >>>: a hash reference with keywords and values for keyword
730             substitution
731              
732             =back
733              
734             =head2 C<<< convert >>>
735              
736             my $pod_text = $parser->convert( $input_text );
737              
738             Given a string with valid Pod andEor wikidoc markup, filterEtranslate it to
739             Pod. This is really just a wrapper around C<<< filter >>> for working with
740             strings rather than files, and provides similar behavior, including adding
741             a 'Generated by' header.
742              
743             =head2 C<<< filter >>>
744              
745             $parser->filter( \%args );
746              
747             Filters from an input file for Pod and wikidoc, translating it to Pod
748             and writing it to an output file. The output file will be prefixed with
749             a 'Generated by' comment with the version of Pod::WikiDoc and timestamp,
750             as required by L.
751              
752             C<<< filter >>> takes a single, optional argument: a hash reference with
753             the following optional keys:
754              
755             =over
756              
757             =item *
758              
759             C<<< input >>>: a filename or filehandle to read from. Defaults to STDIN.
760              
761             =item *
762              
763             C<<< output >>>: a filename or filehandle to write to. If given a filename
764             and the file already exists, it will be clobbered. Defaults to STDOUT.
765              
766             =back
767              
768             =head2 C<<< format >>>
769              
770             my $pod_text = $parser->format( $wiki_text );
771              
772             Given a string with valid Pod andEor wikidoc markup, filterEtranslate it to
773             Pod. Unlike C<<< convert >>>, no 'Generated by' comment is added. This
774             function is used internally by Pod::WikiDoc, but is being made available
775             as a public method for users who want more granular control of the
776             translation process or who want to convert wikidoc to Pod for other
777             creative purposes using the Pod::WikiDoc engine.
778              
779             =head1 WIKIDOC MARKUP
780              
781             Pod::WikiDoc uses a wiki-style text markup, called wikidoc. It is heavily
782             influenced by L. Like other wiki markup, it has both block and
783             inline elements, which map directly to their Pod equivalents.
784              
785             Block elements include:
786              
787             =over
788              
789             =item *
790              
791             Headers
792              
793             =item *
794              
795             Verbatim text
796              
797             =item *
798              
799             Bullet lists
800              
801             =item *
802              
803             Numbered lists
804              
805             =item *
806              
807             Ordinary paragraphs
808              
809             =back
810              
811             Block elements should be separated by a blank line (though Pod::WikiDoc
812             will do the right thing in many cases if you don't).
813              
814             Inline elements include:
815              
816             =over
817              
818             =item *
819              
820             Bold
821              
822             =item *
823              
824             Italic
825              
826             =item *
827              
828             Code
829              
830             =item *
831              
832             Link
833              
834             =item *
835              
836             Escape code
837              
838             =item *
839              
840             Keywords
841              
842             =back
843              
844             All text except that found in verbatim text, code markup or keywords is
845             transformed to convert special Pod characters to Pod escape code markup:
846             EEltE, EEgtE, EEsolE, EEverbarE. Inline markup can be escaped with
847             a backslash (\). Including a literal backslash requires a double-backslash
848             (\\).
849              
850             =head2 Headers
851              
852             Headers are indicated with one or more equals signs followed by whitespace in
853             the first column. The number of equals signs indicates the level of the
854             header (the maximum is four). Headers can not span multiple lines.
855              
856             = header level 1
857            
858             == header level 2
859              
860             =head2 Verbatim text
861              
862             Verbatim text is indicated with leading whitespace in each line of text,
863             just as with Pod.
864              
865             #<--- first column
866            
867             sub verbatim {}
868              
869             =head2 Bullet lists
870              
871             Bullet lists are indicated with an asterisk in the first column followed by
872             whitespace. Bullet lists can span multiple lines. Lines after the first
873             should not have an asterisk or be indented.
874              
875             * First item in the list
876             * Second item in the list
877             on multiple lines
878             * Third item in the list
879              
880             =head2 Numbered lists
881              
882             Numbered lists work just like numbered lists, but with a leading 0 followed
883             by whitespace.
884              
885             0 First item in the list
886             0 Second item in the list
887             on multiple lines
888             0 Third item in the list
889              
890             =head2 Ordinary paragraphs
891              
892             Ordinary paragraphs consist of one or more lines of text that do not match
893             the criteria of other blocks. Paragraphs are terminated with a empty line.
894              
895             This is an ordinary paragraph that
896             spans multiple lines.
897              
898             =head2 Bold markup
899              
900             Bold text is indicated by bracketing with asterisks. Bold markup must
901             begin at a whitespace boundary, the start of a line, or the inside of
902             other markup.
903              
904             This shows *bold* text.
905              
906             =head2 Italic markup
907              
908             Italic text is indicated by bracketing with tildes. Italic markup must
909             begin at a whitespace boundary, the start of a line, or the inside of
910             other markup.
911              
912             This shows ~italic~ text.
913              
914             =head2 Code markup
915              
916             Code (monospaced) text is indicated by bracketing with matched braces. Code
917             markup must begin at a whitespace boundary, the start of a line, or the inside
918             of other markup. Brackets should nest properly with code.
919              
920             This shows {code} text. It can surround text
921             with brackets like this: { $data{ $id } }
922              
923             =head2 Link markup
924              
925             Link text is indicated by bracketing with square brackets. As with Pod, link
926             text may include a vertical bar to separate display text from the link itself.
927             Link markup must begin at a whitespace boundary, the start of a line, or the
928             inside of other markup.
929              
930             This is an ordinary [Pod::WikiDoc] link.
931             This is a [way to ~markup~ links|Pod::WikiDoc] with display text
932             Hypertext links look like this: [http://www.google.com/]
933              
934             =head2 Escape code markup
935              
936             Pod-style escape text is passed through as normal to support international
937             or other unusual characters.
938              
939             This is the euro symbol: E
940              
941             =head2 Keyword markup
942              
943             Text surrounded by double-percent signs is treated as a keyword for expansion.
944             The entire expression will be replaced with the value of the keyword from the
945             hash provided when the parser is created with C<<< new() >>>. If the keyword is
946             unknown or the value is undefined, the keyword will be passed through
947             unchanged.
948              
949             This is version %%VERSION%%
950              
951             =head1 DIAGNOSTICS
952              
953             =over
954              
955             =item *
956              
957             C<<< Error: Argument to convert() must be a scalar >>>
958              
959             =item *
960              
961             C<<< Error: Argument to filter() must be a hash reference >>>
962              
963             =item *
964              
965             C<<< Error: Argument to format() must be a scalar >>>
966              
967             =item *
968              
969             C<<< Error: Argument to new() must be a hash reference >>>
970              
971             =item *
972              
973             C<<< Error: Class method new() can't be called on an object >>>
974              
975             =item *
976              
977             C<<< Error: Couldn't open input file 'FILENAME' >>>
978              
979             =item *
980              
981             C<<< Error: Couldn't open output file 'FILENAME' >>>
982              
983             =item *
984              
985             C<<< Error: 'input' parameter for filter() must be a filename or filehandle >>>
986              
987             =item *
988              
989             C<<< Error: 'output' parameter for filter() must be a filename or filehandle >>>
990              
991             =back
992              
993             =head1 INCOMPATIBILITIES
994              
995             =over
996              
997             =item *
998              
999             Default prefix length for wikidoc comment-blocks conflicts with
1000             L. Change the C<<< comment_prefix_length >>> argument to C<<< new >>> in
1001             Pod::WikiDoc or the level of 'smartness' in L to avoid the
1002             conflict.
1003              
1004             =back
1005              
1006             =over
1007              
1008             =item *
1009              
1010             Module::Build before 0.28 does not look in external C<<< .pod >>> files
1011             to generate a C<<< README >>> with the C<<< create_readme >>> option or to find a module
1012             abstract. Set the abstract manually in the C<<< Build.PL >>> file with the
1013             C<<< dist_abstract >>> option.
1014              
1015             =back
1016              
1017             =for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders
1018              
1019             =head1 SUPPORT
1020              
1021             =head2 Bugs / Feature Requests
1022              
1023             Please report any bugs or feature requests through the issue tracker
1024             at L.
1025             You will be notified automatically of any progress on your issue.
1026              
1027             =head2 Source Code
1028              
1029             This is open source software. The code repository is available for
1030             public review and contribution under the terms of the license.
1031              
1032             L
1033              
1034             git clone https://github.com/dagolden/pod-wikidoc.git
1035              
1036             =head1 AUTHOR
1037              
1038             David A Golden
1039              
1040             =head1 COPYRIGHT AND LICENSE
1041              
1042             This software is Copyright (c) 2012 by David A Golden.
1043              
1044             This is free software, licensed under:
1045              
1046             The Apache License, Version 2.0, January 2004
1047              
1048             =cut
1049              
1050              
1051             __END__