File Coverage

blib/lib/Dist/Zilla/Plugin/OurPkgVersion.pm
Criterion Covered Total %
statement 84 87 96.5
branch 37 44 84.0
condition 8 12 66.6
subroutine 13 13 100.0
pod 3 3 100.0
total 145 159 91.1


line stmt bran cond sub pod time code
1             package Dist::Zilla::Plugin::OurPkgVersion;
2 9     9   37862056 use 5.014;
  9         38  
3 9     9   59 use strict;
  9         24  
  9         248  
4 9     9   53 use warnings;
  9         21  
  9         482  
5              
6             our $VERSION = '0.21'; # VERSION
7              
8 9     9   65 use Moose;
  9         21  
  9         73  
9             with (
10             'Dist::Zilla::Role::FileMunger',
11             'Dist::Zilla::Role::FileFinderUser' => {
12             default_finders => [
13             ':InstallModules',
14             ':PerlExecFiles',
15             ],
16             },
17             'Dist::Zilla::Role::PPI',
18             );
19              
20 9     9   64388 use Carp qw( confess );
  9         34  
  9         901  
21 9     9   5751 use PPI;
  9         931657  
  9         495  
22 9     9   94 use MooseX::Types::Perl qw( LaxVersionStr );
  9         24  
  9         153  
23 9     9   24250 use namespace::autoclean;
  9         23  
  9         98  
