File Coverage

blib/lib/Dist/Zilla/Plugin/Test/Inline.pm
Criterion Covered Total %
statement 42 42 100.0
branch 3 6 50.0
condition n/a
subroutine 11 11 100.0
pod 2 2 100.0
total 58 61 95.0


line stmt bran cond sub pod time code
1 1     1   1648448 use strict;
  1         1  
  1         72  
2             package Dist::Zilla::Plugin::Test::Inline;
3             # ABSTRACT: Create test files from inline tests in POD sections
4             # VERSION
5             $Dist::Zilla::Plugin::Test::Inline::VERSION = '0.011005';
6             #pod =head1 SYNOPSIS
7             #pod
8             #pod In your C<dist.ini>:
9             #pod
10             #pod [Test::Inline]
11             #pod
12             #pod In your module:
13             #pod
14             #pod # My/AddressRange.pm
15             #pod
16             #pod =begin testing
17             #pod
18             #pod use Test::Exception;
19             #pod dies_ok {
20             #pod My::AddressRange->list_from_range('10.2.3.A', '10.2.3.5')
21             #pod } "list_from_range() complains about invalid address";
22             #pod
23             #pod =end testing
24             #pod
25             #pod =cut
26             #pod
27             #pod sub list_from_range {
28             #pod # ...
29             #pod }
30             #pod
31             #pod This will result in a file C<t/inline-tests/my_addressrange.t> in your distribution.
32             #pod
33             #pod =head1 DESCRIPTION
34             #pod
35             #pod This plugin integrates L<Test::Inline> into C<Dist::Zilla>.
36             #pod
37             #pod It scans all non-binary files in the lib path of your distribution for inline
38             #pod tests in POD sections that are embedded between the keywords
39             #pod
40             #pod =begin testing
41             #pod ...
42             #pod =end testing
43             #pod
44             #pod These tests are then exported into C<t/inline-tests/*.t> files when
45             #pod C<Dist::Zilla> builds your module. Multiple of test sections may be specified
46             #pod within one file.
47             #pod
48             #pod Please note that this plugin (in contrast to pure L<Test::Inline>) can also
49             #pod handle L<Moops>-like class and role definitions.
50             #pod
51             #pod =head2 Files to be scanned for inline tests
52             #pod
53             #pod Only files already gathered by previous file gatherer plugins are scanned. In
54             #pod other words: tests will not be extracted for files which have been excluded.
55             #pod
56             #pod Example:
57             #pod
58             #pod [GatherDir]
59             #pod exclude_match = Hidden\.pm
60             #pod [Test::Inline]
61             #pod
62             #pod This will lead to C<Dist::Zilla::Plugin::Test::Inline> ignoring C<Hidden.pm>.
63             #pod
64             #pod =head1 ACKNOWLEDGEMENTS
65             #pod
66             #pod The code of this Dist::Zilla file gatherer plugin is based on
67             #pod L<https://github.com/moose/moose/blob/master/inc/ExtractInlineTests.pm>.
68             #pod
69             #pod =for :list
70             #pod * Dave Rolsky <autarch@urth.org>, who basically wrote most of this but left the
71             #pod honor of making a plugin out of it to me ;-)
72             #pod
73             #pod =cut
74              
75 1     1   4 use Moose;
  1         2  
  1         8  
