File Coverage

blib/lib/Version/Dotted/Semantic.pm
Criterion Covered Total %
statement 34 34 100.0
branch 2 2 100.0
condition 2 3 66.6
subroutine 11 11 100.0
pod 2 2 100.0
total 51 52 98.0


line stmt bran cond sub pod time code
1             # ---------------------------------------------------------------------- copyright and license ---
2             #
3             # file: lib/Version/Dotted/Semantic.pm
4             #
5             # Copyright © 2016 Van de Bugger.
6             #
7             # This file is part of perl-Version-Dotted.
8             #
9             # perl-Version-Dotted is free software: you can redistribute it and/or modify it under the terms
10             # of the GNU General Public License as published by the Free Software Foundation, either version
11             # 3 of the License, or (at your option) any later version.
12             #
13             # perl-Version-Dotted is distributed in the hope that it will be useful, but WITHOUT ANY
14             # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15             # PURPOSE. See the GNU General Public License for more details.
16             #
17             # You should have received a copy of the GNU General Public License along with
18             # perl-Version-Dotted. If not, see .
19             #
20             # Chapter "Dotted Semantic Versioning" is licensed under CC BY 3.0
21             # .
22             #
23             # ---------------------------------------------------------------------- copyright and license ---
24              
25             #pod =for :this This is C module/class documentation. However, read
26             #pod C module/class documentation first, since it contains many relevant details.
27             #pod
28             #pod =for :those General topics like getting source, building, installing, bug reporting and some
29             #pod others are covered in the F.
30             #pod
31             #pod =for test_synopsis my ( $v, $int, $bool );
32             #pod
33             #pod =for comment ---------------------------------------------------------------------------------------
34             #pod
35             #pod =head1 SYNOPSIS
36             #pod
37             #pod use Version::Dotted::Semantic; # import nothing
38             #pod use Version::Dotted::Semantic 'qv'; # import qv
39             #pod
40             #pod # Construct:
41             #pod $v = Version::Dotted::Semantic->new( v1 ); # v1.0.0 (at least 3 parts)
42             #pod $v = qv( v1 ); # ditto
43             #pod $v = qv( 'v1.2.3.4' ); # v1.2.3.4
44             #pod
45             #pod # Get parts by name (indexing also works):
46             #pod $int = $v->part( 'major' ); # Always defined.
47             #pod $int = $v->part( 'minor' ); # ditto
48             #pod $int = $v->part( 'patch' ); # ditto
49             #pod $int = $v->part( 'trial' ); # May be undefined.
50             #pod $int = $v->major; # Always defined.
51             #pod $int = $v->minor; # ditto
52             #pod $int = $v->patch; # ditto
53             #pod $int = $v->trial; # May be undefined.
54             #pod
55             #pod # Bump the version (indexing also works):
56             #pod $v->bump( 'trial' ); # Bump trial part.
57             #pod $v->bump( 'patch' ); # Bump patch and drop trial.
58             #pod $v->bump( 'minor' ); # Bump minor, reset patch and drop trial.
59             #pod $v->bump( 'major' ); # Bump major, reset minor and patch, drop trial.
60             #pod
61             #pod # Release status:
62             #pod $bool = $v->is_trial; # true if version has more than 3 parts.
63             #pod
64             #pod # See Version::Dotted for other methods.
65             #pod
66             #pod =for comment ---------------------------------------------------------------------------------------
67             #pod
68             #pod =head1 DESCRIPTION
69             #pod
70             #pod This is subclass of C. Three features distinct it from the parent:
71             #pod
72             #pod =over
73             #pod
74             #pod =item *
75             #pod
76             #pod Version object always has at least 3 parts.
77             #pod
78             #pod $v = qv( v1 ); # == v1.0.0
79             #pod $v->part( 0 ) == 1; # Parts 0, 1, 2 are always defined.
80             #pod $v->part( 1 ) == 0; # Zero if not specified explicitly.
81             #pod $v->part( 2 ) == 0; # ditto
82             #pod $v->part( 3 ) == undef; # But may be defined.
83             #pod
84             #pod =item *
85             #pod
86             #pod First four parts have individual names.
87             #pod
88             #pod $v->major = $v->part( 'major' ); # == $v->part( 0 );
89             #pod $v->minor = $v->part( 'minor' ); # == $v->part( 1 );
90             #pod $v->patch = $v->part( 'patch' ); # == $v->part( 2 );
91             #pod $v->trial = $v->part( 'trial' ); # == $v->part( 3 );
92             #pod
93             #pod $v->bump( 'trial' ); # the same as $v->bump( 3 );
94             #pod
95             #pod =item *
96             #pod
97             #pod The number of parts defines release status: more than 3 parts denotes trial release.
98             #pod
99             #pod $v = qv( v1 ); # $v == v1.0.0
100             #pod $v->is_trial; # false
101             #pod $v->bump( 'trial' ); # $v == v1.0.0.1
102             #pod $v->is_trial; # true
103             #pod
104             #pod =back
105             #pod
106             #pod =for comment ---------------------------------------------------------------------------------------
107             #pod
108             #pod =head1 SEMANTIC VERSIONING
109             #pod
110             #pod See L. It sound very reasonable to
111             #pod me.
112             #pod
113             #pod Unfortunately, Semantic Versioning cannot be applied to Perl modules (maintaining compatibility
114             #pod with C objects) due to wider character set (letters, hyphens, plus signs, e. g.
115             #pod 1.0.0-alpha.3+8daebec8a8e1) and specific precedence rules (1.0.0-alpha < 1.0.0).
116             #pod
117             #pod =for comment ---------------------------------------------------------------------------------------
118             #pod
119             #pod =head1 DOTTED SEMANTIC VERSIONING
120             #pod
121             #pod Dotted Semantic Versioning is adaptation of Semantic Versioning for Perl realities.
122             #pod
123             #pod =head2 Summary
124             #pod
125             #pod Given a version number vI.I.I, increment the:
126             #pod
127             #pod =for :list
128             #pod * I version when you make incompatible API changes,
129             #pod * I version when you add functionality in a backwards-compatible manner, and
130             #pod * I version when you make backwards-compatible bug fixes.
131             #pod
132             #pod Additional labels for I versions are available as extension to the
133             #pod vI.I.I format.
134             #pod
135             #pod =head2 Introduction
136             #pod
137             #pod See L.
138             #pod
139             #pod =head2 Dotted Semantic Versioning Specification
140             #pod
141             #pod The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”,
142             #pod “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in L
143             #pod 2119|http://tools.ietf.org/html/rfc2119>.
144             #pod
145             #pod =over
146             #pod
147             #pod =item 1
148             #pod
149             #pod Software using Dotted Semantic Versioning MUST declare a public API. This API could be declared in
150             #pod the code itself or exist strictly in documentation. However it is done, it should be precise and
151             #pod comprehensive.
152             #pod
153             #pod =item 2
154             #pod
155             #pod A I version number MUST take the form vI.I.I where I, I, and I are
156             #pod non-negative integers, and MUST NOT contain leading zeroes. I is the I version, I is
157             #pod the I version, and I is the I version. Each element MUST increase numerically. For
158             #pod instance: v1.9.0 -> v1.10.0 -> v1.11.0.
159             #pod
160             #pod =item 3
161             #pod
162             #pod Once a versioned package has been released, the contents of that version MUST NOT be modified. Any
163             #pod modifications MUST be released as a new version.
164             #pod
165             #pod =item 4
166             #pod
167             #pod Major version zero (v0.I.I) is for initial development. Anything may change at any time. The
168             #pod public API should not be considered stable.
169             #pod
170             #pod =item 5
171             #pod
172             #pod Version v1.0.0 defines the public API. The way in which the version number is incremented after
173             #pod this release is dependent on this public API and how it changes.
174             #pod
175             #pod =item 6
176             #pod
177             #pod I version I (vI.I.I | I > 0) MUST be incremented if only backwards compatible
178             #pod bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior.
179             #pod
180             #pod =item 7
181             #pod
182             #pod I version I (vI.I.I | I > 0) MUST be incremented if new, backwards compatible
183             #pod functionality is introduced to the public API. It MUST be incremented if any public API
184             #pod functionality is marked as deprecated. It MAY be incremented if substantial new functionality or
185             #pod improvements are introduced within the private code. It MAY include patch level changes. Patch
186             #pod version MUST be reset to 0 when minor version is incremented.
187             #pod
188             #pod =item 8
189             #pod
190             #pod I version I (vI.I.I | I > 0) MUST be incremented if any backwards
191             #pod incompatible changes are introduced to the public API. It MAY include minor and patch level
192             #pod changes. Patch and minor version MUST be reset to 0 when major version is incremented.
193             #pod
194             #pod =item 9
195             #pod
196             #pod A I version MAY be denoted by appending a dot and a series of dot separated numbers
197             #pod immediately following the patch version. Numbers are non-negative integers and MUST NOT include
198             #pod leading zeroes. A trial version indicates that the version is unstable and might not satisfy the
199             #pod intended compatibility requirements as denoted by its associated normal version. Examples:
200             #pod v1.0.0.1, v1.0.0.1.1, v1.0.0.0.3.7, v1.0.0.7.92.
201             #pod
202             #pod =item 10
203             #pod
204             #pod (Paragraph excluded, build metadata is not used.)
205             #pod
206             #pod =item 11
207             #pod
208             #pod Precedence refers to how versions are compared to each other when ordered. Precedence MUST be
209             #pod calculated by separating the version into numbers in order. Precedence is determined by the first
210             #pod difference when comparing each of these numbers from left to right. Example: v1.0.0 < v2.0.0 <
211             #pod v2.1.0 < v2.1.1. A larger set of parts has a higher precedence than a smaller set, if all of the
212             #pod preceding identifiers are equal. Example: v1.0.0 < v1.0.0.1 < v1.0.0.1.1 < v1.0.0.1.2 < v1.0.0.2 <
213             #pod v1.0.1.
214             #pod
215             #pod =back
216             #pod
217             #pod =head2 Why Use Dotted Semantic Versioning?
218             #pod
219             #pod See L.
220             #pod
221             #pod =head2 FAQ
222             #pod
223             #pod See L.
224             #pod
225             #pod =head2 About
226             #pod
227             #pod The Dotted Semantic Versioning specification is authored by Van de Bugger. It is adaptation of
228             #pod Semantic Versioning 2.0.0 for Perl modules.
229             #pod
230             #pod L is authored by L
231             #pod Preston-Werner|http://tom.preston-werner.com/>, inventor of Gravatars and cofounder of GitHub.
232             #pod
233             #pod =for comment ---------------------------------------------------------------------------------------
234             #pod
235             #pod =head1 ADAPTATION DETAILS
236             #pod
237             #pod Paragraphs 1..8 of Semantic Versioning define I version number and establish rules for
238             #pod I, I and I. I would say these paragraphs are core of Semantic Versioning.
239             #pod Happily they can be applied for versioning Perl modules with almost no modifications. I just added
240             #pod leading 'v' character to version numbers.
241             #pod
242             #pod Paragraphs 9..11 define auxiliary stuff (I, I) and version
243             #pod precedence rules. Unfortunately, these paragraphs cannot be applied as-is for versioning Perl
244             #pod modules, they require adaptation.
245             #pod
246             #pod =head2 Paragraph 9, pre-release version
247             #pod
248             #pod Semantic Versioning uses term I. I version is denoted by appending minus
249             #pod sign and a series of dot separated identifiers which comprise alphanumeric and hyphen.
250             #pod
251             #pod Dotted version cannot include letters and hyphens, a workaround is required.
252             #pod
253             #pod First, let us call it I (instead of I), it is more Perlish and CPANish. (BTW,
254             #pod it is also more correct term, because trial versions are actually released.)
255             #pod
256             #pod Second, let us reduce trial identifier alphabet to digits (instead of alphanumeric and hyphen; it
257             #pod fully meets Semantic Versioning, they call such identifiers "numeric").
258             #pod
259             #pod Third, let us denote I version by dot. Dot is already used to separate parts of I
260             #pod version: I, I, and I. However, the number of parts in I version is
261             #pod fixed, so we can easily distinguish I: the first 3 parts compose I version,
262             #pod everything behind I (if any) compose I.
263             #pod
264             #pod =head2 Paragraph 10, build metadata
265             #pod
266             #pod I is denoted by appending a plus sign and dot separated identifiers.
267             #pod
268             #pod Dotted version cannot include plus sign, a workaround is required (again).
269             #pod
270             #pod Replacement plus sign with dot (like replacing hyphen with dot for I versions) does not
271             #pod work: I would be indistinguishable from I version. Fortunately, I
272             #pod metadata> is not mandatory, so let us drop it completely.
273             #pod
274             #pod =head2 Paragraph 11, precedence
275             #pod
276             #pod This paragraph defines version precedence. It prescribes a I version has lower
277             #pod precedence than a I version with the same I, I, and I: 1.0.0-alpha <
278             #pod 1.0.0.
279             #pod
280             #pod This looks good for Semantic Versioning with hyphen and alphanumeric I identifiers,
281             #pod but it does not look good for Dotted Semantic Versioning with only dots and numeric I
282             #pod identifiers: 1.0.0.1 < 1.0.0.
283             #pod
284             #pod So, let us use natural precedence as it implemented by C module: 1.0.0 < 1.0.0.1. A
285             #pod I release can be placed before I release by choosing appropriate I, I,
286             #pod and I versions. For example, a series of I releases preceding version 1.0.0 could be
287             #pod 0.999.999.1, 0.999.999.2, 0.999.999.3, etc, a series of I releases preceding 1.1.0 could be
288             #pod 1.0.999.1, 1.0.999.2, etc.
289             #pod
290             #pod =cut
291              
292             package Version::Dotted::Semantic;
293              
294 2     2   40064 use strict;
  2         3  
  2         47  
