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   385516 use 5.006; use strict; use warnings; our $VERSION = q|0.02|;
  3     3   12  
  3     3   18  
  3         16  
  3         71  
  3         13  
  3         6  
  3         336  
3              
4             use overload
5 0     0   0 q|${}| => sub { $_[0]->generate(q|string|) },
6 3     3   1776 fallback => 1;
  3         5250  
  3         34  
7              
8             sub new {
9 4     4 1 437751 my $class = shift;
10 4 50 33     39 my $self = bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  0 100       0  
11 4   100     72 $self->{pod} ||= {};
12 4   100     19 $self->{width} ||= 100;
13 4         15 return $self;
14             }
15              
16 28     28 1 140 sub pod { $_[0]->{pod} }
17              
18 1     1 1 11 sub start { name(@_) }
19              
20 1     1 1 5 sub end { generate(@_) }
21              
22             sub name {
23 2     2 1 12 my ($self, $name, $abbr) = @_;
24 2         12 $self->pod->{$name} = __PACKAGE__->new(name => $name, width => $self->{width}, pod => []);
25 2 50       5 push @{ $self->pod->{$name}->pod }, {
  2         6  
26             identifier => q|head1|,
27             title => q|NAME|,
28             content => $name . ($abbr ? (q| - | . $abbr) : q||)
29             };
30 2         9 return $self->{pod}->{$name};
31             }
32              
33             sub generate {
34 8     8 1 675 my ($self, $type) = @_;
35 8 100       16 if (ref $self->pod eq q|HASH|) {
36 1         1 my %out;
37 1         2 for my $key (keys %{$self->pod}) {
  1         4  
38 1         2 $out{$key} = $self->pod->{$key}->generate();
39             }
40 1         4 return \%out;
41             }
42 7   100     24 $type ||= q|string|;
43 7         13 my $last_identifier = _last_identifier($self);
44 7 50       27 push @{$self->{pod}}, {
  0         0  
45             identifier => q|back|
46             } if ($last_identifier =~ m/item|over/);
47 7 100       30 push @{$self->pod}, {
  5         11  
48             identifier => q|cut|
49             } if ($last_identifier !~ m/none|cut/);
50 7         13 my $pod = q||;
51 7         8 $pod .= $self->generate_pod_section($_) for (@{ $self->pod });
  7         30  
52 7         13 my $method = sprintf(q|to_%s|, $type);
53 7   50     43 $self->$method($pod || q|empty|);
54             }
55              
56             sub add {
57 38     38 1 84 my ($self, $identifier, $title, $content) = @_;
58 38         57 my $has_ident = defined $identifier;
59 38 100 100     253 if (defined $content && ($identifier || "p") ne 'v' && $self->{width}) {
    100 100        
      66        
      66        
60 24         557 my @chars = split "", $content;
61 24         48 my $die = 0;
62 24         71 my ($string, $length) = ('', 0);
63 24         50 while (@chars) {
64 538         722 my $i = 0;
65 538   100     5595 $i++ while (defined $chars[$i] && $chars[$i] !~ m/(\s|\n)/);
66 538 100 100     1343 $length = 0 if ($i == 0 && $chars[$i] =~ m/\n/);
67 538   100     1232 $i ||= 1;
68             ($length + $i <= $self->{width}) ? do {
69 537   50     1321 $string .= join "", splice @chars, 0, $i || 1;
70 537         1130 $length += $i;
71 538 100       971 } : do {
72 1   50     7 $string .= "\n" . join "", splice @chars, 0, $i || 1;
73 1 50       6 $string =~ s/\s$//i && $i--;
74 1         4 $length = $i;
75             };
76             }
77 24         52 $content = $string;
78             } elsif ($has_ident && $identifier eq 'v') {
79 5         18 $identifier = $has_ident = undef;
80             }
81              
82 38 100       73 if ($has_ident) {
83 31 100       55 if ($identifier eq q|item|) {
84 10 100       22 if (_last_identifier($self) !~ m/item|over/) {
85 4         8 push @{$self->{pod}}, {
  4         32  
86             identifier => q|over|
87             };
88             }
89             } else {
90 21         53 my $last_identifier = _last_identifier($self);
91 21 100       86 if ($last_identifier =~ m/item|over/) {
92 4         6 push @{$self->{pod}}, {
  4         14  
93             identifier => q|back|
94             };
95             }
96 21 100       62 push @{$self->{pod}}, {
  18         92  
97             identifier => q|cut|
98             } if ($last_identifier !~ m/cut/);
99             }
100             }
101 38 100       55 push @{ $self->{pod} }, {
  38 100       206  
    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 3 my $self = shift;
110 2         5 $self->add(undef, undef, @_);
111 2         4 $self;
112             }
113              
114             sub v {
115 3     3 1 6 my $self = shift;
116 3         12 $self->add('v', undef, @_);
117 3         12 $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 568 my $self = shift;
128 3         10 $self->add(q|head2|, @_);
129 3         12 $self;
130             }
131              
132             sub h3 {
133 1     1 1 3 my $self = shift;
134 1         4 $self->add(q|head3|, @_);
135 1         4 $self;
136             }
137              
138             sub h4 {
139 1     1 1 3 my $self = shift;
140 1         22 $self->add(q|head4|, @_);
141 1         4 $self;
142             }
143              
144             sub item {
145 6     6 1 16 my $self = shift;
146 6         15 $self->add(q|item|, @_);
147 6         15 $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         10 $self->add(q|head1|, q|DESCRIPTION|, $self->_default_description_cb(@_));
159 2         12 $self;
160             }
161              
162             sub synopsis {
163 2     2 1 938 my $self = shift;
164 2         9 $self->add(q|head1|, q|SYNOPSIS|, undef);
165 2         11 $self->add(q|v|, undef, $self->_default_synopsis_cb(@_));
166 2         8 $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 6 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         24 ->license($args{license}, $args{name});
188 1         9 $self;
189             }
190              
191             sub author {
192 1     1 1 4 my $self = shift;
193 1         6 $self->add(q|head1|, q|AUTHOR|, $self->_default_author_cb(@_));
194 1         2 $self;
195             }
196              
197             sub formatted_author {
198 1     1 1 3 my ($self, $name, $email) = @_;
199 1         6 $email =~ s/\@/ at /g;
200 1         5 $self->add(q|head1|, q|AUTHOR|, sprintf(q|%s, C<< <%s> >>|, $name, $email));
201 1         7 $self
202             }
203              
204             sub bugs {
205 2     2 1 581 my ($self, $content) = @_;
206 2         10 $self->add(q|head1|, q|BUGS|, $self->_default_bugs_cb($content));
207 2         10 $self;
208             }
209              
210             sub support {
211 2     2 1 10 my ($self, $content, @items) = @_;
212 2         7 $self->add(q|head1|, q|SUPPORT|, $self->_default_support_cb($content));
213 2         9 @items = $self->_default_support_items_cb(@items);
214 2         7 $self->add(q|item|, @{$_}) for (@items);
  4         10  
215 2         35 $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     32 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     22 return $self->{synopsis_cb} && $self->{synopsis_cb}->($self, @_) || @_;
231             }
232              
233             sub _default_methods_cb {
234 2     2   5 my ($self) = shift;
235 2   33     33 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   2 my ($self) = shift;
245 1   33     6 return $self->{author_cb} && $self->{author_cb}->($self, @_) || @_;
246             }
247              
248             sub _default_bugs_cb {
249 2     2   4 my ($self, $content) = @_;
250             return $self->{bugs_cb}
251 2 50       13 ? $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   5 my ($self) = @_;
259 2         12 (my $formatted_name = $self->{name}) =~ s/\:\:/\-/g;
260 2         7 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         8 return $content;
270             }
271              
272             sub _default_support_cb {
273 2     2   6 my ($self, $content) = @_;
274             return $self->{support_cb}
275 2 50       93 ? $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   6 my ($self) = @_;
283 2         6 my $content = q|You can find documentation for this module with the perldoc command.|;
284 2         7 $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       20 ? $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   5 my ($self) = @_;
300 2         4 my @items = ();
301 2         35 (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         5 push @items, [
307             q|* Search CPAN|,
308             sprintf(q|L|, $formatted_name)
309             ];
310 2         9 return @items;
311             }
312              
313             sub acknowledgements {
314 2     2 1 5 my $self = shift;
315 2         10 $self->add(q|head1|, q|ACKNOWLEDGEMENTS|, $self->default_acknowledgements_cb(@_));
316 2         10 $self;
317             }
318              
319             sub default_acknowledgements_cb {
320 2     2 0 13 my ($self) = shift;
321 2   66     23 return $self->{acknowledgements_cb} && $self->{acknowledgements_cb}->($self, @_) || @_;
322             }
323              
324             sub license {
325 2     2 1 7 my ($self, $license, $name) = @_;
326 2         9 $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 5 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 5 my ($self, $author) = @_;
340 2   100     13 my $content = sprintf(qq|This software is Copyright (c) 2022 %s\n\n|, $author || q|by the author|);
341 2         6 $content .= q|This is free software, licensed under:|;
342 2         7 $content .= qq|\n\n The Artistic License 2.0 (GPL Compatible)|;
343             }
344              
345             sub generate_pod_section {
346 166     166 0 273 my ($self, $section) = @_;
347 166         321 my $pod = q||;
348 166 100       310 $pod .= sprintf(qq|\n\n=%s|, $section->{identifier}) if $section->{identifier};
349 166 100       313 $pod .= sprintf(q| %s|, $section->{title}) if $section->{title};
350 166 100       297 $pod .= sprintf(qq|\n\n%s|, $section->{content}) if $section->{content};
351 166         384 return $pod;
352             }
353              
354             sub to_string {
355 5     5 1 12 my ($self, $string) = @_;
356 5 50       14 return $_[0]->generate(q|string|) if (!$string);
357 5         32 $string =~ s/^\n*//g;
358 5         38 return $string;
359             }
360              
361             sub to_file {
362 1     1 1 5 my ($self, $string) = @_;
363 1 50       4 return $_[0]->generate(q|file|) if (!$string);
364 1         7 (my $file = $self->{name}) =~ s/\:\:/\//g;
365 1         3 $file .= '.pm';
366 1         530 require $file;
367 1         28 $file = $INC{$file};
368 1 50       31 open my $fh, "<", $file or die "Cannot open file for read/writing $file";
369 1         2 my $current = do { local $/; <$fh> };
  1         5  
  1         17  
370 1         8 close $fh;
371 1 50       10 die "no \_\_END\_\_ to code bailing on writing to the .pm file" unless $current =~ s/(\_\_END\_\_).*/$1/xmsg;
372 1         3 $current .= $string;
373 1         310 open my $wh, ">", $file;
374 1         6 print $wh $current;
375 1         214 close $wh;
376 1         12 return $string;
377             }
378              
379             sub to_seperate_file {
380 1     1 1 4 my ($self, $string) = @_;
381 1 50       4 return $_[0]->generate(q|seperate_file|) if (!$string);
382 1         7 (my $file = $self->{name}) =~ s/\:\:/\//g;
383 1         2 $file .= '.pm';
384 1         7 require $file;
385 1         2 $file = $INC{$file};
386 1         4 $file =~ s/pm$/pod/;
387 1         7 $string =~ s/^\n*//g;
388 1         83 open my $wh, ">", $file;
389 1         6 print $wh $string;
390 1         45 close $wh;
391 1         8 return $string;
392             }
393              
394             sub _last_identifier {
395 38     38   54 my $self = shift;
396 38         95 my ($i, $last_identifier) = -1;
397             $self->{pod}->[$i]
398             ? $self->{pod}->[$i]->{identifier}
399 38         64 ? do { $last_identifier = $self->{pod}->[$i]->{identifier}; 1 }
  38         80  
400             : $i--
401 38 100       157 : do { $last_identifier = q|none|; }
  0 50       0  
402             while (!$last_identifier);
403 38         125 return $last_identifier;
404             }
405              
406              
407             1;
408              
409             __END__