File Coverage

blib/lib/EBook/MOBI/Driver/POD.pm
Criterion Covered Total %
statement 235 246 95.5
branch 120 140 85.7
condition 26 39 66.6
subroutine 23 23 100.0
pod 4 10 40.0
total 408 458 89.0


line stmt bran cond sub pod time code
1             package EBook::MOBI::Driver::POD;
2              
3             our $VERSION = '0.72'; # TRIAL VERSION (hook for Dist::Zilla::Plugin::OurPkgVersion)
4              
5 9     9   1312 use strict;
  9         14  
  9         238  
6 9     9   48 use warnings;
  9         15  
  9         362  
7              
8 9     9   45 use Pod::Parser;
  9         18  
  9         396  
9 9     9   4831 use EBook::MOBI::Driver;
  9         23  
  9         406  
10             our @ISA = qw(Pod::Parser EBook::MOBI::Driver);
11              
12 9     9   6539 use Text::Trim;
  9         5112  
  9         513  
13 9     9   6775 use HTML::Entities;
  9         55528  
  9         799  
14 9     9   67 use Carp;
  9         19  
  9         459  
15 9     9   5764 use EBook::MOBI::Converter;
  9         24  
  9         269  
16 9     9   5899 use IO::String;
  9         20117  
  9         465  
17              
18             # This constants are used for internal replacement
19             # See interior_sequence() and _html_enc() for usage
20 9         1170 use constant { GT => '1_qpdhcn_thisStringShouldNeverOccurInInput',
21             LT => '2_udtcqk_thisStringShouldNeverOccurInInput',
22             AMP => '3_pegjyq_thisStringShouldNeverOccurInInput',
23             COL => '4_jdkmso_thisStringShouldNeverOccurInInput',
24             QUO => '5_wuehlo_thisStringShouldNeverOccurInInput',
25             DQUO=> '6_jrgwpm_thisStringShouldNeverOccurInInput',
26 9     9   58 };
  9         18  
27              
28             # IMPORTANT
29             # This constant ist JUST a shortcut for readability.
30             # Because it is used in hases ($parser->{}) a + is used so that it is not
31             # interpreted as a string, so it looks like this: $parser->{+P . 'bla'}
32             # See http://perldoc.perl.org/constant.html for details
33 9     9   39 use constant { P => 'EBook_MOBI_Pod2Mhtml_' };
  9         17  
  9         1346659  