295 2     2   5 use warnings;
  2         3  
  2         69  
296              
297             # ABSTRACT: (Adapted) Semantic Versioning
298             our $VERSION = 'v0.0.0_07'; # TRIAL VERSION
299              
300 2     2   407 use parent 'Version::Dotted';
  2         262  
  2         10  
301              
302 2     2   82 use Scalar::Util qw{};
  2         2  
  2         145  
303              
304             # --------------------------------------------------------------------------------------------------
305              
306             #pod =Attribute min_len
307             #pod
308             #pod Minimal number of parts, read-only.
309             #pod
310             #pod $int = Version::Dotted::Semantic->min_len; # == 3
311             #pod
312             #pod C objects always have at least 3 parts.
313             #pod
314             #pod =cut
315              
316 11     11 1 18 sub min_len { 3 }; ## no critic ( RequireFinalReturn )
317              
318             # --------------------------------------------------------------------------------------------------
319              
320             my $names = {
321             major => 0,
322             minor => 1,
323             patch => 2,
324             trial => 3,
325             };
326              
327             # --------------------------------------------------------------------------------------------------
328              
329             #pod =method major
330             #pod
331             #pod =method minor
332             #pod
333             #pod =method patch
334             #pod
335             #pod Returns the first, the second, and the third part of the version, respectively.
336             #pod
337             #pod $int = $v->major; # the first part
338             #pod $int = $v->minor; # the second part
339             #pod $int = $v->patch; # the third part
340             #pod
341             #pod Since version always has at least 3 parts, these methods never return C.
342             #pod
343             #pod =method trial
344             #pod
345             #pod Returns the fourth part of the version.
346             #pod
347             #pod $int = $v->trial; # the fourth part
348             #pod
349             #pod The method returns C if version has less than 4 parts.
350             #pod
351             #pod =cut
352              
353             while ( my ( $name, $idx ) = each( %$names ) ) {
354             my $sub = sub {
355 8     8   11 my ( $self ) = @_;
356 8         37 return $self->{ version }->[ $idx ];
357             };
358 2     2   6 no strict 'refs'; ## no critic ( ProhibitNoStrict )
  2         3  
  2         177  
359             *{ $name } = $sub;
360             };
361              
362             # --------------------------------------------------------------------------------------------------
363              
364             for my $name ( qw{ part bump } ) {
365             my $sub = sub {
366 22     22   565 my ( $self, $idx ) = @_;
367 22 100       65 if ( not Scalar::Util::looks_like_number( $idx ) ) {
368 14   66     32 $idx = $names->{ $idx } // do {
369 2         11 $self->_warn( "Invalid version part name '$idx'" );
370 2         7 return;
371             };
372             };
373 2     2   6 no strict 'refs'; ## no critic ( ProhibitNoStrict )
  2         2  
  2         101  
374 20         13 return &{ "Version::Dotted::$name" }( $self, $idx );
  20         62  
375             };
376 2     2   9 no strict 'refs'; ## no critic ( ProhibitNoStrict )
  2         1  
  2         161  