24              
25             has underscore_eval_version => (
26             is => 'ro',
27             isa => 'Bool',
28             default => 0,
29             );
30              
31             has semantic_version => (
32             is => 'ro',
33             isa => 'Bool',
34             default => 0,
35             );
36              
37             has skip_main_module => (
38             is => 'ro',
39             isa => 'Bool',
40             default => 0,
41             );
42              
43             has overwrite => (
44             is => 'ro',
45             isa => 'Bool',
46             default => 0,
47             );
48              
49             has no_critic => (
50             is => 'ro',
51             isa => 'Bool',
52             default => 0,
53             );
54              
55             sub munge_files {
56 8     8 1 1024456 my $self = shift;
57              
58 8         32 $self->munge_file($_) for
59 25 100       40808 grep { $self->skip_main_module ? $_->name ne $self->zilla->main_module->name : 1 }
60 8         69 @{ $self->found_files };
61              
62 8         2161 return;
63             }
64              
65             sub BUILD {
66 9     9 1 27 my $self = shift;
67              
68 9 100 100     376 if ($self->underscore_eval_version && $self->semantic_version) {
69 1         23 confess 'You cannot setup both underscore_eval_version and semantic_version';
70             }
71              
72 8         311 return 1;
73             }
74              
75             sub munge_file { ## no critic (Subroutines::ProhibitExcessComplexity)
76 24     24 1 3151 my ( $self, $file ) = @_;
77              
78 24 50       107 if ( $file->name =~ m/\.pod$/ixms ) {
79 0         0 $self->log_debug( 'Skipping: "' . $file->name . '" is pod only');
80 0         0 return;
81             }
82              
83 24         2022 my $version = $self->zilla->version;
84              
85 24 50       976 confess 'invalid characters in version'
86             unless LaxVersionStr->check( $version ); ## no critic (Modules::RequireExplicitInclusion)
87              
88 24         20561 my $doc = $self->ppi_document_for_file($file);
89              
90 24 50       126976 return unless defined $doc;
91              
92 24 100       1135 $doc->index_locations if $self->overwrite; # optimize calls to check line numbers
93 24         2804 my $comments = $doc->find('PPI::Token::Comment');
94              
95 24         21426 my $version_regex
96             = q{
97             ^
98             (\s*) # capture leading whitespace for whole-line comments
99             (
100             \#\#?\s*VERSION # capture # VERSION or ## VERSION
101             \b # and ensure it ends on a word boundary
102             [ # conditionally
103             [:print:] # all printable characters after VERSION
104             \s # any whitespace including newlines - GH #5
105             ]* # as many of the above as there are
106             )
107             $ # until the EOL}
108             ;
109              
110 24         61 my $munged_version = 0;
111 24 100       106 if ( ref($comments) eq 'ARRAY' ) {
112 22         51 foreach ( @{ $comments } ) {
  22         69  
113 38 100       4002 if ( /$version_regex/xms ) {
114 24         420 my ( $ws, $comment ) = ( $1, $2 );
115 24 100       841 $comment =~ s/(?=\bVERSION\b)/TRIAL /x if $self->zilla->is_trial;
116 24         8415 my $code
117             = "$ws"
118             . q{our $VERSION = '}
119             . $version
120             . qq{'; $comment}
121             ;
122              
123 24 100       875 if ( $self->semantic_version ) {
124 1 50       10 confess 'Invalid semantic version syntax declaration in INI file' unless ( $version =~ /^v\d+\.\d+\.\d+$/x );
125 1         4 $code = "use version;\n" . $code;
126             }
127              
128             # If the comment is not a whole-line comment, and if the user wants to overwrite
129             # existing "our $VERSION=...;", then find the other tokens from this line, looking
130             # for our $VERSION = $VALUE. If found, edit only the VALUE.
131 24 100 66     826 if ( $self->overwrite && !$_->line ) {
132 3         32 my $line_no = $_->line_number;
133 3     288   75 my $nodes = $doc->find( sub { $_[1]->line_number == $line_no } );
  288         6399  
134 3   33     96 my $version_value_token = $nodes && $self->_identify_version_value_token(@$nodes);
135 3 50       9 if ( $version_value_token ) {
136 3         24 $version_value_token->set_content(qq{'$version'});
137 3         15 $code = $ws . $comment;
138 3         10 $munged_version++;
139             }
140             }
141              
142 24 100 66     152 if ( $version =~ /_/ && $self->underscore_eval_version ) {
143 1         4 my $eval = "\$VERSION = eval \$VERSION;";
144 1 50       36 $eval .= " ## no critic (BuiltinFunctions::ProhibitStringyEval)"
145             if $self->no_critic;
146 1 50       7 $code .= $_->line? "$eval\n" : "\n$eval";
147             }
148              
149 24         185 $_->set_content($code);
150 24         134 $munged_version++;
151             }
152             }
153             }
154              
155 24 100       260 if ( $munged_version ) {
156 20         122 $self->save_ppi_document_to_file( $doc, $file);
157 20         28026 $self->log_debug([ 'adding $VERSION assignment to %s', $file->name ]);
158             }
159             else {
160 4         79 $self->log( 'Skipping: "'
161             . $file->name
162             . '" has no "# VERSION" comment'
163             );
164             }
165 24         4635 return;
166             }
167              
168             sub _identify_version_value_token {
169 3     3   13 my ( $self, @tokens ) = @_;
170 3         7 my $val_tok;
171 3         9 my @want = ('our', '$VERSION', '=', undef, ';');
172 3         7 my $i = 0;
173 3         30 for ( @tokens ) {
174 39 100       311 next if $_->isa('PPI::Token::Whitespace');
175             # If the next thing we want is "undef", this is where we capture the value token.
176 27 100       71 if (!defined $want[$i]) {
    100          
    100          
177 3         6 $val_tok = $_;
178 3         5 ++$i;
179             }
180             # Else if the token matches the current step in the sequence, advance the sequence
181             # If sequence completely matched, return.
182             elsif ($want[$i] eq $_->content) {
183 13         46 ++$i;
184 13 100       60 return $val_tok if $i >= $#want;
185             }
186             # A mismatch restarts the search
187             elsif ($i) {
188 1         6 $i = 0;
189             }
190             }
191 0           return; # no match
192             }
193              
194             __PACKAGE__->meta->make_immutable;
195             1;
196             # ABSTRACT: No line insertion and does Package version with our
197              
198             __END__
199              
200             =pod
201              
202             =head1 NAME
203              
204             Dist::Zilla::Plugin::OurPkgVersion - No line insertion and does Package version with our
205              
206             =head1 VERSION
207              
208             version 0.21
209              
210             =head1 SYNOPSIS
211              
212             in dist.ini
213              
214             [OurPkgVersion]
215              
216             in your modules
217              
218             # VERSION
219              
220             =head1 DESCRIPTION
221              
222             This module was created as an alternative to
223             L<Dist::Zilla::Plugin::PkgVersion> and uses some code from that module. This
224             module is designed to use a the more readable format C<our $VERSION =
225             $version;> as well as not change then number of lines of code in your files,
226             which will keep your repository more in sync with your CPAN release. It also
227             allows you slightly more freedom in how you specify your version.
228              
229             =head2 EXAMPLES
230              
231             in dist.ini
232              
233             ...
234             version = 0.01;
235             [OurPkgVersion]
236              
237             in lib/My/Module.pm
238              
239             package My::Module;
240             # VERSION
241             ...
242              
243             output lib/My/Module.pm
244              
245             package My::Module;
246             our $VERSION = '0.01'; # VERSION
247             ...
248              
249             please note that whitespace before the comment is significant so
250              
251             package My::Module;
252             BEGIN {
253             # VERSION
254             }
255             ...
256              
257             becomes
258              
259             package My::Module;
260             BEGIN {
261             our $VERSION = '0.01'; # VERSION
262             }
263             ...
264              
265             while
266              
267             package My::Module;
268             BEGIN {
269             # VERSION
270             }
271             ...
272              
273             becomes
274              
275             package My::Module;
276             BEGIN {
277             our $VERSION = '0.01'; # VERSION
278             }
279             ...
280              
281             you can also add additional comments to your comment
282              
283             ...
284             # VERSION: generated by DZP::OurPkgVersion
285             ...
286              
287             becomes
288              
289             ...
290             our $VERSION = '0.1.0'; # VERSION: generated by DZP::OurPkgVersion
291             ...
292              
293             you can also use perltidy's default static side comments (##)
294              
295             ...
296             ## VERSION
297             ...
298              
299             becomes
300              
301             ...
302             our $VERSION = '0.1.0'; ## VERSION
303             ...
304              
305             Also note, the package line is not in any way significant, it will insert the
306             C<our $VERSION> line anywhere in the file before C<# VERSION> as many times as
307             you've written C<# VERSION> regardless of whether or not inserting it there is
308             a good idea. OurPkgVersion will not insert a version unless you have C<#
309             VERSION> so it is a bit more work.
310              
311             If you make a trial release, the comment will be altered to say so:
312              
313             # VERSION
314              
315             becomes
316              
317             our $VERSION = '0.01'; # TRIAL VERSION
318              
319             =encoding UTF-8
320              
321             =head1 METHODS
322              
323             =over
324              
325             =item BUILD
326              
327             Provides validations after object creation.
328              
329             =item munge_files
330              
331             Override the default provided by L<Dist::Zilla::Role::FileMunger> to limit
332             the number of files to search to only be modules and executables.
333              
334             =item munge_file
335              
336             tells which files to munge, see L<Dist::Zilla::Role::FileMunger>.
337              
338             =item finder
339              
340             Override the default L<FileFinder|Dist::Zilla::Role::FileFinder> for
341             finding files to check and update. The default value is C<:InstallModules>
342             and C<:PerlExecFiles> (when available; otherwise C<:ExecFiles>)
343             -- see also L<Dist::Zilla::Plugin::ExecDir>, to make sure the script
344             files are properly marked as executables for the installer.
345              
346             =back
347              
348             =head1 PROPERTIES
349              
350             =over
351              
352             =item underscore_eval_version
353              
354             For version numbers that have an underscore in them, add this line
355             immediately after the our version assignment:
356              
357             $VERSION = eval $VERSION;
358              
359             This is arguably the correct thing to do, but changes the line numbering
360             of the generated Perl module or source, and thus optional.
361              
362             =item semantic_version
363              
364             Setting this property to "true" (1) will set the version of the
365             module/distribution to properly use semantic versioning. It will also expect
366             that you setup C<version> with a v-string, without adding quotes. For example:
367              
368             version = v0.0.1
369              
370             Beware you can't setup both C<underscore_eval_version> and C<semantic_version>
371             since both are mutually exclusive: if you try, your code is going to C<die>.
372              
373             For more details, check
374             L<this blog|https://weblog.bulknews.net/how-to-correctly-use-semantic-version-vx-y-z-in-perl-modules-eb08568ab911>
375             for more details about using semantic version with Perl.
376              
377             =item skip_main_module
378              
379             Set to true to ignore the main module in the distribution. This prevents
380             a warning when using L<Dist::Zilla::Plugin::VersionFromMainModule> to
381             obtain the version number instead of the C<dist.ini> file.
382              
383             =item overwrite
384              
385             When enabled, this option causes any match of the C<< # VERSION >> comment
386             to first check for an existing C<< our $VERSION = ...; >> on the same line,
387             and if found, overwrite the value in the existing statement. (the comment
388             still gets modified for trial releases)
389              
390             Currently, the value must be a single Perl token such as a string or number.
391              
392             =item no_critic
393              
394             When C<underscore_eval_version> is used the generated code for dev versions
395             may not technically be L<Perl::Critic> compliant due to string eval, but is
396             nevertheless pretty safe. This option will add the appropriate C<no critic>
397             directive to save you the hassle.
398              
399             =back
400              
401             =head1 BUGS
402              
403             Please report any bugs or feature requests on the bugtracker website
404             L<https://github.com/plicease/dist-zilla-plugin-ourpkgversion/issues>
405              
406             When submitting a bug or request, please include a test-file or a
407             patch to an existing test-file that illustrates the bug or desired
408             feature.
409              
410             =head1 CONTRIBUTORS
411              
412             =for stopwords Alceu Rodrigues de Freitas Junior Ian Sealy Michael Conrad Jemmeson Stephan Loyd Alexandr Ciornii Alexei Znamensky Christian Walde Christopher J. Madsen David Golden Graham Ollis Graham✈️✈️
413              
414             =over 4
415              
416             =item *
417              
418             Alceu Rodrigues de Freitas Junior <alceu.junior@quintoandar.com.br>
419              
420             =item *
421              
422             Ian Sealy <git@iansealy.com>
423              
424             =item *
425              
426             Michael Conrad <mike@nrdvana.net>
427              
428             =item *
429              
430             Michael Jemmeson <mjemmeson@cpan.org>
431              
432             =item *
433              
434             Stephan Loyd <stephanloyd9@gmail.com>
435              
436             =item *
437              
438             Alceu Rodrigues de Freitas Junior <arfreitas@cpan.org>
439              
440             =item *
441              
442             Alexandr Ciornii <alexchorny@gmail.com>
443              
444             =item *
445              
446             Alexei Znamensky <russoz@cpan.org>
447              
448             =item *
449              
450             Christian Walde <walde.christian@googlemail.com>
451              
452             =item *
453              
454             Christopher J. Madsen <perl@cjmweb.net>
455              
456             =item *
457              
458             David Golden <dagolden@cpan.org>
459              
460             =item *
461              
462             Graham Ollis <perl@wdlabs.com>
463              
464             =item *
465              
466             Graham Ollis <plicease@cpan.org>
467              
468             =item *
469              
470             Graham✈️✈️ <plicease@cpan.org>
471              
472             =back
473              
474             =head1 AUTHORS
475              
476             =over 4
477              
478             =item *
479              
480             Caleb Cushing <xenoterracide@gmail.com>
481              
482             =item *
483              
484             Grahan Ollis <plicease@cpan.org>
485              
486             =back
487              
488             =head1 COPYRIGHT AND LICENSE
489              
490             This software is Copyright (c) 2019 by Caleb Cushing.
491              
492             This is free software, licensed under:
493              
494             The Artistic License 2.0 (GPL Compatible)
495              
496             =cut