76             with
77             # FileGatherer: turn this module as a Dist::Zilla plugin
78             'Dist::Zilla::Role::FileGatherer',
79             # FileFinderUser: add $self->found_files function to this module
80             'Dist::Zilla::Role::FileFinderUser' => { # where to take input files from
81             default_finders => [ ':InstallModules', ':ExecFiles' ],
82             },
83             # PrereqSource: allows to register prerequisites
84             'Dist::Zilla::Role::PrereqSource',
85             ;
86              
87             #pod =method gather_files
88             #pod
89             #pod Required by role L<Dist::Zilla::Role::FileGatherer>.
90             #pod
91             #pod Searches for inline test code in POD sections using L<Test::Inline>, creates
92             #pod in-memory test files and passes them to L<Dist::Zilla>.
93             #pod
94             #pod =cut
95             sub gather_files {
96 1     1 1 646424 my $self = shift;
97 1         3 my $arg = shift;
98              
99 1     1   5983 use Test::Inline;
  1         31386  
  1         190  
100              
101             # give Test::Inline our own extract and output handlers
102 1         12 my $inline = Test::Inline->new(
103             verbose => 0,
104             ExtractHandler => 'Dist::Zilla::Plugin::Test::Inline::Extract',
105             OutputHandler => Dist::Zilla::Plugin::Test::Inline::Output->new($self),
106             );
107              
108             # all files in the dist that match above filters (':InstallModules', ':ExecFiles')
109 1         115 for my $file (@{$self->found_files}) {
  1         6  
110 1 50       1750 next if $file->is_bytes;
111 1 50       52 $inline->add(\$file->content)
112             and $self->log("extracted inline tests from ".$file->name);
113             }
114              
115             # add test files to Dist::Zilla distribution
116 1         864 $inline->save;
117             }
118              
119             #pod =method register_prereqs
120             #pod
121             #pod Required by role L<Dist::Zilla::Role::PrereqSource>.
122             #pod
123             #pod Adds L<Test::More> to the list of prerequisites (as L<Test::Inline> inserts
124             #pod C<use Test::More;>) for the distribution that uses this plugin.
125             #pod
126             #pod =cut
127             sub register_prereqs {
128 1     1 1 4124 my $self = shift;
129 1         31 $self->zilla->register_prereqs(
130             {
131             type => 'requires',
132             phase => 'test',
133             },
134             'Test::More' => 0,
135             );
136             }
137              
138             #
139             # Used to connect Test::Inline to Dist::Zilla
140             # (write generated test code into in-memory files)
141             #
142             {
143             package Dist::Zilla::Plugin::Test::Inline::Output;
144             $Dist::Zilla::Plugin::Test::Inline::Output::VERSION = '0.011005';
145             sub new {
146 1     1   2 my $class = shift;
147 1         3 my $dzil = shift;
148              
149 1         11 return bless { dzil => $dzil }, $class;
150             }
151              
152             sub write {
153 1     1   385 my $self = shift;
154 1         2 my $name = shift;
155 1         2 my $content = shift;
156              
157 1     1   496 use Dist::Zilla::File::InMemory;
  1         66414  
  1         183  
158              
159 1         43 $self->{dzil}->add_file(
160             Dist::Zilla::File::InMemory->new(
161             name => "t/inline-tests/$name",
162             content => $content,
163             )
164             );
165              
166 1         603 return 1;
167             }
168             }
169             #
170             # Taken from https://github.com/moose/Moose/blob/master/inc/MyInline.pm
171             #
172             {
173             package Dist::Zilla::Plugin::Test::Inline::Extract;
174             $Dist::Zilla::Plugin::Test::Inline::Extract::VERSION = '0.011005';
175 1     1   8 use parent 'Test::Inline::Extract';
  1         2  
  1         6  
176            
177             # Extract code specifically marked for testing
178             our $search = qr/
179             (?:^|\n) # After the beginning of the string, or a newline
180             ( # ... start capturing
181             # EITHER
182             package\s+ # A package
183             [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
184             \s*; # And a statement terminator
185             | # OR
186             class\s+ # A class
187             [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
188             ($|\s+|\s*{) # And some spaces or an opening bracket
189             | # OR
190             role\s+ # A role
191             [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
192             ($|\s+|\s*{) # And some spaces or an opening bracket
193             | # OR
194             =for[ \t]+example[ \t]+begin\n # ... when we find a =for example begin
195             .*? # ... and keep capturing
196             \n=for[ \t]+example[ \t]+end\s*? # ... until the =for example end
197             (?:\n|$) # ... at the end of file or a newline
198             | # OR
199             =begin[ \t]+(?:test|testing)\b # ... when we find a =begin test or testing
200             .*? # ... and keep capturing
201             \n=end[ \t]+(?:test|testing)\s*? # ... until an =end tag
202             (?:\n|$) # ... at the end of file or a newline
203             ) # ... and stop capturing
204             /isx;
205            
206             sub _elements {
207 1     1   980 my $self = shift;
208 1         3 my @elements = ();
209 1         31 while ( $self->{source} =~ m/$search/go ) {
210 2         4 my $element = $1;
211             # rename "role" or "class" to "package" so Test::Inline understands
212 2         6 $element =~ s/^(role|class)(\s+)/package$2/;
213 2         9 $element =~ s/\n\s*$//;
214 2         22 push @elements, $element;
215             }
216            
217 1 50   2   8 (List::Util::first { /^=/ } @elements) ? \@elements : '';
  2         10  
218             }
219            
220             }
221              
222              
223             1;
224              
225             __END__
226              
227             =pod
228              
229             =head1 NAME
230              
231             Dist::Zilla::Plugin::Test::Inline - Create test files from inline tests in POD sections
232              
233             =head1 VERSION
234              
235             version 0.011005
236              
237             =head1 SYNOPSIS
238              
239             In your C<dist.ini>:
240              
241             [Test::Inline]
242              
243             In your module:
244              
245             # My/AddressRange.pm
246              
247             =begin testing
248              
249             use Test::Exception;
250             dies_ok {
251             My::AddressRange->list_from_range('10.2.3.A', '10.2.3.5')
252             } "list_from_range() complains about invalid address";
253              
254             =end testing
255            
256             =cut
257            
258             sub list_from_range {
259             # ...
260             }
261              
262             This will result in a file C<t/inline-tests/my_addressrange.t> in your distribution.
263              
264             =head1 DESCRIPTION
265              
266             This plugin integrates L<Test::Inline> into C<Dist::Zilla>.
267              
268             It scans all non-binary files in the lib path of your distribution for inline
269             tests in POD sections that are embedded between the keywords
270              
271             =begin testing
272             ...
273             =end testing
274              
275             These tests are then exported into C<t/inline-tests/*.t> files when
276             C<Dist::Zilla> builds your module. Multiple of test sections may be specified
277             within one file.
278              
279             Please note that this plugin (in contrast to pure L<Test::Inline>) can also
280             handle L<Moops>-like class and role definitions.
281              
282             =head2 Files to be scanned for inline tests
283              
284             Only files already gathered by previous file gatherer plugins are scanned. In
285             other words: tests will not be extracted for files which have been excluded.
286              
287             Example:
288              
289             [GatherDir]
290             exclude_match = Hidden\.pm
291             [Test::Inline]
292              
293             This will lead to C<Dist::Zilla::Plugin::Test::Inline> ignoring C<Hidden.pm>.
294              
295             =head1 METHODS
296              
297             =head2 gather_files
298              
299             Required by role L<Dist::Zilla::Role::FileGatherer>.
300              
301             Searches for inline test code in POD sections using L<Test::Inline>, creates
302             in-memory test files and passes them to L<Dist::Zilla>.
303              
304             =head2 register_prereqs
305              
306             Required by role L<Dist::Zilla::Role::PrereqSource>.
307              
308             Adds L<Test::More> to the list of prerequisites (as L<Test::Inline> inserts
309             C<use Test::More;>) for the distribution that uses this plugin.
310              
311             =head1 ACKNOWLEDGEMENTS
312              
313             The code of this Dist::Zilla file gatherer plugin is based on
314             L<https://github.com/moose/moose/blob/master/inc/ExtractInlineTests.pm>.
315              
316             =over 4
317              
318             =item *
319              
320             Dave Rolsky <autarch@urth.org>, who basically wrote most of this but left the honor of making a plugin out of it to me ;-)
321              
322             =back
323              
324             =head1 AUTHOR
325              
326             Jens Berthold <jens.berthold@jebecs.de>
327              
328             =head1 COPYRIGHT AND LICENSE
329              
330             This software is copyright (c) 2015 by Jens Berthold.
331              
332             This is free software; you can redistribute it and/or modify it under
333             the same terms as the Perl 5 programming language system itself.
334              
335             =cut