File Coverage

blib/lib/Pod/WordML.pm
Criterion Covered Total %
statement 192 252 76.1
branch 24 42 57.1
condition 3 15 20.0
subroutine 72 109 66.0
pod 11 94 11.7
total 302 512 58.9


line stmt bran cond sub pod time code
1             package Pod::WordML;
2 2     2   6929 use strict;
  2         6  
  2         89  
3 2     2   12 use base 'Pod::PseudoPod';
  2         3  
  2         1947  
4              
5 2     2   110330 use warnings;
  2         4  
  2         80  
6 2     2   10 no warnings;
  2         5  
  2         83  
7              
8 2     2   2385 use subs qw();
  2         68  
  2         56  
9 2     2   11 use vars qw($VERSION);
  2         5  
  2         95  
10              
11 2     2   11 use Carp;
  2         4  
  2         1080  
12              
13             $VERSION = '0.16';
14              
15             =encoding utf8
16              
17             =head1 NAME
18              
19             Pod::WordML - Turn Pod into Microsoft Word's WordML
20              
21             =head1 SYNOPSIS
22              
23             use Pod::WordML;
24              
25             =head1 DESCRIPTION
26              
27             ***THIS IS ALPHA SOFTWARE. MAJOR PARTS WILL CHANGE***
28              
29             I wrote just enough of this module to get my job done, and I skipped every
30             part of the specification I didn't need while still making it flexible enough
31             to handle stuff later.
32              
33             =head2 The style information
34              
35             I don't handle all of the complexities of styles, defining styles, and
36             all that other stuff. There are methods to return style names, and you
37             can override those in a subclass.
38              
39             =cut
40              
41             =over 4
42              
43             =item document_header
44              
45             This is the start of the document that defines all of the styles. You'll need
46             to override this. You can take this directly from
47              
48             =cut
49              
50             sub document_header
51             {
52 9     9 1 26 my $string = <<'XML';
53            
54            
55            
56            
57             XML
58              
59 9         32 $string .= $_[0]->fonts . $_[0]->lists . $_[0]->styles;
60              
61 9         40 $string .= <<'XML';
62            
63             XML
64             }
65              
66            
67 9     9 0 35 sub fonts { '' }
68 9     9 0 35 sub lists { '' }
69 9     9 0 24 sub styles { '' }
70              
71             =item document_footer
72              
73             =cut
74              
75             sub document_footer
76             {
77 9     9 1 17 <<'XML';
78            
79            
80             XML
81             }
82            
83             =item head1_style, head2_style, head3_style, head4_style
84              
85             The paragraph styles to use with each heading level. By default these are
86             C, and so on.
87              
88             =cut
89              
90 0     0 0 0 sub head0_style { 'Heading0' }
91 3     3 1 14 sub head1_style { 'Heading1' }
92 1     1 1 5 sub head2_style { 'Heading2' }
93 1     1 1 4 sub head3_style { 'Heading3' }
94 0     0 1 0 sub head4_style { 'Heading4' }
95              
96             =item normal_paragraph_style
97              
98             The paragraph style for normal Pod paragraphs. You don't have to use this
99             for all normal paragraphs, but you'll have to override and extend more things
100             to get everything just how you like. You'll need to override C to
101             get more variety.
102              
103             =cut
104              
105 16     16 0 33 sub normal_para_style { 'NormalParagraphStyle' }
106              
107             =item bullet_paragraph_style
108              
109             Like C, but for paragraphs sections under C<=item>
110             sections.
111              
112             =cut
113              
114 4     4 0 11 sub first_item_para_style { 'FirstItemParagraphStyle' }
115 9     9 0 22 sub middle_item_para_style { 'MiddleItemParagraphStyle' }
116 0     0 0 0 sub last_item_para_style { 'LastItemParagraphStyle' }
117 4     4 0 6 sub item_subpara_style { 'ItemSubParagraphStyle' }
118              
119             =item code_paragraph_style
120              
121             Like C, but for verbatim sections. To get more fancy
122             handling, you'll need to override C and C.
123              
124             =cut
125              
126 0     0 0 0 sub code_para_style { 'CodeParagraphStyle' }
127 0     0 0 0 sub single_code_line_style { 'CodeParagraphStyle' }
128              
129             =item inline_code_style
130              
131             The character style that goes with C<< CE> >>.
132              
133             =cut
134              
135 0     0 1 0 sub inline_code_style { 'CodeCharacterStyle' }
136              
137             =item inline_url_style
138              
139             The character style that goes with C<< UEE >>.
140              
141             =cut
142              
143 0     0 1 0 sub inline_url_style { 'URLCharacterStyle' }
144              
145             =item inline_italic_style
146              
147             The character style that goes with C<< IE> >>.
148              
149             =cut
150              
151 0     0 1 0 sub inline_italic_style { 'ItalicCharacterStyle' }
152              
153             =item inline_bold_style
154              
155             The character style that goes with C<< BE> >>.
156              
157             =cut
158              
159 0     0 1 0 sub inline_bold_style { 'BoldCharacterStyle' }
160              
161             =back
162              
163             =head2 The Pod::Simple mechanics
164              
165             Everything else is the same stuff from C.
166              
167             =cut
168 2     2   2486 use Data::Dumper;
  2         15809  
  2         7378  