34              
35             # Overwrite sub of Pod::Parser
36             sub begin_input {
37 33     33 0 1398 my $parser = shift;
38 33         574 my $out_fh = $parser->output_handle(); # handle for parsing output
39              
40 33         311 $parser->{+P . 'toMobi'} = EBook::MOBI::Converter->new();
41              
42 33         142 $parser->debug_msg('found POD, parsing...');
43              
44             # make sure that this variable is set to 0 at beginning
45 33         61 $parser->{+P . 'listcontext'} = 0;
46 33         50 $parser->{+P . 'listjustwentback'} = 0;
47 33         702 $parser->{+P . 'begin'} = '';
48             }
49              
50             # Overwrite sub of Pod::Parser
51             sub end_input {
52 33     33 0 1315 my $parser = shift;
53 33         116 my $out_fh = $parser->output_handle();
54              
55 33         224 $parser->debug_msg('...end of POD reached');
56             }
57              
58             # Overwrite sub of Pod::Parser
59             # Here all POD commands starting with '=' are handled
60             sub command {
61 181     181 0 10901 my ($parser, $command, $paragraph, $line_num) = @_;
62 181         581 my $out_fh = $parser->output_handle(); # handle for parsing output
63              
64             # IMAGE is an unofficial command introduced by Renee, its very simple:
65             # =image PATH_TO_IMAGE ANY TEXT FOLLOWING UNTIL END OF LINE
66 181 100       450 if ($command eq 'image') {
67              
68 1         220 print
69             "WARNING: the unofficial POD command '=image' is deprecated.\n";
70              
71             # With this regex we parse the content, coming with the command.
72             # An example could look like this:
73             # $paragraph = '/home/user/picture.jpg Pic1: A Camel'
74 1 50       9 if ($paragraph =~ m/(\S*)\s*(.*)/g) {
75 1         3 my $img_path = $1; # e.g.: '/home/user/picture.jpg'
76 1         3 my $img_desc = $2; # e.g.: 'A Camel'
77              
78             # We convert special chars to HTML, but only in the
79             # description, not in the path!
80 1         4 $img_desc = _html_enc($img_desc);
81              
82             # We print out an html image tag.
83             # e.g.:
84             # recindex is MOBI specific, its the number of the picture,
85             # pointing into the picture records of the Mobi-format
86             print $out_fh
87 1         6 $parser->{+P . 'toMobi'}
88             ->image($img_path, $img_desc);
89             }
90             }
91             # POD compatible additional syntax to process images
92             # =for image PATH_TO_IMAGE ANY TEXT FOLLOWING UNTIL END OF LINE
93 181 100       808 if ($command eq 'for') {
    100          
    100          
    50          
    100          
    100          
94              
95             # With this regex we parse the content, coming with the command.
96             # An example could look like this:
97             # $paragraph = 'image /home/user/picture.jpg Pic1: A Camel'
98 1 50       8 if ($paragraph =~ m/image\s*(\S*)\s*(.*)/g) {
99 1         2 my $img_path = $1; # e.g.: '/home/user/picture.jpg'
100 1         2 my $img_desc = $2; # e.g.: 'A Camel'
101              
102             # We convert special chars to HTML, but only in the
103             # description, not in the path!
104 1         3 $img_desc = _html_enc($img_desc);
105              
106             # We print out an html image tag.
107             # e.g.:
108             # recindex is MOBI specific, its the number of the picture,
109             # pointing into the picture records of the Mobi-format
110             print $out_fh
111 1         5 $parser->{+P . 'toMobi'}
112             ->image($img_path, $img_desc);
113             }
114             }
115             # Lists are a bit complex. The commands 'over', 'back' and 'item'
116             # are used. They exchange state over a global variable. This state
117             # is the listcontext, which can be: 'begin', 'ul' or 'ol'.
118             # OVER: starts the listcontext
119             elsif ($command eq 'over') {
120              
121             # If we reach an 'over' command we can't do anything yet
122             # because we don't know if it will be an ordered or an
123             # unordered list! So we just set a global variable to 'begin',
124             # the first item call can then know that it is the first item
125             # and that it defines the rest of the list type.
126              
127 25 100       52 if (exists $parser->{+P . 'list'}) {
128             # if we reach here, this means that this is a nested list
129 9         14 $parser->{+P . 'listlvl'}++;
130             }
131             else {
132 16         32 $parser->{+P . 'listlvl'} = 0;
133             }
134              
135              
136 25         30 push @{$parser->{+P . 'list'}}
  25         1134  
137             , {
138             type => '' ,
139             items => 0 ,
140             state => 'over' ,
141             contentInCmd => 1 ,
142             blockquotes => 0 ,
143             };
144             }
145             # BACK: ends the listcontext
146             elsif ($command eq 'back') {
147              
148 25         34 my $lvl = $parser->{+P . 'listlvl'};
149              
150             # print end-tag according to the lists type
151 25 100       85 if ($parser->{+P . 'list'}->[$lvl]->{type} eq 'ul') {
    100          
    50          
152 14         46 print $out_fh '' . "\n"; # close last item
153 14         232 print $out_fh '' . "\n";
154             }
155             elsif ($parser->{+P . 'list'}->[$lvl]->{type} eq 'ol') {
156 6         21 print $out_fh '' . "\n"; # close last item
157 6         101 print $out_fh '' . "\n";
158             }
159             elsif
160             ($parser->{+P . 'list'}->[$lvl]->{type}
161             eq 'blockquote') {
162             # list is processed
163             # there where no items...
164             }
165             else {
166             carp 'POD parsing error. Undefined listcontext: '
167 0         0 . $parser->{+P . 'listcontext'};
168             }
169              
170             # DELETE if list is finish
171 25 100       318 if ($parser->{+P . 'listlvl'} == 0) {
172 16         35 delete $parser->{+P . 'listlvl'};
173 16         47 delete $parser->{+P . 'list'};
174 16         379 delete $parser->{+P . 'listjustwentback'};
175             }
176             else {
177 9         20 $parser->{+P . 'list'}->[$lvl]->{state} = 'back';
178 9         12 $parser->{+P . 'listlvl'}--;
179 9         367 $parser->{+P . 'listjustwentback'} = 1;
180             }
181             }
182             # CUT: end of POD
183             elsif ($command eq 'cut') {
184             # We don't need to do anything here...
185             }
186             elsif ($command eq 'begin') {
187 1 50       7 if ($paragraph =~ m/^\W*(\w+)\W*$/) {
188 1         2 my $begin_name = $1;
189 1         38 $parser->{+P . 'begin'} = $begin_name;
190             }
191             }
192             elsif ($command eq 'end') {
193 1 50       7 if ($paragraph =~ m/^\W*(\w+)\W*$/) {
194 1         2 my $end_name = $1;
195 1 50       4 if ($parser->{+P . 'begin'} eq $end_name) {
196 1         39 $parser->{+P . 'begin'} = '';
197             }
198             else {
199 0         0 croak 'no nested begin/end supported';
200             }
201             }
202             }
203             # if we reach this ELSE, this means that the command can only be
204             # of type HEAD or ITEM (so they contain some text!)
205             else {
206             # first we remove all whitespace from begin and end of the title
207 128         327 trim $paragraph;
208             # then we call interpolate so that 'interior_sequence' is called.
209             # this is replacing inline POD.
210 128         6898 my $expansion = $parser->interpolate($paragraph, $line_num);
211             # then we replace special chars with HTML entities
212 128         344 $expansion = _html_enc($expansion);
213              
214             # Now we just need to print the text with the matching HTML tag
215 128 100       562 if ($command eq 'head0') {
    100          
    100          
    100          
    100          
    100          
216             # head0 gets only printed if the option is set!
217             # (head0 is not official POD standard)
218 17 100       43 if ($parser->head0_mode()) {
219             # before every head1 we insert a "mobi-pagebreak"
220             # but not before the first one!
221 9 100 66     73 if (exists $parser->{+P . 'firstH1passed'}
      66        
222             and exists $parser->{+P . 'pages'}
223             and $parser->{+P . 'pages'}
224             ) {
225             print $out_fh
226 3         13 $parser->{+P . 'toMobi'}->pagebreak();
227             }
228             else {
229 6         13 $parser->{+P . 'firstH1passed'} = 1;
230             }
231              
232             print $out_fh
233 9         69 $parser->{+P . 'toMobi'}->title($expansion, 1);
234             }
235             }
236             elsif ($command eq 'head1') {
237             # we need to check to which level we translate the headings...
238 38 100       85 if ($parser->head0_mode()) {
239             print $out_fh
240 9         29 $parser->{+P . 'toMobi'}->title($expansion, 2);
241             }
242             else {
243             # before every head1 we insert a "mobi-pagebreak"
244             # but not before the first one!
245 29 100 66     120 if (exists $parser->{+P . 'firstH1passed'}
      66        
246             and exists $parser->{+P . 'pages'}
247             and $parser->{+P . 'pages'}
248             ) {
249             print $out_fh
250 2         11 $parser->{+P . 'toMobi'}->pagebreak();
251             }
252             else {
253 27         52 $parser->{+P . 'firstH1passed'} = 1;
254             }
255              
256             print $out_fh
257 29         149 $parser->{+P . 'toMobi'}->title($expansion, 1);
258             }
259             }
260             elsif ($command eq 'head2') {
261             # we need to check to which level we translate the headings...
262 12 100       31 if ($parser->head0_mode()) {
263             print $out_fh
264 4         13 $parser->{+P . 'toMobi'}->title($expansion, 3);
265             }
266             else {
267             print $out_fh
268 8         33 $parser->{+P . 'toMobi'}->title($expansion, 2);
269             }
270             }
271             elsif ($command eq 'head3') {
272             # we need to check to which level we translate the headings...
273 1 50       5 if ($parser->head0_mode()) {
274             print $out_fh
275 0         0 $parser->{+P . 'toMobi'}->title($expansion, 4);
276             }
277             else {
278             print $out_fh
279 1         6 $parser->{+P . 'toMobi'}->title($expansion, 3);
280             }
281             }
282             elsif ($command eq 'head4') {
283             # we need to check to which level we translate the headings...
284 1 50       4 if ($parser->head0_mode()) {
285             print $out_fh
286 0         0 $parser->{+P . 'toMobi'}->title($expansion, 5);
287             }
288             else {
289             print $out_fh
290 1         6 $parser->{+P . 'toMobi'}->title($expansion, 4);
291             }
292             }
293             # ITEM: lists items
294             elsif ($command eq 'item') {
295              
296             # If we are still in listcontext 'begin' this means that this is
297             # the first item of the list, which will be used to figure out
298             # the type of the list.
299 58         92 my $lvl = $parser->{+P . 'listlvl'};
300              
301 58         86 $parser->{+P . 'list'}->[$lvl]->{items}++;
302              
303 58 100       114 if ($parser->{+P . 'list'}->[$lvl]->{items} == 1){
304              
305             # if we are already in a list...
306 20 100 66     129 if ($parser->{+P . 'list'}->[$lvl]->{state}
      100        
307             eq 'over'
308             and $lvl > 0
309             and
310             $parser->{+P . 'list'}->[$lvl-1]->{items}
311             > 0
312             ) {
313             # we need to close the last item!
314 6         20 print $out_fh '' . "\n";
315             }
316              
317             # is there a digit at first, if yes this is an ordered list
318 20 100       192 if ($expansion =~ /^\s*\d+\s*(.*)$/) {
    100          
    100          
319 6         13 $expansion = $1;
320             $parser->{+P . 'list'}->[$lvl]
321 6         13 ->{type} = 'ol';
322              
323 6 100       18 if ($expansion =~ /[[:alnum:][:punct:]]+/) {
324 5         17 print $out_fh '
    ' . "\n";
325             }
326             else {
327 1         3 $parser->{+P . 'list'}->[$lvl]->{contentInCmd} = 0;
328 1         4 print $out_fh "
    \n";
329             }
330             }
331             # is there a '*' at first, if yes this is an unordered list
332             elsif ($expansion =~ /^\s*\*{1}\s*(.*)$/) {
333 11         31 $expansion = $1;
334 11         23 $parser->{+P . 'list'}->[$lvl]->{type} = 'ul';
335              
336 11 100       32 if ($expansion =~ /[[:alnum:][:punct:]]+/) {
337 9         31 print $out_fh '
    ' . "\n";
338             }
339             else {
340 2         4 $parser->{+P . 'list'}->[$lvl]->{contentInCmd} = 0;
341 2         9 print $out_fh "
    \n";
342             #\n";
343             }
344             }
345             # are there only prinable chars? We default to unordered
346             elsif ($expansion =~ /[[:alnum:][:punct:]]+/) {
347 1         2 $parser->{+P . 'list'}->[$lvl]->{type} = 'ul';
348 1         5 print $out_fh '
    ' . "\n";
349             # do nothing
350             }
351             # The lists text may be in a normal text section...
352             # we default to unordered
353             else {
354 2         8 $parser->{+P . 'list'}->[$lvl]->{type} = 'ul';
355 2         4 $parser->{+P . 'list'}->[$lvl]->{contentInCmd} = 0;
356 2         10 print $out_fh "
    \n";
357             }
358             }
359              
360             # if it is not the first item we save the checks for list-type
361             else {
362              
363             # but first we need to close the last item!
364 38 100       78 if ($parser->{+P . 'listjustwentback'}) {
365 7         18 $parser->{+P . 'listjustwentback'} = 0;
366             }
367             else {
368             # we need to close the last item!
369 31         110 print $out_fh '' . "\n";
370             }
371              
372             my $type =
373 38         571 $parser->{+P . 'list'}->[$lvl]->{type};
374              
375             # then we check the type and extract the content
376 38 100       87 if ($type eq 'ol') {
377 10 50       43 if ($expansion =~ /^\s*\d+\s*(.*)$/) {
378 10         21 $expansion = $1;
379             }
380             }
381 38 100       80 if ($type eq 'ul') {
382 28 100       103 if ($expansion =~ /^\s*\*{1}\s*(.*)$/) {
383 22         51 $expansion = $1;
384             }
385             }
386             }
387              
388             # we print the item... but we don't close it!
389             # it get's closed by the next item or the =back call
390 58         479 print $out_fh '
  • ' . $expansion;
  • 391             }
    392             }
    393             }
    394              
    395             # Overwrite sub of Pod::Parser
    396             # Here all code parts of POD get parsed
    397             sub verbatim {
    398 1     1 0 128 my ($parser, $paragraph, $line_num) = @_;
    399 1         7 my $out_fh = $parser->output_handle(); # handle for parsing output
    400              
    401             # We have to escape the case where there is only a newline, because
    402             # Pod::Parser calls verbatim() with $paragraph="\n" every time an empty
    403             # line is found in the Pod. But that is not what we are looking for!
    404             # We are looking for code-blocks here...
    405 1 50       20 if ($paragraph eq "\n") { return }
      0         0  
    406              
    407             # we look for POD inline commands
    408 1         49 my $expansion = $parser->interpolate($paragraph, $line_num);
    409             # then for special chars
    410 1         3 $expansion = _html_enc($expansion);
    411             # and last but not least we replace whitespace with a HTML tag.
    412             # this we do only for the verbatim command!
    413             # this is so, that code format (indenting) is keeped in html
    414 1         5 $expansion = _nbsp($expansion);
    415              
    416             # also only in verbatim we replace newline with the
    tag
    417             # this is so, that code format is keeped in html
    418 1         8 $expansion =~ s/\n/
    \n/g;
    419              
    420             # trim must be last,
    421             # otherwise _nbsp() is not working for the first line
    422 1         4 trim $expansion;
    423              
    424             # ok, we are done and print out the result
    425 1         25 print $out_fh "$expansion\n";
    426             }
    427              
    428             # Overwrite sub of Pod::Parser
    429             # Here normal POD text paragraphs get parsed
    430             sub textblock {
    431 86     86 0 5420 my ($parser, $paragraph, $line_num) = @_;
    432 86         285 my $out_fh = $parser->output_handle(); # handle for parsing output
    433              
    434             # we could be in a =begin block so we just check that and return if
    435             # this is the case
    436 86 100       226 if ($parser->{+P . 'begin'} eq 'html') {
    437             # we are in a html block, so just print the plain thing
    438 1         3 print $out_fh "

    \n";

    439 1         16 print $out_fh $paragraph;
    440 1         17 print $out_fh "

    \n";
    441             return
    442 1         56 }
    443              
    444             # no begin block... so do the rest of this complicate code!
    445              
    446             # ok, this one is tricky...
    447             # textblock() can be called when the parser is actually parsing a list.
    448             # this happens if the list is written like that:
    449             # =over
    450             #
    451             # =item
    452             #
    453             # Text that appears in this sub as $paragraph
    454             #
    455             # =back
    456             # If the text is on the SAME LINE as the =item command, this will not
    457             # happen. It is only when the text is separated with newline.
    458             # Ok... we need to check here if we are in a list.. and then do some
    459             # stuffe to handle that case.
    460              
    461             # we translate the POD inline commands...
    462 85         4511 my $expansion = $parser->interpolate($paragraph, $line_num);
    463             # remove leading and trailing whitespace...
    464 85         266 trim $expansion;
    465             # and translate special chars to HTML
    466 85         1300 $expansion = _html_enc($expansion);
    467              
    468             # store the list-nesting in a local variable (just for readability)
    469 85         152 my $lvl = $parser->{+P . 'listlvl'};
    470              
    471             # if there is no list WE ARE LUCKY and just print the text as paragraph
    472 85 100 100     410 if (not exists $parser->{+P . 'list'}) {
        100          
        100          
        50          
    473 56         226 print $out_fh '

    ' . $expansion . '

    ' . "\n";
    474             }
    475             # NOOOOOOO... we have a list
    476             # ok... let's try to figure out what to do!
    477              
    478             # items and some content found already in the command...
    479             # ... so we add a
    before the following textblock.
    480             elsif ($parser->{+P . 'list'}->[$lvl]->{items} > 0
    481             and $parser->{+P . 'list'}->[$lvl]->{contentInCmd} == 1
    482             ) {
    483 2         10 print $out_fh '
    ' . $expansion;
    484             }
    485             # if there was not yet content found we just print what we have now
    486             elsif ($parser->{+P . 'list'}->[$lvl]->{items} > 0) {
    487 12         44 print $out_fh $expansion;
    488             }
    489             # if there where no items yet this can only mean that we are in a list
    490             # without any items but with pure text... so we do blockquotes for
    491             # each paragraph
    492             elsif ($parser->{+P . 'list'}->[$lvl]->{items} == 0) {
    493              
    494             # we set the listtype
    495 15         25 $parser->{+P . 'list'}->[$lvl]->{type} = 'blockquote';
    496 15         20 $parser->{+P . 'list'}->[$lvl]->{blockquotes}++;
    497              
    498 15 100 100     83 if ($parser->{+P . 'list'}->[$lvl]->{blockquotes} == 1
          100        
    499             and $lvl > 0
    500             and $parser->{+P . 'list'}->[$lvl-1]->{items} > 0
    501             ) {
    502 1         5 print $out_fh "\n";
    503             }
    504              
    505             # we do some pseudo-indenting
    506             # TODO: more nice would be real nesting...
    507 15         50 for (0..$lvl) {
    508 21         157 print $out_fh '
    ';
    509             }
    510 15         260 print $out_fh $expansion;
    511 15         246 for (0..$lvl) {
    512 21         143 print $out_fh '' ."\n";
    513             }
    514             }
    515             else {
    516             # we should not reach here...
    517 0         0 croak "POD parsing error. Found undefined textblock in a list.";
    518             }
    519             }
    520              
    521             # Overwrite sub of Pod::Parser
    522             # This method is called for handling inline POD, like e.g. B
    523             sub interior_sequence {
    524 19     19 0 35 my ($parser, $cmd, $arg) = @_;
    525              
    526             # IMPORTANT here we do some tricky stuff...
    527             # what we actually want is this:
    528             # B -> some text
    529             # but this is not possible, because then the <> would be replaced by
    530             # HTML entities later on!
    531             # So that is why we replace like this:
    532             # < -> constant: LT
    533             # and
    534             # > -> constant: GT
    535             # So B becomes XLTXsome textXGTX
    536             # The function which is doing the HTML translation must then replace
    537             # this words again with < and > (this is what _html_enc() is doing)
    538 19 100       244 return LT . 'b' . GT . $arg . LT . '/b' . GT if ($cmd eq 'B');
    539 16 100       95 return LT . 'code' . GT . $arg . LT . '/code' . GT if ($cmd eq 'C');
    540 15 100       101 return LT . 'code' . GT . $arg . LT . '/code' . GT if ($cmd eq 'F');
    541 14 100       131 return LT . 'i' . GT . $arg . LT . '/i' . GT if ($cmd eq 'I');
    542 12 100       92 return AMP . $arg . COL if ($cmd eq 'E');
    543              
    544             # if there is an L<> we have to take care a little bit more
    545 11 50       20 if ($cmd eq 'L') {
    546              
    547             # if we have this:
    548             # L
    549             # this means that CHI::Driver::File is the name to be displayed
    550             # and "File" is the link... which we direct to metacpan...
    551              
    552             # empty vars
    553 11         13 my $text = '';
    554 11         13 my $link = '';
    555              
    556             # if named we set the vars
    557 11 100       43 if ($arg =~ m/^(.*)\|(.*)$/) {
    558 5         10 $text = $1;
    559 5         9 $link = $2;
    560             }
    561              
    562             # in case this is not set, we set it to original value
    563 11 100       18 $link = $arg unless $link;
    564              
    565             # the case
    566             # L
    567             # for relative sections is not handled well here because we
    568             # don't know the module like that!
    569             # so we just print the text as is
    570 11 100 100     78 if($link =~ m%^/(.*)%) {
        100          
        100          
    571 2         4 my $section = $1;
    572 2 100       4 if ($text) {
    573 1         48 return "$text ($section)";
    574             }
    575             else {
    576 1         39 return DQUO . $section . DQUO;
    577             }
    578             # EXIT
    579             }
    580              
    581             # if the links seems to be http we also just return!
    582             elsif ($link =~ /^http.*$/
    583             or $link =~ /^.*\.{1}\w{2,5}$/ ) {
    584             # this is a weblink!
    585             # keep on going...
    586             }
    587              
    588             # if no special case we continue...
    589             elsif ($link =~ m%(.*)/(.*)%) {
    590 2         5 my $module = $1;
    591 2         4 my $section = $2;
    592 2         3 $section =~ s/"//;
    593              
    594 2 50 33     12 if ($module && $section) {
        0 0        
        0 0        
    595 2         5 $link = "$module#$section";
    596             }
    597             elsif ($module && not $section) {
    598 0         0 $link = $module;
    599             }
    600             elsif (not $module && $section) {
    601             # this case should not happen but you never know
    602             # (it should be handled in the first if!)
    603 0         0 return "\"$section\"";
    604             }
    605              
    606             # this URL should be valid now
    607 2         6 $link = "https://metacpan.org/module/$link";
    608              
    609             }
    610             # normal module name
    611             else {
    612             # this URL should be valid now
    613 2         5 $link = "https://metacpan.org/module/$link";
    614             }
    615              
    616             # in case this is not set, we set it to original value
    617 9 100       20 $text = $arg unless $text;
    618              
    619 9         402 return LT.'a href='.QUO.$link.QUO.GT.$text.LT.'/a'.GT
    620             }
    621              
    622             # if nothing matches we return the content unformated 'as is'
    623 0         0 return $arg;
    624             }
    625              
    626             sub parse {
    627 11     11 1 23 my ($parser, $input) = @_;
    628              
    629             # INPUT:
    630 11         70 my $input_fh = IO::String->new($input);
    631              
    632             # OUTPUT:
    633             # We create this IO-object because Pod::Parser does not provide
    634             # pure string-data as return of result data
    635 11         454 my $buffer4html; # this variable will contain the result!!!
    636 11         47 my $buffer4html_handle = IO::String->new($buffer4html);
    637              
    638             # we call the parser to parse, result will be in $buffer4html
    639 11         744 $parser->parse_from_filehandle($input_fh, $buffer4html_handle);
    640              
    641 11         33 return $buffer4html;
    642             };
    643              
    644             sub set_options {
    645 5     5 1 6 my $self = shift;
    646 5         8 my $args = shift;
    647              
    648 5 50       14 if (ref($args) eq "HASH") {
    649 5 100       17 $self->head0_mode($args->{head0_mode}) if (exists $args->{head0_mode});
    650 5 100       17 $self->pagemode ($args->{pagemode}) if (exists $args->{pagemode});
    651             }
    652             else {
    653 0         0 $self->debug_msg('Plugin options are not in a HASH');
    654             }
    655             }
    656              
    657             sub pagemode {
    658 25     25 1 41729 my ($self, $boolean) = @_;
    659              
    660 25 50       76 if (@_ > 1) {
    661 25         97 $self->{+P . 'pages'} = $boolean;
    662             }
    663             else {
    664 0         0 return $self->{+P . 'pages'};
    665             }
    666             }
    667              
    668             sub head0_mode {
    669 74     74 1 643 my ($self, $boolean) = @_;
    670              
    671 74 100       140 if (@_ > 1) {
    672 5         14 $self->{+P . 'head0_mode'} = $boolean;
    673             }
    674             else {
    675 69         270 return $self->{+P . 'head0_mode'};
    676             }
    677             }
    678              
    679             # encode_entities() from HTML::Entities does not translate it correctly
    680             # this is why I make it here manually as a quick fix
    681             # don't reall know where how to handle this utf8 problem for now...
    682             sub _html_enc {
    683 216     216   300 my $string = shift;
    684              
    685 216         611 $string = encode_entities($string);
    686             # ^
    687 216         2385 my $lt = LT; # |
    688 216         267 my $gt = GT; # |
    689 216         228 my $am = AMP; # |
    690 216         325 my $co = COL; # |-- don't change this order!
    691 216         220 my $qu = QUO; # |
    692 216         229 my $dqu= DQUO; # |
    693 216         537 $string =~ s/$lt/
    694 216         378 $string =~ s/$gt/>/g; # |
    695 216         342 $string =~ s/$am/&/g; # |
    696 216         320 $string =~ s/$co/;/g; # |
    697 216         322 $string =~ s/$qu/'/g; # |
    698 216         302 $string =~ s/$dqu/"/g; #<---|
    699              
    700 216         437 return $string;
    701             }
    702              
    703             ## replaces whitespace with html entitie
    704             sub _nbsp {
    705 1     1   2 my $string = shift;
    706              
    707 1         12 $string =~ s/\ / /g;
    708              
    709 1         3 return $string;
    710             }
    711              
    712             1;
    713              
    714             __END__