File Coverage

blib/lib/Dist/Zilla/Plugin/InsertExample.pm
Criterion Covered Total %
statement 78 79 98.7
branch 28 34 82.3
condition 2 3 66.6
subroutine 16 16 100.0
pod 0 3 0.0
total 124 135 91.8


line stmt bran cond sub pod time code
1 1     1   3216083 use strict;
  1         3  
  1         35  
2 1     1   6 use warnings;
  1         2  
  1         35  
3 1     1   24 use 5.020;
  1         3  
4              
5             package Dist::Zilla::Plugin::InsertExample 0.15 {
6              
7 1     1   5 use Moose;
  1         3  
  1         8  
8              
9 1     1   6572 use Moose::Util::TypeConstraints;
  1         4  
  1         11  
10 1     1   1915 use MooseX::Types::Moose qw(ArrayRef Str RegexpRef);
  1         2  
  1         12  
11              
12 1     1   4896 use Encode qw( encode );
  1         2  
  1         86  
13 1     1   7 use List::Util qw( first any );
  1         3  
  1         64  
14 1     1   7 use experimental qw( signatures postderef );
  1         3  
  1         10  
15              
16             # ABSTRACT: Insert example into your POD from a file
17              
18              
19             with 'Dist::Zilla::Role::FileMunger';
20             with 'Dist::Zilla::Role::FileFinderUser' => {
21             default_finders => [ qw( :InstallModules :ExecFiles ) ],
22             };
23              
24             has remove_boiler => (is => 'ro', isa => 'Int');
25             {
26             my $type = subtype as ArrayRef[RegexpRef];
27             coerce $type, from ArrayRef[Str], via { [map { qr/$_/ } @$_ ]};
28             has matches_boiler_barrier => ( is => 'ro', isa => $type, coerce => 1, default => sub { [] } );
29             }
30              
31             has indent => (is => 'ro', isa => 'Int', default => 1);
32              
33              
34 8     8 0 1168 sub mvp_aliases { +{ qw( match_boiler_barrier matches_boiler_barrier ) } }
35             sub mvp_multivalue_args { qw( matches_boiler_barrier ) }
36              
37             sub munge_files ($self)
38 8     8 0 149325 {
  8         23  
  8         16  
39 8         50 $self->munge_file($_) for $self->found_files->@*;
40             }
41              
42 8         17 sub munge_file ($self, $file)
43 8     8 0 12013 {
  8         15  
  8         14  
44 8         35 my $content = $file->content;
45 8 50       6162 if($content =~ s{^#\s*EXAMPLE:\s*(.*)\s*$}{$self->_slurp_example($1)."\n"}meg)
  8         40  
46             {
47 8         37 $self->log([ 'adding examples in %s', $file->name]);
48 8         3144 $file->content($content);
49             }
50             }
51              
52 8         16 sub _slurp_example ($self, $filename)
53 8     8   16 {
  8         20  
  8         14  
54 8         14 my $fh;
55              
56 8 100   24   225 if(my $file = first { $_->name eq $filename } $self->zilla->files->@*)
  24 50       851  
57             {
58 6         238 my $content = encode 'UTF-8', $file->content;
59 1 50   1   8 open $fh, '<', \$content
  1         1  
  1         8  
  6         2786  
60 0         0 or $self->log_fatal("unable to open content of @{[ $file->name ]} as in memory string");
61 6         934 binmode $fh, ':utf8';
62             }
63             elsif($file = $self->zilla->root->child($filename))
64             {
65 2 50       253 $self->log_fatal("no such example file $filename") unless -r $file;
66 2         64 $fh = $file->openr_utf8;
67             }
68              
69 8         1482 my $indent = ' ' x $self->indent;
70              
71 8         21 my $in_boiler = 1;
72 8         16 my $found_content = 0;
73 8         96 while(my $line = <$fh>)
74             {
75 20 100       665 if($self->remove_boiler)
76             {
77 14 100       390 if( $self->matches_boiler_barrier->@* )
78             {
79 9 100       18 if($in_boiler)
80             {
81 7 100   7   221 $in_boiler = 0 if any { $line =~ $_ } $self->matches_boiler_barrier->@*;
  7         26  
82 7         29 next;
83             }
84             }
85             else
86             {
87 5 100       19 next if $line =~ /^\s*$/;
88 4 100       13 next if $line =~ /^#!\/usr\/bin\/perl/;
89 3 50       7 next if $line =~ /^#!\/usr\/bin\/env perl/;
90 3 100       11 next if $line =~ /^use strict;$/;
91 2 100       30 next if $line =~ /^use warnings;$/;
92             }
93 3 50       10 return '' if eof $fh;
94             }
95             # get rid of any blank lines before the content.
96 9 100 66     57 next if $line =~ /^\s*$/ && ! $found_content;
97 8         15 ++$found_content;
98              
99 8 100       18 return join "\n", map { "$indent$_" } split /\n/, $line . do { local $/; my $rest = <$fh>; defined $rest ? $rest : '' };
  43         196  
  8         29  
  8         60  
  8         99  
100             }
101              
102             }
103              
104             __PACKAGE__->meta->make_immutable;
105             }
106              
107             1;
108              
109             __END__
110              
111             =pod
112              
113             =encoding UTF-8
114              
115             =head1 NAME
116              
117             Dist::Zilla::Plugin::InsertExample - Insert example into your POD from a file
118              
119             =head1 VERSION
120              
121             version 0.15
122              
123             =head1 SYNOPSIS
124              
125             In your dist.ini:
126              
127             [InsertExample]
128              
129             In your POD:
130              
131             =head1 EXAMPLE
132            
133             Here is an exaple that writes hello world to the terminal:
134            
135             # EXAMPLE: example/hello.pl
136              
137             File in your dist named example/hello.pl
138              
139             #!/usr/bin/perl
140             say 'hello world';
141              
142             After dzil build your POD becomes:
143              
144             =head1 EXAMPLE
145            
146             Here is an example that writes hello world to the terminal:
147            
148             #!/usr/bin/perl
149             say 'hello world';
150              
151             and example/hello.pl is there too (unless you prune it with another
152             plugin).
153              
154             =head1 DESCRIPTION
155              
156             This plugin takes examples included in your distribution and
157             inserts them in your POD where you have an EXAMPLE directive.
158             This allows you to keep a version in the distribution which
159             can be run by you and your users, as well as making it
160             available in your POD documentation, without the need for
161             updating example scripts in multiple places.
162              
163             When the example is inserted into your pod a space will be appended
164             at the start of each line so that it is printed in a fixed width
165             font.
166              
167             This plugin will first look for examples in the currently
168             building distribution, including generated and munged files.
169             If no matching filename is found, it will look in the distribution
170             source root.
171              
172             =head1 OPTIONS
173              
174             =head2 remove_boiler
175              
176             Remove the C<#!/usr/bin/perl>, C<use strict;> or C<use warnings;> from
177             the beginning of your example before inserting them into the POD.
178              
179             If L</match_boiler_barrier> is also set, it instead removes all lines up-to
180             and including the line matched by L</match_boiler_barrier>.
181              
182             =head2 match_boiler_barrier
183              
184             A regular expression matching a line indicating the end of
185             boilerplate. This option may be used multiple times.
186             It must be used in conjunction with L</remove_boiler>.
187              
188             =head2 indent
189              
190             Specifies the number of spaces to indent by. This is 1 by default,
191             because it is sufficient to force POD to consider it a verbatim
192             paragraph. I understand a lot of Perl programmers out there prefer
193             4 spaces. You can also set this to 0 to get no indentation at all
194             and it won't be a verbatim paragraph at all.
195              
196             =head1 AUTHOR
197              
198             Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
199              
200             Contributors:
201              
202             Diab Jerius (DJERIUS)
203              
204             =head1 COPYRIGHT AND LICENSE
205              
206             This software is copyright (c) 2013 by Graham Ollis.
207              
208             This is free software; you can redistribute it and/or modify it under
209             the same terms as the Perl 5 programming language system itself.
210              
211             =cut