169 9     9 1 26577 sub new { my $self = $_[0]->SUPER::new() }
170              
171             sub emit
172             {
173 152     152 0 202 print {$_[0]->{'output_fh'}} $_[0]->{'scratch'};
  152         607  
174 152         1456 $_[0]->{'scratch'} = '';
175 152         1701 return;
176             }
177              
178             sub get_pad
179             {
180             # flow elements first
181 50 50   50 0 205 if( $_[0]{module_flag} ) { 'scratch' }
  0 50       0  
182 0         0 elsif( $_[0]{url_flag} ) { 'url_text' }
183             # then block elements
184             # finally the default
185 50         134 else { 'scratch' }
186             }
187              
188             sub start_Document
189             {
190 9     9 0 15825 $_[0]->{'scratch'} .= $_[0]->document_header; $_[0]->emit;
  9         44  
191             }
192              
193             sub end_Document
194             {
195 9     9 0 548 $_[0]->{'scratch'} .= $_[0]->document_footer; $_[0]->emit;
  9         26  
196             }
197              
198             =begin comment
199              
200            
201            
202            
203            
204            
205             This is an h1
206            
207            
208              
209             =cut
210              
211             sub _header_start
212             {
213 5     5   10 my( $self, $style, $level ) = @_;
214            
215 5         9 my $format = '
216            
217            
218            
219            
220             ';
221              
222 5         30 $self->{scratch} = sprintf $format, $style;
223 5         14 $self->emit;
224             }
225            
226             sub _header_end
227             {
228 5     5   13 '
229            
230            
231             ';
232             }
233              
234 0     0 0 0 sub start_head0 { $_[0]->_header_start( $_[0]->head0_style, 0 ); }
235 0     0 0 0 sub end_head0 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  0         0  
236            
237 3     3 0 598 sub start_head1 { $_[0]->_header_start( $_[0]->head1_style, 1 ); }
238 3     3 0 48 sub end_head1 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  3         10  
239              
240 1     1 0 162 sub start_head2 { $_[0]->_header_start( $_[0]->head2_style, 2 ); }
241 1     1 0 16 sub end_head2 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  1         5  
242              
243 1     1 0 165 sub start_head3 { $_[0]->_header_start( $_[0]->head3_style, 3 ); }
244 1     1 0 13 sub end_head3 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  1         4  
245              
246 0     0 0 0 sub start_head4 { $_[0]->_header_start( $_[0]->head4_style, 4 ); }
247 0     0 0 0 sub end_head4 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  0         0  
248              
249             sub end_non_code_text
250             {
251 42     42 0 48 my $self = shift;
252            
253 42         71 $self->make_curly_quotes;
254            
255 42         93 $self->emit;
256             }
257              
258             =begin comment
259              
260            
261            
262            
263             This is a line in a paragraph
264            
265            
266            
267            
268            
269             This is another line in another paragraph
270            
271            
272            
273            
274            
275            
276            
277              
278             =end comment
279              
280             =cut
281              
282             sub make_para
283             {
284 7     7 0 9 my( $self, $style, $para ) = @_;
285            
286 7         15 $self->{'scratch'} =
287             qq|
288            
289            
290            
291            
292             $para
293            
294            
295             |;
296            
297 7         28 $self->emit;
298             }
299            
300             sub start_Para
301             {
302 33     33 0 3239 my $self = shift;
303            
304             # it would be nice to take this through make_para
305 33         37 my $style = do {
306 33 100       104 if( $self->{in_item} )
    100          
307             {
308 13 100       34 if( $self->{item_count} == 1 ) { $self->first_item_para_style }
  4         26  
309 9         24 else { $self->middle_item_para_style }
310             }
311 4         13 elsif( $self->{in_item_list} ) { $self->item_subpara_style }
312 16         53 else { $self->normal_para_style }
313             };
314            
315 33         94 $self->{'scratch'} =
316             qq|
317            
318            
319            
320            
321             |;
322            
323 33 100       104 $self->{'scratch'} .= "\x{25FE} " if $self->{in_item};
324            
325 33         76 $self->emit;
326            
327 33         109 $self->{'in_para'} = 1;
328             }
329              
330              
331             sub end_Para
332             {
333 33     33 0 256 my $self = shift;
334            
335 33         63 $self->{'scratch'} .= '
336            
337            
338             ';
339              
340 33         68 $self->emit;
341            
342 33         79 $self->end_non_code_text;
343              
344 33         79 $self->{'in_para'} = 0;
345             }
346              
347 0     0 0 0 sub start_figure { }
348              
349 0     0 0 0 sub end_figure { }
350              
351 1     1 0 5 sub first_code_line_style { 'first code line' }
352 5     5 0 11 sub middle_code_line_style { 'middle code line' }
353 1     1 0 2 sub last_code_line_style { 'last code line' }
354              
355 1     1 0 4 sub first_code_line { $_[0]->make_para( $_[0]->first_code_line_style, $_[1] ) }
356 5     5 0 11 sub middle_code_line { $_[0]->make_para( $_[0]->middle_code_line_style, $_[1] ) }
357 1     1 0 4 sub last_code_line { $_[0]->make_para( $_[0]->last_code_line_style, $_[1] ) }
358            
359             sub start_Verbatim
360             {
361 1     1 0 22 $_[0]{'in_verbatim'} = 1;
362             }
363              
364             sub end_Verbatim
365             {
366 1     1 0 9 my $self = shift;
367            
368             # get rid of all but one trailing newline
369 1         8 $self->{'scratch'} =~ s/\s+\z//;
370            
371 1         6 chomp( my @lines = split m/^/m, $self->{'scratch'} );
372 1         3 $self->{'scratch'} = '';
373            
374 1         3 @lines = map { s/
  7         7  
  7         11  
375            
376 1 50       6 if( @lines == 1 )
    50          
377             {
378 0         0 $self->make_para( $self->single_code_line_style, @lines );
379             }
380             elsif( @lines )
381             {
382 1         1 my $first = shift @lines;
383 1         2 my $last = pop @lines;
384            
385 1         5 $self->first_code_line( $first );
386            
387 1         2 foreach my $line ( @lines )
388             {
389 5         9 $self->middle_code_line( $line );
390             }
391            
392 1         4 $self->last_code_line( $last );
393             }
394            
395 1         4 $self->{'in_verbatim'} = 0;
396             }
397              
398             sub _get_initial_item_type
399             {
400 4     4   952 my $self = shift;
401            
402 4         28 my $type = $self->SUPER::_get_initial_item_type;
403            
404             #print STDERR "My item type is [$type]\n";
405            
406 4         2385 $type;
407             }
408              
409             =pod
410              
411            
412            
413            
414            
415            
416            
417            
418            
419            
420             List item 1
421            
422            
423            
424             =cut
425              
426 0     0 0 0 sub not_implemented { croak "Not implemented!" }
427              
428 0     0 0 0 sub bullet_item_style { 'bullet item' }
429             sub start_item_bullet
430             {
431 13     13 0 9386 my( $self ) = @_;
432            
433 13         26 $self->{in_item} = 1;
434 13         19 $self->{item_count}++;
435            
436 13         34 $self->start_Para;
437             }
438              
439 0     0 0 0 sub start_item_number { not_implemented() }
440 0     0 0 0 sub start_item_block { not_implemented() }
441 0     0 0 0 sub start_item_text { not_implemented() }
442              
443             sub end_item_bullet
444             {
445 13     13 0 154 my $self = shift;
446 13         27 $self->end_Para;
447 13         39 $self->{in_item} = 0;
448             }
449 0     0 0 0 sub end_item_number { not_implemented() }
450 0     0 0 0 sub end_item_block { not_implemented() }
451 0     0 0 0 sub end_item_text { not_implemented() }
452              
453             sub start_over_bullet
454             {
455 4     4 0 131 my $self = shift;
456              
457 4         10 $self->{in_item_list} = 1;
458 4         16 $self->{item_count} = 0;
459             }
460 0     0 0 0 sub start_over_text { not_implemented() }
461 0     0 0 0 sub start_over_block { not_implemented() }
462 0     0 0 0 sub start_over_number { not_implemented() }
463              
464             sub end_over_bullet
465             {
466 4     4 0 227 my $self = shift;
467            
468 4         10 $self->end_non_code_text;
469            
470 4         7 $self->{in_item_list} = 0;
471 4         60 $self->{item_count} = 0;
472 4         8 $self->{last_thingy} = 'item_list';
473 4         19 $self->{scratch} = '';
474             }
475 0     0 0 0 sub end_over_text { not_implemented() }
476 0     0 0 0 sub end_over_block { not_implemented() }
477 0     0 0 0 sub end_over_number { not_implemented() }
478              
479             sub start_char_style
480             {
481 7     7 0 10 my( $self, $style ) = @_;
482            
483 7         19 $self->{'scratch'} .= qq|
484            
485            
486            
487            
488            
489             |;
490              
491 7         17 $self->emit;
492             }
493              
494             sub end_char_style
495             {
496 7     7 0 17 $_[0]->{'scratch'} .= '
497            
498            
499             ';
500              
501 7         16 $_[0]->emit;
502             }
503              
504              
505 1     1 0 18 sub bold_char_style { 'Bold' }
506 1     1 0 17 sub end_B { $_[0]->end_char_style }
507             sub start_B
508             {
509 1     1 0 25 $_[0]->start_char_style( $_[0]->bold_char_style );
510             }
511              
512 5     5 0 15 sub inline_code_char_style { 'Code' }
513             sub start_C
514             {
515 5     5 0 82 $_[0]->{in_C} = 1;
516 5         19 $_[0]->start_char_style( $_[0]->inline_code_char_style );
517             }
518             sub end_C
519             {
520 5     5 0 64 $_[0]->end_char_style;
521 5         13 $_[0]->{in_C} = 0;
522             }
523            
524 1     1 0 3 sub italic_char_style { 'Italic' }
525 1     1 0 14 sub end_I { $_[0]->end_char_style }
526 1     1 0 19 sub start_I { $_[0]->start_char_style( $_[0]->italic_char_style ); }
527              
528 0     0 0 0 sub start_F { $_[0]->end_char_style }
529 0     0 0 0 sub end_F { $_[0]->start_char_style( $_[0]->italic_char_style ); }
530              
531             sub start_M
532             {
533 0     0 0 0 $_[0]{'module_flag'} = 1;
534 0         0 $_[0]{'module_text'} = '';
535 0         0 $_[0]->start_C;
536             }
537              
538             sub end_M
539             {
540 0     0 0 0 $_[0]->end_C;
541 0         0 $_[0]{'module_flag'} = 0;
542             }
543              
544 0     0 0 0 sub start_N { }
545 0     0 0 0 sub end_N { }
546              
547 0     0 0 0 sub start_U { $_[0]->start_I }
548 0     0 0 0 sub end_U { $_[0]->end_I }
549              
550             sub handle_text
551             {
552 50     50 0 646 my( $self, $text ) = @_;
553              
554 50         111 my $pad = $self->get_pad;
555            
556 50         126 $self->escape_text( \$text );
557 50         90 $self->{$pad} .= $text;
558            
559 50 100       88 unless( $self->dont_escape )
560             {
561 44         104 $self->make_curly_quotes;
562 44         91 $self->make_em_dashes;
563 44         84 $self->make_ellipses;
564             }
565             }
566              
567             sub dont_escape {
568 50     50 0 61 my $self = shift;
569 50 100       305 $self->{in_verbatim} || $self->{in_C}
570             }
571            
572             sub escape_text
573             {
574 50     50 0 62 my( $self, $text_ref ) = @_;
575            
576 50         88 $$text_ref =~ s/&/&/g;
577 50         76 $$text_ref =~ s/
578              
579 50         100 return 1;
580             }
581              
582             sub make_curly_quotes
583             {
584 86     86 0 104 my( $self ) = @_;
585            
586 86         138 my $text = $self->{scratch};
587            
588 86         1376 require Tie::Cycle;
589            
590 86         1289 tie my $cycle, 'Tie::Cycle', [ qw( “ ” ) ];
591              
592 86         1728 1 while $text =~ s/"/$cycle/;
593            
594             # escape escape chars. This is escpaing them for InDesign
595             # so don't worry about double escaping for other levels. Don't
596             # worry about InDesign in the pod.
597 86         152 $text =~ s/'/’/g;
598            
599 86         171 $self->{'scratch'} = $text;
600            
601 86         222 return 1;
602             }
603              
604             sub make_em_dashes
605             {
606 44     44 0 97 $_[0]->{scratch} =~ s/--/—/g;
607 44         54 return 1;
608             }
609              
610             sub make_ellipses
611             {
612 44     44 0 90 $_[0]->{scratch} =~ s/\Q.../…/g;
613 44         146 return 1;
614             }
615            
616             BEGIN {
617 2     2   726 require Pod::Simple::BlackBox;
618              
619             package Pod::Simple::BlackBox;
620              
621             sub _ponder_Verbatim {
622 1     1   237 my ($self,$para) = @_;
623 1         2 DEBUG and print STDERR " giving verbatim treatment...\n";
624              
625 1         4 $para->[1]{'xml:space'} = 'preserve';
626 1         5 foreach my $line ( @$para[ 2 .. $#$para ] )
627             {
628 8         26 $line =~ s/^\t//gm;
629 8         19 $line =~ s/^(\t+)/" " x ( 4 * length($1) )/e
  3         15  
630             }
631            
632             # Now the VerbatimFormatted hoodoo...
633 1 50 33     13 if( $self->{'accept_codes'} and
    50          
634             $self->{'accept_codes'}{'VerbatimFormatted'}
635             ) {
636 0   0     0 while(@$para > 3 and $para->[-1] !~ m/\S/) { pop @$para }
  0         0  
637             # Kill any number of terminal newlines
638 0         0 $self->_verbatim_format($para);
639             } elsif ($self->{'codes_in_verbatim'}) {
640 0         0 push @$para,
641 0         0 @{$self->_make_treelet(
642             join("\n", splice(@$para, 2)),
643             $para->[1]{'start_line'}, $para->[1]{'xml:space'}
644             )};
645 0         0 $para->[-1] =~ s/\n+$//s; # Kill any number of terminal newlines
646             } else {
647 1 50       7 push @$para, join "\n", splice(@$para, 2) if @$para > 3;
648 1         8 $para->[-1] =~ s/\n+$//s; # Kill any number of terminal newlines
649             }
650 1         4 return;
651             }
652              
653             }
654              
655 2     2   91 BEGIN {
656              
657             # override _treat_Es so I can localize e2char
658             sub _treat_Es
659             {
660 5     5   1995 my $self = shift;
661              
662 5         39 require Pod::Escapes;
663 5         20 local *Pod::Escapes::e2char = *e2char_tagged_text;
664              
665 5         29 $self->SUPER::_treat_Es( @_ );
666             }
667              
668             sub e2char_tagged_text
669             {
670             package Pod::Escapes;
671            
672 2     2 0 100 my $in = shift;
673              
674 2 50 33     14 return unless defined $in and length $in;
675            
676 2 50       12 if( $in =~ m/^(0[0-7]*)$/ ) { $in = oct $in; }
  0 50       0  
677 0         0 elsif( $in =~ m/^0?x([0-9a-fA-F]+)$/ ) { $in = hex $1; }
678              
679 2 50       8 if( $NOT_ASCII )
680             {
681 0 0       0 unless( $in =~ m/^\d+$/ )
682             {
683 0         0 $in = $Name2character{$in};
684 0 0       0 return unless defined $in;
685 0         0 $in = ord $in;
686             }
687              
688 0   0     0 return $Code2USASCII{$in}
689             || $Latin1Code_to_fallback{$in}
690             || $FAR_CHAR;
691             }
692            
693 2 50 33     13 if( defined $Name2character_number{$in} and $Name2character_number{$in} < 127 )
    0          
694             {
695 2         9 return "&$in;";
696             }
697             elsif( defined $Name2character_number{$in} )
698             {
699             # this needs to be fixed width because I want to look for
700             # it in a negative lookbehind
701 0           return sprintf '&#x%04x;', $Name2character_number{$in};
702             }
703             else
704             {
705 0           return '???';
706             }
707            
708             }
709             }
710              
711             =head1 TO DO
712              
713              
714             =head1 SEE ALSO
715              
716             L, L
717              
718             =head1 SOURCE AVAILABILITY
719              
720             This source is in Github:
721              
722             http://github.com/briandfoy/Pod-WordML
723              
724             If, for some reason, I disappear from the world, one of the other
725             members of the project can shepherd this module appropriately.
726              
727             =head1 AUTHOR
728              
729             brian d foy, C<< >>
730              
731             =head1 COPYRIGHT AND LICENSE
732              
733             Copyright (c) 2009-2014, brian d foy, All Rights Reserved.
734              
735             You may redistribute this under the same terms as Perl itself.
736              
737             =cut
738              
739             1;