File Coverage

blib/lib/Dist/Zilla/Plugin/Test/Inline.pm
Criterion Covered Total %
statement 52 52 100.0
branch 3 6 50.0
condition n/a
subroutine 14 14 100.0
pod 1 1 100.0
total 70 73 95.8


line stmt bran cond sub pod time code
1 1     1   1655401 use strict;
  1         2  
  1         66  
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.011004';
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         9  
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             );
84              
85 1     1   5234 use File::Basename qw( basename );
  1         7  
  1         73  
86 1     1   4 use File::Spec;
  1         1  
  1         22  
87 1     1   4 use File::Temp qw( tempdir );
  1         2  
  1         70  
88 1     1   576 use File::Find::Rule;
  1         6452  
  1         9  
89 1     1   628 use Test::Inline;
  1         31036  
  1         32  
90 1     1   472 use Dist::Zilla::File::InMemory;
  1         67398  
  1         241  
91              
92             #pod =method gather_files
93             #pod
94             #pod Required by role L<Dist::Zilla::Role::FileGatherer>.
95             #pod
96             #pod Searches for inline test code in POD sections using L<Test::Inline>, creates
97             #pod in-memory test files and passes them to L<Dist::Zilla>.
98             #pod
99             #pod =cut
100             sub gather_files {
101 1     1 1 646344 my $self = shift;
102 1         2 my $arg = shift;
103              
104             # give Test::Inline our own extract and output handlers
105 1         10 my $inline = Test::Inline->new(
106             verbose => 0,
107             ExtractHandler => 'Dist::Zilla::Plugin::Test::Inline::Extract',
108             OutputHandler => Dist::Zilla::Plugin::Test::Inline::Output->new($self),
109             );
110              
111             # all files in the dist that match above filters (':InstallModules', ':ExecFiles')
112 1         111 for my $file (@{$self->found_files}) {
  1         7  
113 1 50       1507 next if $file->is_bytes;
114 1 50       52 $inline->add(\$file->content)
115             and $self->log("extracted inline tests from ".$file->name);
116             }
117              
118             # add test files to Dist::Zilla distribution
119 1         745 $inline->save;
120             }
121              
122             #
123             # Used to connect Test::Inline to Dist::Zilla
124             # (write generated test code into in-memory files)
125             #
126             {
127             package Dist::Zilla::Plugin::Test::Inline::Output;
128             $Dist::Zilla::Plugin::Test::Inline::Output::VERSION = '0.011004';
129             sub new {
130 1     1   2 my $class = shift;
131 1         1 my $dzil = shift;
132              
133 1         14 return bless { dzil => $dzil }, $class;
134             }
135              
136             sub write {
137 1     1   442 my $self = shift;
138 1         2 my $name = shift;
139 1         1 my $content = shift;
140              
141 1         42 $self->{dzil}->add_file(
142             Dist::Zilla::File::InMemory->new(
143             name => "t/inline-tests/$name",
144             content => $content,
145             )
146             );
147              
148 1         606 return 1;
149             }
150             }
151             #
152             # Taken from https://github.com/moose/Moose/blob/master/inc/MyInline.pm
153             #
154             {
155             package Dist::Zilla::Plugin::Test::Inline::Extract;
156             $Dist::Zilla::Plugin::Test::Inline::Extract::VERSION = '0.011004';
157 1     1   9 use parent 'Test::Inline::Extract';
  1         1  
  1         7  
158            
159             # Extract code specifically marked for testing
160             our $search = qr/
161             (?:^|\n) # After the beginning of the string, or a newline
162             ( # ... start capturing
163             # EITHER
164             package\s+ # A package
165             [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
166             \s*; # And a statement terminator
167             | # OR
168             class\s+ # A class
169             [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
170             ($|\s+|\s*{) # And some spaces or an opening bracket
171             | # OR
172             role\s+ # A role
173             [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
174             ($|\s+|\s*{) # And some spaces or an opening bracket
175             | # OR
176             =for[ \t]+example[ \t]+begin\n # ... when we find a =for example begin
177             .*? # ... and keep capturing
178             \n=for[ \t]+example[ \t]+end\s*? # ... until the =for example end
179             (?:\n|$) # ... at the end of file or a newline
180             | # OR
181             =begin[ \t]+(?:test|testing)\b # ... when we find a =begin test or testing
182             .*? # ... and keep capturing
183             \n=end[ \t]+(?:test|testing)\s*? # ... until an =end tag
184             (?:\n|$) # ... at the end of file or a newline
185             ) # ... and stop capturing
186             /isx;
187            
188             sub _elements {
189 1     1   899 my $self = shift;
190 1         3 my @elements = ();
191 1         28 while ( $self->{source} =~ m/$search/go ) {
192 2         5 my $element = $1;
193             # rename "role" or "class" to "package" so Test::Inline understands
194 2         4 $element =~ s/^(role|class)(\s+)/package$2/;
195 2         11 $element =~ s/\n\s*$//;
196 2         23 push @elements, $element;
197             }
198            
199 1 50   2   7 (List::Util::first { /^=/ } @elements) ? \@elements : '';
  2         8  
200             }
201            
202             }
203              
204              
205             1;
206              
207             __END__
208              
209             =pod
210              
211             =head1 NAME
212              
213             Dist::Zilla::Plugin::Test::Inline - Create test files from inline tests in POD sections
214              
215             =head1 VERSION
216              
217             version 0.011004
218              
219             =head1 SYNOPSIS
220              
221             In your C<dist.ini>:
222              
223             [Test::Inline]
224              
225             In your module:
226              
227             # My/AddressRange.pm
228              
229             =begin testing
230              
231             use Test::Exception;
232             dies_ok {
233             My::AddressRange->list_from_range('10.2.3.A', '10.2.3.5')
234             } "list_from_range() complains about invalid address";
235              
236             =end testing
237            
238             =cut
239            
240             sub list_from_range {
241             # ...
242             }
243              
244             This will result in a file C<t/inline-tests/my_addressrange.t> in your distribution.
245              
246             =head1 DESCRIPTION
247              
248             This plugin integrates L<Test::Inline> into C<Dist::Zilla>.
249              
250             It scans all non-binary files in the lib path of your distribution for inline
251             tests in POD sections that are embedded between the keywords
252              
253             =begin testing
254             ...
255             =end testing
256              
257             These tests are then exported into C<t/inline-tests/*.t> files when
258             C<Dist::Zilla> builds your module. Multiple of test sections may be specified
259             within one file.
260              
261             Please note that this plugin (in contrast to pure L<Test::Inline>) can also
262             handle L<Moops>-like class and role definitions.
263              
264             =head2 Files to be scanned for inline tests
265              
266             Only files already gathered by previous file gatherer plugins are scanned. In
267             other words: tests will not be extracted for files which have been excluded.
268              
269             Example:
270              
271             [GatherDir]
272             exclude_match = Hidden\.pm
273             [Test::Inline]
274              
275             This will lead to C<Dist::Zilla::Plugin::Test::Inline> ignoring C<Hidden.pm>.
276              
277             =head1 METHODS
278              
279             =head2 gather_files
280              
281             Required by role L<Dist::Zilla::Role::FileGatherer>.
282              
283             Searches for inline test code in POD sections using L<Test::Inline>, creates
284             in-memory test files and passes them to L<Dist::Zilla>.
285              
286             =head1 ACKNOWLEDGEMENTS
287              
288             The code of this Dist::Zilla file gatherer plugin is based on
289             L<https://github.com/moose/moose/blob/master/inc/ExtractInlineTests.pm>.
290              
291             =over 4
292              
293             =item *
294              
295             Dave Rolsky <autarch@urth.org>, who basically wrote most of this but left the honor of making a plugin out of it to me ;-)
296              
297             =back
298              
299             =head1 AUTHOR
300              
301             Jens Berthold <jens.berthold@jebecs.de>
302              
303             =head1 COPYRIGHT AND LICENSE
304              
305             This software is copyright (c) 2015 by Jens Berthold.
306              
307             This is free software; you can redistribute it and/or modify it under
308             the same terms as the Perl 5 programming language system itself.
309              
310             =cut