File Coverage

blib/lib/POD/Generate.pm
Criterion Covered Total %
statement 211 228 92.5
branch 56 74 75.6
condition 35 57 61.4
subroutine 45 51 88.2
pod 29 33 87.8
total 376 443 84.8


line stmt bran cond sub pod time code
1             package POD::Generate;
2 3     3   175590 use 5.006; use strict; use warnings; our $VERSION = q|0.01|;
  3     3   29  
  3     3   14  
  3         4  
  3         56  
  3         12  
  3         4  
  3         206  
3              
4             use overload
5 0     0   0 q|${}| => sub { $_[0]->generate(q|string|) },
6 3     3   2888 fallback => 1;
  3         2429  
  3         24  
7              
8             sub new {
9 4     4 1 150 my $class = shift;
10 4 50 33     30 my $self = bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  0 100       0  
11 4   100     62 $self->{pod} ||= {};
12 4   100     13 $self->{width} ||= 100;
13 4         10 return $self;
14             }
15              
16 28     28 1 96 sub pod { $_[0]->{pod} }
17              
18 1     1 1 7 sub start { name(@_) }
19              
20 1     1 1 3 sub end { generate(@_) }
21              
22             sub name {
23 2     2 1 10 my ($self, $name, $abbr) = @_;
24 2         7 $self->pod->{$name} = __PACKAGE__->new(name => $name, width => $self->{width}, pod => []);
25 2 50       4 push @{ $self->pod->{$name}->pod }, {
  2         4  
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 517 my ($self, $type) = @_;
35 8 100       16 if (ref $self->pod eq q|HASH|) {
36 1         2 my %out;
37 1         2 for my $key (keys %{$self->pod}) {
  1         3  
38 1         3 $out{$key} = $self->pod->{$key}->generate();
39             }
40 1         5 return \%out;
41             }
42 7   100     25 $type ||= q|string|;
43 7         11 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       29 push @{$self->pod}, {
  5         12  
48             identifier => q|cut|
49             } if ($last_identifier !~ m/none|cut/);
50 7         9 my $pod = q||;
51 7         9 $pod .= $self->generate_pod_section($_) for (@{ $self->pod });
  7         11  
52 7         13 my $method = sprintf(q|to_%s|, $type);
53 7   50     34 $self->$method($pod || q|empty|);
54             }
55              
56             sub add {
57 40     40 1 71 my ($self, $identifier, $title, $content) = @_;
58 40         72 my $has_ident = defined $identifier;
59 40 100 100     186 if (defined $content && ($identifier || "p") ne 'v' && $self->{width}) {
    100 100        
      66        
      66        
60 26         318 my @chars = split "", $content;
61 26         37 my $die = 0;
62 26         41 my ($string, $length) = ('', 0);
63 26         47 while (@chars) {
64 540         583 my $i = 0;
65 540   100     4251 $i++ while (defined $chars[$i] && $chars[$i] !~ m/(\s|\n)/);
66 540 100 100     1079 $length = 0 if ($i == 0 && $chars[$i] =~ m/\n/);
67 540   100     996 $i ||= 1;
68             ($length + $i <= $self->{width}) ? do {
69 539   50     1035 $string .= join "", splice @chars, 0, $i || 1;
70 539         877 $length += $i;
71 540 100       768 } : do {
72 1   50     4 $string .= "\n" . join "", splice @chars, 0, $i || 1;
73 1 50       4 $string =~ s/\s$//i && $i--;
74 1         2 $length = $i;
75             };
76             }
77 26         45 $content = $string;
78             } elsif ($has_ident && $identifier eq 'v') {
79 5         8 $identifier = $has_ident = undef;
80             }
81              
82 40 100       61 if ($has_ident) {
83 33 100       47 if ($identifier eq q|item|) {
84 12 100       23 if (_last_identifier($self) !~ m/item|over/) {
85 4         7 push @{$self->{pod}}, {
  4         21  
86             identifier => q|over|
87             };
88             }
89             } else {
90 21         41 my $last_identifier = _last_identifier($self);
91 21 100       61 if ($last_identifier =~ m/item|over/) {
92 4         7 push @{$self->{pod}}, {
  4         21  
93             identifier => q|back|
94             };
95             }
96 21 100       106 push @{$self->{pod}}, {
  18         54  
97             identifier => q|cut|
98             } if ($last_identifier !~ m/cut/);
99             }
100             }
101 40 100       46 push @{ $self->{pod} }, {
  40 100       181  
    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         6 $self->add(undef, undef, @_);
111 2         3 $self;
112             }
113              
114             sub v {
115 3     3 1 5 my $self = shift;
116 3         8 $self->add('v', undef, @_);
117 3         9 $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 499 my $self = shift;
128 3         11 $self->add(q|head2|, @_);
129 3         9 $self;
130             }
131              
132             sub h3 {
133 1     1 1 2 my $self = shift;
134 1         4 $self->add(q|head3|, @_);
135 1         3 $self;
136             }
137              
138             sub h4 {
139 1     1 1 2 my $self = shift;
140 1         4 $self->add(q|head4|, @_);
141 1         2 $self;
142             }
143              
144             sub item {
145 6     6 1 12 my $self = shift;
146 6         14 $self->add(q|item|, @_);
147 6         23 $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 7 my $self = shift;
158 2         10 $self->add(q|head1|, q|DESCRIPTION|, $self->_default_description_cb(@_));
159 2         6 $self;
160             }
161              
162             sub synopsis {
163 2     2 1 774 my $self = shift;
164 2         7 $self->add(q|head1|, q|SYNOPSIS|, undef);
165 2         8 $self->add(q|v|, undef, $self->_default_synopsis_cb(@_));
166 2         7 $self;
167             }
168              
169             sub methods {
170 2     2 1 4 my $self = shift;
171 2         10 $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         4 ->support($args{support}, @{$args{support_items}})
186             ->acknowledgements($args{acknowledgements})
187 1         13 ->license($args{license}, $args{name});
188 1         6 $self;
189             }
190              
191             sub author {
192 1     1 1 5 my $self = shift;
193 1         4 $self->add(q|head1|, q|AUTHOR|, $self->_default_author_cb(@_));
194 1         3 $self;
195             }
196              
197             sub formatted_author {
198 1     1 1 2 my ($self, $name, $email) = @_;
199 1         4 $email =~ s/\@/ at /g;
200 1         7 $self->add(q|head1|, q|AUTHOR|, sprintf(q|%s, C<< <%s> >>|, $name, $email));
201 1         4 $self
202             }
203              
204             sub bugs {
205 2     2 1 438 my ($self, $content) = @_;
206 2         9 $self->add(q|head1|, q|BUGS|, $self->_default_bugs_cb($content));
207 2         8 $self;
208             }
209              
210             sub support {
211 2     2 1 8 my ($self, $content, @items) = @_;
212 2         17 $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);
  6         13  
215 2         11 $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   6 my ($self) = shift;
225 2   33     27 return $self->{description_cb} && $self->{description_cb}->($self, @_) || @_;
226             }
227              
228             sub _default_synopsis_cb {
229 2     2   5 my ($self) = shift;
230 2   33     16 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     14 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     8 return $self->{author_cb} && $self->{author_cb}->($self, @_) || @_;
246             }
247              
248             sub _default_bugs_cb {
249 2     2   5 my ($self, $content) = @_;
250             return $self->{bugs_cb}
251 2 50       18 ? $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   13 my ($self) = @_;
259 2         15 (my $formatted_name = $self->{name}) =~ s/\:\:/\-/g;
260 2         13 my $content = sprintf(
261             qq|Please report any bugs or feature requests to C, or through\n|,
262             lc($formatted_name)
263             );
264 2         7 $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   4 my ($self, $content) = @_;
274             return $self->{support_cb}
275 2 50       13 ? $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   4 my ($self) = @_;
283 2         4 my $content = q|You can find documentation for this module with the perldoc command.|;
284 2         10 $content .= sprintf(qq|\n\n perldoc %s\n\n|, $self->{name});
285 2         4 $content .= q|You can also look for information at:|;
286 2         7 return $content;
287             }
288              
289             sub _default_support_items_cb {
290 2     2   7 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         3 my @items = ();
301 2         8 (my $formatted_name = $self->{name}) =~ s/\:\:/\-/g;
302 2         11 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|* CPAN Ratings|,
308             sprintf(q|L|, $formatted_name)
309             ];
310 2         7 push @items, [
311             q|* Search CPAN|,
312             sprintf(q|L|, $formatted_name)
313             ];
314 2         7 return @items;
315             }
316              
317             sub acknowledgements {
318 2     2 1 4 my $self = shift;
319 2         7 $self->add(q|head1|, q|ACKNOWLEDGEMENTS|, $self->default_acknowledgements_cb(@_));
320 2         9 $self;
321             }
322              
323             sub default_acknowledgements_cb {
324 2     2 0 4 my ($self) = shift;
325 2   66     16 return $self->{acknowledgements_cb} && $self->{acknowledgements_cb}->($self, @_) || @_;
326             }
327              
328             sub license {
329 2     2 1 5 my ($self, $license, $name) = @_;
330 2         16 $self->add(q|head1|, q|LICENSE AND COPYRIGHT|, $self->default_license_cb($license, $name));
331             }
332              
333             sub default_license_cb {
334 2     2 0 8 my ($self, $license, $name) = @_;
335             return $self->{license_cb}
336 2 50       13 ? $self->{license_cb}->($self, $license, $name)
    50          
337             : defined $license
338             ? $license
339             : $self->default_license_content($name);
340             }
341              
342             sub default_license_content {
343 2     2 0 5 my ($self, $author) = @_;
344 2   100     13 my $content = sprintf(qq|This software is Copyright (c) 2022 %s\n\n|, $author || q|by the author|);
345 2         27 $content .= q|This is free software, licensed under:|;
346 2         21 $content .= qq|\n\n The Artistic License 2.0 (GPL Compatible)|;
347             }
348              
349             sub generate_pod_section {
350 169     169 0 233 my ($self, $section) = @_;
351 169         174 my $pod = q||;
352 169 100       343 $pod .= sprintf(qq|\n\n=%s|, $section->{identifier}) if $section->{identifier};
353 169 100       273 $pod .= sprintf(q| %s|, $section->{title}) if $section->{title};
354 169 100       259 $pod .= sprintf(qq|\n\n%s|, $section->{content}) if $section->{content};
355 169         369 return $pod;
356             }
357              
358             sub to_string {
359 5     5 1 11 my ($self, $string) = @_;
360 5 50       10 return $_[0]->generate(q|string|) if (!$string);
361 5         27 $string =~ s/^\n*//g;
362 5         15 return $string;
363             }
364              
365             sub to_file {
366 1     1 1 7 my ($self, $string) = @_;
367 1 50       9 return $_[0]->generate(q|file|) if (!$string);
368 1         9 (my $file = $self->{name}) =~ s/\:\:/\//g;
369 1         3 $file .= '.pm';
370 1         482 require $file;
371 1         15 $file = $INC{$file};
372 1 50       31 open my $fh, "<", $file or die "Cannot open file for read/writing $file";
373 1         3 my $current = do { local $/; <$fh> };
  1         5  
  1         19  
374 1         9 close $fh;
375 1 50       12 die "no \_\_END\_\_ to code bailing on writing to the .pm file" unless $current =~ s/(\_\_END\_\_).*/$1/xmsg;
376 1         3 $current .= $string;
377 1         75 open my $wh, ">", $file;
378 1         7 print $wh $current;
379 1         107 close $wh;
380 1         9 return $string;
381             }
382              
383             sub to_seperate_file {
384 1     1 1 4 my ($self, $string) = @_;
385 1 50       4 return $_[0]->generate(q|seperate_file|) if (!$string);
386 1         4 (my $file = $self->{name}) =~ s/\:\:/\//g;
387 1         3 $file .= '.pm';
388 1         5 require $file;
389 1         2 $file = $INC{$file};
390 1         5 $file =~ s/pm$/pod/;
391 1         5 $string =~ s/^\n*//g;
392 1         50 open my $wh, ">", $file;
393 1         13 print $wh $string;
394 1         51 close $wh;
395 1         8 return $string;
396             }
397              
398             sub _last_identifier {
399 40     40   47 my $self = shift;
400 40         54 my ($i, $last_identifier) = -1;
401             $self->{pod}->[$i]
402             ? $self->{pod}->[$i]->{identifier}
403 40         76 ? do { $last_identifier = $self->{pod}->[$i]->{identifier}; 1 }
  40         62  
404             : $i--
405 40 100       113 : do { $last_identifier = q|none|; }
  0 50       0  
406             while (!$last_identifier);
407 40         94 return $last_identifier;
408             }
409              
410              
411             1;
412              
413             __END__