File Coverage

blib/lib/POD/Generate.pm
Criterion Covered Total %
statement 210 227 92.5
branch 56 74 75.6
condition 35 57 61.4
subroutine 45 51 88.2
pod 29 33 87.8
total 375 442 84.8


line stmt bran cond sub pod time code
1             package POD::Generate;
2 3     3   308560 use 5.006; use strict; use warnings; our $VERSION = q|0.03|;
  3     3   10  
  3     3   20  
  3         17  
  3         73  
  3         11  
  3         6  
  3         298  
3              
4             use overload
5 0     0   0 q|${}| => sub { $_[0]->generate(q|string|) },
6 3     3   1961 fallback => 1;
  3         4940  
  3         24  
7              
8             sub new {
9 4     4 1 334531 my $class = shift;
10 4 50 33     37 my $self = bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  0 100       0  
11 4   100     73 $self->{pod} ||= {};
12 4   100     15 $self->{width} ||= 100;
13 4         13 return $self;
14             }
15              
16 28     28 1 114 sub pod { $_[0]->{pod} }
17              
18 1     1 1 30 sub start { name(@_) }
19              
20 1     1 1 4 sub end { generate(@_) }
21              
22             sub name {
23 2     2 1 10 my ($self, $name, $abbr) = @_;
24 2         9 $self->pod->{$name} = __PACKAGE__->new(name => $name, width => $self->{width}, pod => []);
25 2 50       4 push @{ $self->pod->{$name}->pod }, {
  2         10  
26             identifier => q|head1|,
27             title => q|NAME|,
28             content => $name . ($abbr ? (q| - | . $abbr) : q||)
29             };
30 2         8 return $self->{pod}->{$name};
31             }
32              
33             sub generate {
34 8     8 1 606 my ($self, $type) = @_;
35 8 100       14 if (ref $self->pod eq q|HASH|) {
36 1         2 my %out;
37 1         1 for my $key (keys %{$self->pod}) {
  1         2  
38 1         2 $out{$key} = $self->pod->{$key}->generate();
39             }
40 1         3 return \%out;
41             }
42 7   100     20 $type ||= q|string|;
43 7         12 my $last_identifier = _last_identifier($self);
44 7 50       21 push @{$self->{pod}}, {
  0         0  
45             identifier => q|back|
46             } if ($last_identifier =~ m/item|over/);
47 7 100       23 push @{$self->pod}, {
  5         9  
48             identifier => q|cut|
49             } if ($last_identifier !~ m/none|cut/);
50 7         9 my $pod = q||;
51 7         8 $pod .= $self->generate_pod_section($_) for (@{ $self->pod });
  7         10  
52 7         9 my $method = sprintf(q|to_%s|, $type);
53 7   50     23 $self->$method($pod || q|empty|);
54             }
55              
56             sub add {
57 38     38 1 94 my ($self, $identifier, $title, $content) = @_;
58 38         58 my $has_ident = defined $identifier;
59 38 100 100     235 if (defined $content && ($identifier || "p") ne 'v' && $self->{width}) {
    100 100        
      66        
      66        
60 24         494 my @chars = split "", $content;
61 24         42 my $die = 0;
62 24         45 my ($string, $length) = ('', 0);
63 24         70 while (@chars) {
64 538         731 my $i = 0;
65 538   100     6036 $i++ while (defined $chars[$i] && $chars[$i] !~ m/(\s|\n)/);
66 538 100 100     1432 $length = 0 if ($i == 0 && $chars[$i] =~ m/\n/);
67 538   100     1322 $i ||= 1;
68             ($length + $i <= $self->{width}) ? do {
69 537   50     1349 $string .= join "", splice @chars, 0, $i || 1;
70 537         1249 $length += $i;
71 538 100       1002 } : do {
72 1   50     20 $string .= "\n" . join "", splice @chars, 0, $i || 1;
73 1 50       7 $string =~ s/\s$//i && $i--;
74 1         3 $length = $i;
75             };
76             }
77 24         54 $content = $string;
78             } elsif ($has_ident && $identifier eq 'v') {
79 5         18 $identifier = $has_ident = undef;
80             }
81              
82 38 100       78 if ($has_ident) {
83 31 100       55 if ($identifier eq q|item|) {
84 10 100       26 if (_last_identifier($self) !~ m/item|over/) {
85 4         8 push @{$self->{pod}}, {
  4         33  
86             identifier => q|over|
87             };
88             }
89             } else {
90 21         58 my $last_identifier = _last_identifier($self);
91 21 100       124 if ($last_identifier =~ m/item|over/) {
92 4         7 push @{$self->{pod}}, {
  4         17  
93             identifier => q|back|
94             };
95             }
96 21 100       58 push @{$self->{pod}}, {
  18         86  
97             identifier => q|cut|
98             } if ($last_identifier !~ m/cut/);
99             }
100             }
101 38 100       56 push @{ $self->{pod} }, {
  38 100       226  
    100          
102             (defined $identifier ? (identifier => $identifier) : ()),
103             (defined $title ? (title => $title) : ()),
104             (defined $content ? (content => $content) : ())
105             };
106             }
107              
108             sub p {
109 2     2 1 2 my $self = shift;
110 2         4 $self->add(undef, undef, @_);
111 2         4 $self;
112             }
113              
114             sub v {
115 3     3 1 8 my $self = shift;
116 3         10 $self->add('v', undef, @_);
117 3         39 $self;
118             }
119              
120             sub h1 {
121 0     0 1 0 my $self = shift;
122 0         0 $self->add(q|head1|, @_);
123 0         0 $self;
124             }
125              
126             sub h2 {
127 3     3 1 635 my $self = shift;
128 3         10 $self->add(q|head2|, @_);
129 3         9 $self;
130             }
131              
132             sub h3 {
133 1     1 1 3 my $self = shift;
134 1         4 $self->add(q|head3|, @_);
135 1         3 $self;
136             }
137              
138             sub h4 {
139 1     1 1 3 my $self = shift;
140 1         17 $self->add(q|head4|, @_);
141 1         4 $self;
142             }
143              
144             sub item {
145 6     6 1 21 my $self = shift;
146 6         24 $self->add(q|item|, @_);
147 6         32 $self;
148             }
149              
150             sub version {
151 0     0 1 0 my $self = shift;
152 0         0 $self->add(q|head1|, q|VERSION|, $self->_default_version_cb(@_));
153 0         0 $self;
154             }
155              
156             sub description {
157 2     2 1 8 my $self = shift;
158 2         9 $self->add(q|head1|, q|DESCRIPTION|, $self->_default_description_cb(@_));
159 2         11 $self;
160             }
161              
162             sub synopsis {
163 2     2 1 881 my $self = shift;
164 2         10 $self->add(q|head1|, q|SYNOPSIS|, undef);
165 2         9 $self->add(q|v|, undef, $self->_default_synopsis_cb(@_));
166 2         34 $self;
167             }
168              
169             sub methods {
170 2     2 1 4 my $self = shift;
171 2         9 $self->add(q|head1|, q|METHODS|, $self->_default_methods_cb(@_));
172 2         6 $self;
173             }
174              
175             sub exports {
176 0     0 1 0 my $self = shift;
177 0         0 $self->add(q|head1|, q|EXPORTS|, $self->_default_exports_cb(@_));
178 0         0 $self;
179             }
180              
181             sub footer {
182 1     1 1 5 my ($self, %args) = @_;
183             $self->formatted_author($args{name}, $args{email})
184             ->bugs($args{bugs})
185 1         6 ->support($args{support}, @{$args{support_items}})
186             ->acknowledgements($args{acknowledgements})
187 1         18 ->license($args{license}, $args{name});
188 1         8 $self;
189             }
190              
191             sub author {
192 1     1 1 4 my $self = shift;
193 1         3 $self->add(q|head1|, q|AUTHOR|, $self->_default_author_cb(@_));
194 1         2 $self;
195             }
196              
197             sub formatted_author {
198 1     1 1 4 my ($self, $name, $email) = @_;
199 1         6 $email =~ s/\@/ at /g;
200 1         6 $self->add(q|head1|, q|AUTHOR|, sprintf(q|%s, C<< <%s> >>|, $name, $email));
201 1         6 $self
202             }
203              
204             sub bugs {
205 2     2 1 906 my ($self, $content) = @_;
206 2         11 $self->add(q|head1|, q|BUGS|, $self->_default_bugs_cb($content));
207 2         11 $self;
208             }
209              
210             sub support {
211 2     2 1 8 my ($self, $content, @items) = @_;
212 2         47 $self->add(q|head1|, q|SUPPORT|, $self->_default_support_cb($content));
213 2         11 @items = $self->_default_support_items_cb(@items);
214 2         8 $self->add(q|item|, @{$_}) for (@items);
  4         11  
215 2         41 $self;
216             }
217              
218             sub _default_version_cb {
219 0     0   0 my ($self) = shift;
220 0   0     0 return $self->{version_cb} && $self->{version_cb}->($self, @_) || @_;
221             }
222              
223             sub _default_description_cb {
224 2     2   4 my ($self) = shift;
225 2   33     17 return $self->{description_cb} && $self->{description_cb}->($self, @_) || @_;
226             }
227              
228             sub _default_synopsis_cb {
229 2     2   13 my ($self) = shift;
230 2   33     27 return $self->{synopsis_cb} && $self->{synopsis_cb}->($self, @_) || @_;
231             }
232              
233             sub _default_methods_cb {
234 2     2   3 my ($self) = shift;
235 2   33     26 return $self->{methods_cb} && $self->{methods_cb}->($self, @_) || @_;
236             }
237              
238             sub _default_exports_cb {
239 0     0   0 my ($self) = shift;
240 0   0     0 return $self->{exports_cb} && $self->{exports_cb}->($self, @_) || @_;
241             }
242              
243             sub _default_author_cb {
244 1     1   3 my ($self) = shift;
245 1   33     8 return $self->{author_cb} && $self->{author_cb}->($self, @_) || @_;
246             }
247              
248             sub _default_bugs_cb {
249 2     2   6 my ($self, $content) = @_;
250             return $self->{bugs_cb}
251 2 50       21 ? $self->{bugs_cb}->($self, $content)
    50          
252             : defined $content
253             ? $content
254             : $self->_default_bugs_content();
255             }
256              
257             sub _default_bugs_content {
258 2     2   6 my ($self) = @_;
259 2         13 (my $formatted_name = $self->{name}) =~ s/\:\:/\-/g;
260 2         9 my $content = sprintf(
261             qq|Please report any bugs or feature requests to C, or through\n|,
262             lc($formatted_name)
263             );
264 2         5 $content .= sprintf(
265             qq|the web interface at L. I will\n|,
266             $formatted_name
267             );
268 2         5 $content .= q|be notified, and then you'll automatically be notified of progress on your bug as I make changes.|;
269 2         10 return $content;
270             }
271              
272             sub _default_support_cb {
273 2     2   9 my ($self, $content) = @_;
274             return $self->{support_cb}
275 2 50       30 ? $self->{support_cb}->($self, $content)
    50          
276             : defined $content
277             ? $content
278             : $self->_default_support_content();
279             }
280              
281             sub _default_support_content {
282 2     2   5 my ($self) = @_;
283 2         5 my $content = q|You can find documentation for this module with the perldoc command.|;
284 2         8 $content .= sprintf(qq|\n\n perldoc %s\n\n|, $self->{name});
285 2         5 $content .= q|You can also look for information at:|;
286 2         8 return $content;
287             }
288              
289             sub _default_support_items_cb {
290 2     2   8 my ($self, @items) = @_;
291             return $self->{support_items_cb}
292 2 50       15 ? $self->{support_items_cb}->($self, @items)
    50          
293             : scalar @items
294             ? @items
295             : $self->_default_support_items();
296             }
297              
298             sub _default_support_items {
299 2     2   6 my ($self) = @_;
300 2         5 my @items = ();
301 2         12 (my $formatted_name = $self->{name}) =~ s/\:\:/\-/g;
302 2         9 push @items, [
303             q|* RT: CPAN's request tracker (report bugs here)|,
304             sprintf(q|L|, $formatted_name)
305             ];
306 2         7 push @items, [
307             q|* Search CPAN|,
308             sprintf(q|L|, $formatted_name)
309             ];
310 2         8 return @items;
311             }
312              
313             sub acknowledgements {
314 2     2 1 6 my $self = shift;
315 2         17 $self->add(q|head1|, q|ACKNOWLEDGEMENTS|, $self->default_acknowledgements_cb(@_));
316 2         12 $self;
317             }
318              
319             sub default_acknowledgements_cb {
320 2     2 0 13 my ($self) = shift;
321 2   66     24 return $self->{acknowledgements_cb} && $self->{acknowledgements_cb}->($self, @_) || @_;
322             }
323              
324             sub license {
325 2     2 1 8 my ($self, $license, $name) = @_;
326 2         10 $self->add(q|head1|, q|LICENSE AND COPYRIGHT|, $self->default_license_cb($license, $name));
327             }
328              
329             sub default_license_cb {
330 2     2 0 7 my ($self, $license, $name) = @_;
331             return $self->{license_cb}
332 2 50       14 ? $self->{license_cb}->($self, $license, $name)
    50          
333             : defined $license
334             ? $license
335             : $self->default_license_content($name);
336             }
337              
338             sub default_license_content {
339 2     2 0 6 my ($self, $author) = @_;
340 2   100     17 my $content = sprintf(qq|This software is Copyright (c) 2022 %s\n\n|, $author || q|by the author|);
341 2         7 $content .= q|This is free software, licensed under:|;
342 2         9 $content .= qq|\n\n The Artistic License 2.0 (GPL Compatible)|;
343             }
344              
345             sub generate_pod_section {
346 166     166 0 172 my ($self, $section) = @_;
347 166         175 my $pod = q||;
348 166 100       232 $pod .= sprintf(qq|\n\n=%s|, $section->{identifier}) if $section->{identifier};
349 166 100       205 $pod .= sprintf(q| %s|, $section->{title}) if $section->{title};
350 166 100       216 $pod .= sprintf(qq|\n\n%s|, $section->{content}) if $section->{content};
351 166         253 return $pod;
352             }
353              
354             sub to_string {
355 5     5 1 18 my ($self, $string) = @_;
356 5 50       8 return $_[0]->generate(q|string|) if (!$string);
357 5         27 $string =~ s/^\n*//g;
358 5         16 return $string;
359             }
360              
361             sub to_file {
362 1     1 1 3 my ($self, $string) = @_;
363 1 50       4 return $_[0]->generate(q|file|) if (!$string);
364 1         4 (my $file = $self->{name}) =~ s/\:\:/\//g;
365 1         2 $file .= '.pm';
366 1         393 require $file;
367 1         12 $file = $INC{$file};
368 1 50       26 open my $fh, "<", $file or die "Cannot open file for read/writing $file";
369 1         2 my $current = do { local $/; <$fh> };
  1         4  
  1         14  
370 1         6 close $fh;
371 1 50       11 die "no \_\_END\_\_ to code bailing on writing to the .pm file" unless $current =~ s/(\_\_END\_\_).*/$1/xmsg;
372 1         2 $current .= $string;
373 1         147 open my $wh, ">", $file;
374 1         4 print $wh $current;
375 1         161 close $wh;
376 1         10 return $string;
377             }
378              
379             sub to_seperate_file {
380 1     1 1 3 my ($self, $string) = @_;
381 1 50       4 return $_[0]->generate(q|seperate_file|) if (!$string);
382 1         4 (my $file = $self->{name}) =~ s/\:\:/\//g;
383 1         1 $file .= '.pm';
384 1         5 require $file;
385 1         3 $file = $INC{$file};
386 1         4 $file =~ s/pm$/pod/;
387 1         4 $string =~ s/^\n*//g;
388 1         96 open my $wh, ">", $file;
389 1         19 print $wh $string;
390 1         198 close $wh;
391 1         11 return $string;
392             }
393              
394             sub _last_identifier {
395 38     38   50 my $self = shift;
396 38         106 my ($i, $last_identifier) = -1;
397             $self->{pod}->[$i]
398             ? $self->{pod}->[$i]->{identifier}
399 38         65 ? do { $last_identifier = $self->{pod}->[$i]->{identifier}; 1 }
  38         71  
400             : $i--
401 38 100       150 : do { $last_identifier = q|none|; }
  0 50       0  
402             while (!$last_identifier);
403 38         114 return $last_identifier;
404             }
405              
406              
407             1;
408              
409             __END__