File Coverage

blib/lib/Dist/Zilla/Plugin/AlienBase/Doc.pm
Criterion Covered Total %
statement 66 69 95.6
branch 16 24 66.6
condition n/a
subroutine 10 10 100.0
pod 0 5 0.0
total 92 108 85.1


line stmt bran cond sub pod time code
1             package Dist::Zilla::Plugin::AlienBase::Doc 0.30 {
2              
3 2     2   256840 use 5.014;
  2         16  
4 2     2   487 use Moose;
  2         392961  
  2         16  
5 2     2   13417 use Carp ();
  2         7  
  2         121  
6              
7             # ABSTRACT: Generate boilerplate documentation for Alien::Base subclass
8              
9              
10             with 'Dist::Zilla::Role::FileMunger';
11             with 'Dist::Zilla::Role::FileFinderUser' => { default_finders => [ ':InstallModules', ':ExecFiles' ] };
12             with 'Dist::Zilla::Role::PPI';
13             with 'Dist::Zilla::Role::TextTemplate';
14              
15 2     2   1139 use Sub::Exporter::ForMethods 'method_installer';
  2         1783  
  2         10  
16             use Data::Section 0.004 # fixed header_re
17 2     2   1407 { installer => method_installer }, '-setup';
  2         3633  
  2         14  
18              
19              
20             has class_name => (
21             is => 'ro',
22             isa => 'Str',
23             lazy => 1,
24             default => sub {
25             my($self) = @_;
26             my $name = $self->zilla->name;
27             $name =~ s{-}{::};
28             $name;
29             },
30             );
31              
32              
33             has min_version => (
34             is => 'ro',
35             isa => 'Str',
36             default => '0',
37             );
38              
39              
40             has type => (
41             is => 'ro',
42             isa => 'ArrayRef[Str]',
43             default => sub { [ 'library' ] },
44             );
45              
46             has name => (
47             is => 'ro',
48             isa => 'Str',
49             required => 1,
50             );
51              
52              
53             has see_also => (
54             is => 'ro',
55             isa => 'ArrayRef[Str]',
56             default => sub { [ 'Alien', 'Alien::Base', 'Alien::Build::Manual::AlienUser' ] },
57             );
58              
59             around mvp_multivalue_args => sub {
60             my($orig, $self) = @_;
61             ($self->$orig, 'type', 'see_also');
62             };
63              
64             sub render_synopsis
65             {
66 4     4 0 47531 my($self) = @_;
67              
68 4         9 my $str = "\n=head1 SYNOPSIS";
69              
70 4         6 foreach my $type (@{ $self->type })
  4         118  
71             {
72 6         2033 my $template;
73              
74 6 100       31 if($type eq 'library')
    100          
    50          
75             {
76 2         10 $template = $self->section_data('__SYNOPSIS_LIBRARY__')
77             }
78             elsif($type eq 'tool')
79             {
80 2         42 $template = $self->section_data('__SYNOPSIS_TOOL__')
81             }
82             elsif($type eq 'ffi')
83             {
84 2         7 $template = $self->section_data('__SYNOPSIS_FFI__')
85             }
86             else
87             {
88 0         0 Carp::croak("unknown type: $type");
89             }
90              
91 6         2674 $template = $$template;
92 6         164 $template =~ s{\s*$}{};
93              
94 6         13 $str .= "\n\n";
95 6 50       192 $str .= $self->fill_in_string($template, {
96             class => $self->class_name,
97             name => $self->name,
98             version => $self->min_version,
99 0         0 optversion => $self->min_version ? " @{[ $self->min_version ]}" : '',
100             });
101             }
102              
103 4         3839 $str .= "\n\n=cut\n\n";
104              
105 4         21 $str;
106             }
107              
108             sub render_description
109             {
110 2     2 0 1552 my($self) = @_;
111              
112 2         6 my $template = $self->section_data('__DESCRIPTION__');
113              
114 2         80 $template = $$template;
115 2         87 $template =~ s{\s*$}{};
116              
117 2         7 my $str = "\n";
118              
119 2 50       70 $str .= $self->fill_in_string($template, {
120             class => $self->class_name,
121             name => $self->name,
122             version => $self->min_version,
123 0         0 optversion => $self->min_version ? " @{[ $self->min_version ]}" : '',
124             });
125              
126 2         1482 $str .= "\n\n";
127              
128 2         7 $str;
129             }
130              
131             sub render_see_also
132             {
133 2     2 0 8 my($self) = @_;
134              
135 2         6 my $str = "\n=head1 SEE ALSO\n\n";
136 2         4 $str .= join ', ', map { "L<$_>" } @{ $self->see_also };
  5         16  
  2         59  
137 2         6 $str .= "\n\n=cut\n\n";
138              
139 2         7 $str;
140             }
141              
142             sub munge_files
143             {
144 1     1 0 9226 my($self) = @_;
145 1         2 $self->munge_file($_) for @{ $self->found_files };
  1         6  
146 1         216 return;
147             }
148              
149             sub munge_file
150             {
151 1     1 0 1222 my($self, $file) = @_;
152              
153 1         6 my $doc = $self->ppi_document_for_file($file);
154              
155 1 50       94999 return unless defined $doc;
156              
157 1         7 my $comments = $doc->find('PPI::Token::Comment');
158 1         848 my $modified = 0;
159              
160 1 50       3 foreach my $comment (@{ $comments || [] })
  1         5  
161             {
162 3 50       9 if($comment =~ /^\s*##?\s*ALIEN (SYNOPSIS|DESCRIPTION|SEE ALSO)\s*$/)
163             {
164 3         44 my $type = $1;
165 3 100       14 if($type eq 'SYNOPSIS')
    100          
    50          
166             {
167 1         5 $comment->set_content($self->render_synopsis);
168             }
169             elsif($type eq 'DESCRIPTION')
170             {
171 1         5 $comment->set_content($self->render_description);
172             }
173             elsif($type eq 'SEE ALSO')
174             {
175 1         3 $comment->set_content($self->render_see_also);
176             }
177 3         12 $modified = 1;
178             }
179             }
180              
181 1 50       3 if($modified)
182             {
183 1         6 $self->save_ppi_document_to_file( $doc, $file);
184 1         1366 $self->log_debug([ 'adding ALIEN documentation to %s', $file->name ]);
185             }
186              
187 1         139 return;
188             }
189              
190             __PACKAGE__->meta->make_immutable;
191              
192             }
193              
194             package Dist::Zilla::Plugin::AlienBase::Doc;
195              
196             1;
197              
198             =pod
199              
200             =encoding UTF-8
201              
202             =head1 NAME
203              
204             Dist::Zilla::Plugin::AlienBase::Doc - Generate boilerplate documentation for Alien::Base subclass
205              
206             =head1 VERSION
207              
208             version 0.30
209              
210             =head1 SYNOPSIS
211              
212             In your dist.ini:
213              
214             [AlienBase::Doc]
215             name = libfoo
216              
217             In your Alien/Foo.pm:
218              
219             package Alien::Foo;
220            
221             use strict;
222             use warnings;
223             use base qw( Alien::Base );
224            
225             # ALIEN SYNOPSIS
226             # ALIEN DESCRIPTION
227             # ALIEN SEE ALSO
228            
229             1;
230              
231             =head1 DESCRIPTION
232              
233             This plugin generates some boiler plat documentation for your
234             L<Alien::Base> based L<Alien> module. It will find the special codes
235             C<ALIEN SYNOPSIS>, C<ALIEN DESCRIPTION>, and C<ALIEN SEE ALSO> and
236             replace them with the appropriate boilerplate POD documentation for how
237             to use the module. The generated synopsis and see also sections are
238             probably good enough as is. The description is a little more basic, and
239             you may want to write a more detailed description yourself. It is, at
240             least, better than nothing though!
241              
242             =head1 ATTRIBUTES
243              
244             =head2 class_name
245              
246             The name of the L<Alien::Base> subclass. The default is based on the
247             distribution's main module.
248              
249             =head2 min_version
250              
251             The minimum version to suggest using as a prereq.
252              
253             =head2 type
254              
255             Types of the L<Alien>. This can be specified multiple times. Valid types:
256              
257             =over 4
258              
259             =item library
260              
261             =item tool
262              
263             =item ffi
264              
265             =back
266              
267             =head2 see_also
268              
269             List of modules to refer to in the C<SEE ALSO> section. By default this is
270              
271             =over 4
272              
273             =item L<Alien>
274              
275             =item L<Alien::Base>
276              
277             =item L<Alien::Build::Manual::AlienUser>
278              
279             =back
280              
281             =head1 AUTHOR
282              
283             Graham Ollis <plicease@cpan.org>
284              
285             =head1 COPYRIGHT AND LICENSE
286              
287             This software is copyright (c) 2017 by Graham Ollis.
288              
289             This is free software; you can redistribute it and/or modify it under
290             the same terms as the Perl 5 programming language system itself.
291              
292             =cut
293              
294             __DATA__
295              
296             __[ __SYNOPSIS_LIBRARY__ ]__
297             In your Makefile.PL:
298              
299             use ExtUtils::MakeMaker;
300             use Alien::Base::Wrapper ();
301              
302             WriteMakefile(
303             Alien::Base::Wrapper->new('{{ $class }}')->mm_args2(
304             # MakeMaker args
305             NAME => 'Kafka::Librd',
306             ...
307             ),
308             );
309              
310             In your Build.PL:
311              
312             use Module::Build;
313             use Alien::Base::Wrapper qw( {{ $class }} !export );
314              
315             my $builder = Module::Build->new(
316             ...
317             configure_requires => {
318             '{{ $class }}' => '{{ $version }}',
319             ...
320             },
321             Alien::Base::Wrapper->mb_args,
322             ...
323             );
324              
325             $build->create_build_script;
326              
327             __[ __SYNOPSIS_FFI__ ]__
328             In your L<FFI::Platypus> script or module:
329              
330             use FFI::Platypus;
331             use {{ $class }}{{ $optversion }};
332              
333             my $ffi = FFI::Platypus->new(
334             lib => [ {{ $class }}->dynamic_libs ],
335             );
336              
337             __[ __SYNOPSIS_TOOL__ ]__
338             In your script or module:
339              
340             use {{ $class }}{{ $optversion }};
341             use Env qw( @PATH );
342              
343             unshift @PATH, {{ $class }}->bin_dir;
344              
345             __[ __DESCRIPTION__ ]__
346             =head1 DESCRIPTION
347              
348             This distribution provides {{ $name }} so that it can be used by other
349             Perl distributions that are on CPAN. It does this by first trying to
350             detect an existing install of {{ $name }} on your system. If found it
351             will use that. If it cannot be found, the source code will be downloaded
352             from the internet and it will be installed in a private share location
353             for the use of other modules.
354              
355             =cut