377             *{ $name } = $sub;
378             };
379              
380             # --------------------------------------------------------------------------------------------------
381              
382             #pod =method is_trial
383             #pod
384             #pod Returns true in case of trial version, and false otherwise.
385             #pod
386             #pod $bool = $v->is_trial;
387             #pod
388             #pod A version is considered trial if it has more than 3 parts:
389             #pod
390             #pod qv( v1.2.3.4 )->is_trial; # true
391             #pod qv( v1.2.4 )->is_trial; # false
392             #pod
393             #pod =cut
394              
395             sub is_trial {
396 2     2 1 4 my ( $self ) = @_;
397 2         1 return @{ $self->{ version } } > 3;
  2         9  
398             };
399              
400             # --------------------------------------------------------------------------------------------------
401              
402             1;
403              
404             # --------------------------------------------------------------------------------------------------
405              
406             #pod =head1 SEE ALSO
407             #pod
408             #pod =for :list
409             #pod = L
410             #pod = L
411             #pod
412             #pod =head1 COPYRIGHT AND LICENSE
413             #pod
414             #pod =over
415             #pod
416             #pod =item Everything except "Dotted Semantic Versioning" chapter
417             #pod
418             #pod Copyright (C) 2016 Van de Bugger
419             #pod
420             #pod License GPLv3+: The GNU General Public License version 3 or later
421             #pod .
422             #pod
423             #pod This is free software: you are free to change and redistribute it. There is
424             #pod NO WARRANTY, to the extent permitted by law.
425             #pod
426             #pod
427             #pod =item "Dotted Semantic Versioning" chapter
428             #pod
429             #pod Licensed under L.
430             #pod
431             #pod =back
432             #pod
433             #pod =cut
434              
435             # ------------------------------------------------------------------------------------------------
436             #
437             # file: doc/what.pod
438             #
439             # This file is part of perl-Version-Dotted.
440             #
441             # ------------------------------------------------------------------------------------------------
442              
443             #pod =encoding UTF-8
444             #pod
445             #pod =head1 WHAT?
446             #pod
447             #pod C and its subclasses complement standard C class with bump operation and
448             #pod (re)define trial versions differently.
449             #pod
450             #pod =cut
451              
452             # end of file #
453              
454              
455             # end of file #
456              
457             __END__