File Coverage

blib/lib/Pod/WordML.pm
Criterion Covered Total %
statement 25 249 10.0
branch 0 42 0.0
condition 0 15 0.0
subroutine 9 109 8.2
pod 11 94 11.7
total 45 509 8.8


line stmt bran cond sub pod time code
1             package Pod::WordML;
2 1     1   485 use strict;
  1         1  
  1         24  
3 1     1   3 use base 'Pod::PseudoPod';
  1         1  
  1         433  
4              
5 1     1   22526 use warnings;
  1         1  
  1         25  
6 1     1   3 no warnings;
  1         2  
  1         28  
7              
8 1     1   489 use subs qw();
  1         16  
  1         21  
9 1     1   4 use vars qw($VERSION);
  1         2  
  1         29  
10              
11 1     1   3 use Carp;
  1         1  
  1         270  
12              
13             $VERSION = '0.163';
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 0     0 1   my $string = <<'XML';
53            
54            
55            
56            
57             XML
58              
59 0           $string .= $_[0]->fonts . $_[0]->lists . $_[0]->styles;
60              
61 0           $string .= <<'XML';
62            
63             XML
64             }
65              
66              
67 0     0 0   sub fonts { '' }
68 0     0 0   sub lists { '' }
69 0     0 0   sub styles { '' }
70              
71             =item document_footer
72              
73             =cut
74              
75             sub document_footer
76             {
77 0     0 1   <<'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   sub head0_style { 'Heading0' }
91 0     0 1   sub head1_style { 'Heading1' }
92 0     0 1   sub head2_style { 'Heading2' }
93 0     0 1   sub head3_style { 'Heading3' }
94 0     0 1   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 0     0 0   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 0     0 0   sub first_item_para_style { 'FirstItemParagraphStyle' }
115 0     0 0   sub middle_item_para_style { 'MiddleItemParagraphStyle' }
116 0     0 0   sub last_item_para_style { 'LastItemParagraphStyle' }
117 0     0 0   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   sub code_para_style { 'CodeParagraphStyle' }
127 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   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   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   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   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 1     1   491 use Data::Dumper;
  1         4227  
  1         1860  
169 0     0 1   sub new { my $self = $_[0]->SUPER::new() }
170              
171             sub emit
172             {
173 0     0 0   print {$_[0]->{'output_fh'}} $_[0]->{'scratch'};
  0            
174 0           $_[0]->{'scratch'} = '';
175 0           return;
176             }
177              
178             sub get_pad
179             {
180             # flow elements first
181 0 0   0 0   if( $_[0]{module_flag} ) { 'scratch' }
  0 0          
182 0           elsif( $_[0]{url_flag} ) { 'url_text' }
183             # then block elements
184             # finally the default
185 0           else { 'scratch' }
186             }
187              
188             sub start_Document
189             {
190 0     0 0   $_[0]->{'scratch'} .= $_[0]->document_header; $_[0]->emit;
  0            
191             }
192              
193             sub end_Document
194             {
195 0     0 0   $_[0]->{'scratch'} .= $_[0]->document_footer; $_[0]->emit;
  0            
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 0     0     my( $self, $style, $level ) = @_;
214              
215 0           my $format = '
216            
217            
218            
219            
220             ';
221              
222 0           $self->{scratch} = sprintf $format, $style;
223 0           $self->emit;
224             }
225              
226             sub _header_end
227             {
228 0     0     '
229            
230            
231             ';
232             }
233              
234 0     0 0   sub start_head0 { $_[0]->_header_start( $_[0]->head0_style, 0 ); }
235 0     0 0   sub end_head0 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  0            
236              
237 0     0 0   sub start_head1 { $_[0]->_header_start( $_[0]->head1_style, 1 ); }
238 0     0 0   sub end_head1 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  0            
239              
240 0     0 0   sub start_head2 { $_[0]->_header_start( $_[0]->head2_style, 2 ); }
241 0     0 0   sub end_head2 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  0            
242              
243 0     0 0   sub start_head3 { $_[0]->_header_start( $_[0]->head3_style, 3 ); }
244 0     0 0   sub end_head3 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  0            
245              
246 0     0 0   sub start_head4 { $_[0]->_header_start( $_[0]->head4_style, 4 ); }
247 0     0 0   sub end_head4 { $_[0]{'scratch'} .= $_[0]->_header_end; $_[0]->end_non_code_text }
  0            
248              
249             sub end_non_code_text
250             {
251 0     0 0   my $self = shift;
252              
253 0           $self->make_curly_quotes;
254              
255 0           $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 0     0 0   my( $self, $style, $para ) = @_;
285              
286 0           $self->{'scratch'} =
287             qq|
288            
289            
290            
291            
292             $para
293            
294            
295             |;
296              
297 0           $self->emit;
298             }
299              
300             sub start_Para
301             {
302 0     0 0   my $self = shift;
303              
304             # it would be nice to take this through make_para
305 0           my $style = do {
306 0 0         if( $self->{in_item} )
    0          
307             {
308 0 0         if( $self->{item_count} == 1 ) { $self->first_item_para_style }
  0            
309 0           else { $self->middle_item_para_style }
310             }
311 0           elsif( $self->{in_item_list} ) { $self->item_subpara_style }
312 0           else { $self->normal_para_style }
313             };
314              
315 0           $self->{'scratch'} =
316             qq|
317            
318            
319            
320            
321             |;
322              
323 0 0         $self->{'scratch'} .= "\x{25FE} " if $self->{in_item};
324              
325 0           $self->emit;
326              
327 0           $self->{'in_para'} = 1;
328             }
329              
330              
331             sub end_Para
332             {
333 0     0 0   my $self = shift;
334              
335 0           $self->{'scratch'} .= '
336            
337            
338             ';
339              
340 0           $self->emit;
341              
342 0           $self->end_non_code_text;
343              
344 0           $self->{'in_para'} = 0;
345             }
346              
347       0 0   sub start_figure { }
348              
349       0 0   sub end_figure { }
350              
351 0     0 0   sub first_code_line_style { 'first code line' }
352 0     0 0   sub middle_code_line_style { 'middle code line' }
353 0     0 0   sub last_code_line_style { 'last code line' }
354              
355 0     0 0   sub first_code_line { $_[0]->make_para( $_[0]->first_code_line_style, $_[1] ) }
356 0     0 0   sub middle_code_line { $_[0]->make_para( $_[0]->middle_code_line_style, $_[1] ) }
357 0     0 0   sub last_code_line { $_[0]->make_para( $_[0]->last_code_line_style, $_[1] ) }
358              
359             sub start_Verbatim
360             {
361 0     0 0   $_[0]{'in_verbatim'} = 1;
362             }
363              
364             sub end_Verbatim
365             {
366 0     0 0   my $self = shift;
367              
368             # get rid of all but one trailing newline
369 0           $self->{'scratch'} =~ s/\s+\z//;
370              
371 0           chomp( my @lines = split m/^/m, $self->{'scratch'} );
372 0           $self->{'scratch'} = '';
373              
374 0           @lines = map { s/
  0            
  0            
375              
376 0 0         if( @lines == 1 )
    0          
377             {
378 0           $self->make_para( $self->single_code_line_style, @lines );
379             }
380             elsif( @lines )
381             {
382 0           my $first = shift @lines;
383 0           my $last = pop @lines;
384              
385 0           $self->first_code_line( $first );
386              
387 0           foreach my $line ( @lines )
388             {
389 0           $self->middle_code_line( $line );
390             }
391              
392 0           $self->last_code_line( $last );
393             }
394              
395 0           $self->{'in_verbatim'} = 0;
396             }
397              
398             sub _get_initial_item_type
399             {
400 0     0     my $self = shift;
401              
402 0           my $type = $self->SUPER::_get_initial_item_type;
403              
404             #print STDERR "My item type is [$type]\n";
405              
406 0           $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   sub not_implemented { croak "Not implemented!" }
427              
428 0     0 0   sub bullet_item_style { 'bullet item' }
429             sub start_item_bullet
430             {
431 0     0 0   my( $self ) = @_;
432              
433 0           $self->{in_item} = 1;
434 0           $self->{item_count}++;
435              
436 0           $self->start_Para;
437             }
438              
439 0     0 0   sub start_item_number { not_implemented() }
440 0     0 0   sub start_item_block { not_implemented() }
441 0     0 0   sub start_item_text { not_implemented() }
442              
443             sub end_item_bullet
444             {
445 0     0 0   my $self = shift;
446 0           $self->end_Para;
447 0           $self->{in_item} = 0;
448             }
449 0     0 0   sub end_item_number { not_implemented() }
450 0     0 0   sub end_item_block { not_implemented() }
451 0     0 0   sub end_item_text { not_implemented() }
452              
453             sub start_over_bullet
454             {
455 0     0 0   my $self = shift;
456              
457 0           $self->{in_item_list} = 1;
458 0           $self->{item_count} = 0;
459             }
460 0     0 0   sub start_over_text { not_implemented() }
461 0     0 0   sub start_over_block { not_implemented() }
462 0     0 0   sub start_over_number { not_implemented() }
463              
464             sub end_over_bullet
465             {
466 0     0 0   my $self = shift;
467              
468 0           $self->end_non_code_text;
469              
470 0           $self->{in_item_list} = 0;
471 0           $self->{item_count} = 0;
472 0           $self->{last_thingy} = 'item_list';
473 0           $self->{scratch} = '';
474             }
475 0     0 0   sub end_over_text { not_implemented() }
476 0     0 0   sub end_over_block { not_implemented() }
477 0     0 0   sub end_over_number { not_implemented() }
478              
479             sub start_char_style
480             {
481 0     0 0   my( $self, $style ) = @_;
482              
483 0           $self->{'scratch'} .= qq|
484            
485            
486            
487            
488            
489             |;
490              
491 0           $self->emit;
492             }
493              
494             sub end_char_style
495             {
496 0     0 0   $_[0]->{'scratch'} .= '
497            
498            
499             ';
500              
501 0           $_[0]->emit;
502             }
503              
504              
505 0     0 0   sub bold_char_style { 'Bold' }
506 0     0 0   sub end_B { $_[0]->end_char_style }
507             sub start_B
508             {
509 0     0 0   $_[0]->start_char_style( $_[0]->bold_char_style );
510             }
511              
512 0     0 0   sub inline_code_char_style { 'Code' }
513             sub start_C
514             {
515 0     0 0   $_[0]->{in_C} = 1;
516 0           $_[0]->start_char_style( $_[0]->inline_code_char_style );
517             }
518             sub end_C
519             {
520 0     0 0   $_[0]->end_char_style;
521 0           $_[0]->{in_C} = 0;
522             }
523              
524 0     0 0   sub italic_char_style { 'Italic' }
525 0     0 0   sub end_I { $_[0]->end_char_style }
526 0     0 0   sub start_I { $_[0]->start_char_style( $_[0]->italic_char_style ); }
527              
528 0     0 0   sub start_F { $_[0]->end_char_style }
529 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]{'module_flag'} = 1;
534 0           $_[0]{'module_text'} = '';
535 0           $_[0]->start_C;
536             }
537              
538             sub end_M
539             {
540 0     0 0   $_[0]->end_C;
541 0           $_[0]{'module_flag'} = 0;
542             }
543              
544       0 0   sub start_N { }
545       0 0   sub end_N { }
546              
547 0     0 0   sub start_U { $_[0]->start_I }
548 0     0 0   sub end_U { $_[0]->end_I }
549              
550             sub handle_text
551             {
552 0     0 0   my( $self, $text ) = @_;
553              
554 0           my $pad = $self->get_pad;
555              
556 0           $self->escape_text( \$text );
557 0           $self->{$pad} .= $text;
558              
559 0 0         unless( $self->dont_escape )
560             {
561 0           $self->make_curly_quotes;
562 0           $self->make_em_dashes;
563 0           $self->make_ellipses;
564             }
565             }
566              
567             sub dont_escape {
568 0     0 0   my $self = shift;
569             $self->{in_verbatim} || $self->{in_C}
570 0 0         }
571              
572             sub escape_text
573             {
574 0     0 0   my( $self, $text_ref ) = @_;
575              
576 0           $$text_ref =~ s/&/&/g;
577 0           $$text_ref =~ s/
578              
579 0           return 1;
580             }
581              
582             sub make_curly_quotes
583             {
584 0     0 0   my( $self ) = @_;
585              
586 0           my $text = $self->{scratch};
587              
588 0           require Tie::Cycle;
589              
590 0           tie my $cycle, 'Tie::Cycle', [ qw( “ ” ) ];
591              
592 0           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 0           $text =~ s/'/’/g;
598              
599 0           $self->{'scratch'} = $text;
600              
601 0           return 1;
602             }
603              
604             sub make_em_dashes
605             {
606 0     0 0   $_[0]->{scratch} =~ s/--/—/g;
607 0           return 1;
608             }
609              
610             sub make_ellipses
611             {
612 0     0 0   $_[0]->{scratch} =~ s/\Q.../…/g;
613 0           return 1;
614             }
615              
616 0     0     BEGIN {
617 1     1   221 require Pod::Simple::BlackBox;
618              
619             package Pod::Simple::BlackBox;
620              
621             sub _ponder_Verbatim {
622 0     0     my ($self,$para) = @_;
623 0           DEBUG and print STDERR " giving verbatim treatment...\n";
624              
625 0           $para->[1]{'xml:space'} = 'preserve';
626 0           foreach my $line ( @$para[ 2 .. $#$para ] )
627             {
628 0           $line =~ s/^\t//gm;
629 0           $line =~ s/^(\t+)/" " x ( 4 * length($1) )/e
  0            
630             }
631              
632             # Now the VerbatimFormatted hoodoo...
633 0 0 0       if( $self->{'accept_codes'} and
    0          
634             $self->{'accept_codes'}{'VerbatimFormatted'}
635             ) {
636 0   0       while(@$para > 3 and $para->[-1] !~ m/\S/) { pop @$para }
  0            
637             # Kill any number of terminal newlines
638 0           $self->_verbatim_format($para);
639             } elsif ($self->{'codes_in_verbatim'}) {
640             push @$para,
641 0           @{$self->_make_treelet(
642             join("\n", splice(@$para, 2)),
643 0           $para->[1]{'start_line'}, $para->[1]{'xml:space'}
644             )};
645 0           $para->[-1] =~ s/\n+$//s; # Kill any number of terminal newlines
646             } else {
647 0 0         push @$para, join "\n", splice(@$para, 2) if @$para > 3;
648 0           $para->[-1] =~ s/\n+$//s; # Kill any number of terminal newlines
649             }
650 0           return;
651             }
652              
653             }
654              
655 0           BEGIN {
656              
657             # override _treat_Es so I can localize e2char
658             sub _treat_Es
659             {
660 0     0     my $self = shift;
661              
662 0           require Pod::Escapes;
663 0           local *Pod::Escapes::e2char = *e2char_tagged_text;
664              
665 0           $self->SUPER::_treat_Es( @_ );
666             }
667              
668             sub e2char_tagged_text
669             {
670             package Pod::Escapes;
671              
672 0     0 0   my $in = shift;
673              
674 0 0 0       return unless defined $in and length $in;
675              
676 0 0         if( $in =~ m/^(0[0-7]*)$/ ) { $in = oct $in; }
  0 0          
677 0           elsif( $in =~ m/^0?x([0-9a-fA-F]+)$/ ) { $in = hex $1; }
678              
679 0 0         if( $NOT_ASCII )
680             {
681 0 0         unless( $in =~ m/^\d+$/ )
682             {
683 0           $in = $Name2character{$in};
684 0 0         return unless defined $in;
685 0           $in = ord $in;
686             }
687              
688             return $Code2USASCII{$in}
689 0   0       || $Latin1Code_to_fallback{$in}
690             || $FAR_CHAR;
691             }
692              
693 0 0 0       if( defined $Name2character_number{$in} and $Name2character_number{$in} < 127 )
    0          
694             {
695 0           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 © 2009-2017, brian d foy . All rights reserved.
734              
735             You may redistribute this under the Artistic License 2.0.
736              
737              
738             =cut
739              
740             1;