The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Changes::Version - Version string object class

SYNOPSIS

    use Changes::Version;
    my $v = Changes::Version->new(
        major => 1,
        minor => 2,
        patch => 3,
        alpha => 4,
        qv => 1,
        debug => 2,
    );
    # or
    my $v = Changes::Version->new( 'v0.1.2_3' );
    # or
    my $v = Changes::Version->new( 'v0.1.2_3', alpha => 4 );
    # or
    my $v = Changes::Version->new( 'v0.1.2_3', { alpha => 4 } );
    # or
    my $v = Changes::Version->new( major => 0, minor => 1, patch => 2, alpha => 3, qv => 1 );
    # or
    my $v = Changes::Version->new({ major => 0, minor => 1, patch => 2, alpha => 3, qv => 1 });
    die( Changes::Version->error ) if( !defined( $v ) );
    my $v = Changes::Version->parse( 'v1.2.3_4' );
    die( Changes::Version->error ) if( !defined( $v ) );
    my $type = $v->type;
    $v->type( 'decimal' );
    $v->padded(0);
    $v->pretty(1);
    $v->type( 'dotted' );
    $v++;
    # Updating 'minor'
    say "$v"; # v1.3.0
    $v += 2;
    $v->default_frag( 'major' );
    $v++;
    say "$v"; # v2.0.0
    $v->inc_patch;
    say $v->is_alpha; # false
    say $v->numify; # returns new Changes::Version object
    say $v->normal; # returns new Changes::Version object
    say $v->as_string; # same as say "$v";
    # 5.0.6_2
    say $v->format( "%R%d%A" );

VERSION

    v0.2.2

DESCRIPTION

This class represents a software version based on perl's definition and providing for perl recommended dotted decimal and also decimal types. In the future, this will be expanded to other non-perl version formats.

It allows for parsing and manipulation of version objects.

CONSTRUCTOR

new

Provided with an optional version string and an optional hash or hash reference of options and this will instantiate a new Changes::Version object.

If an error occurs, it will return an error, so alway check for the definedness of the returned value.

    my $v = Changes::Version->new(
        major => 1,
        minor => 2,
        patch => 3,
        alpha => 4,
    );
    die( Changes::Version->error ) if( !defined( $v ) );

Note that if you do:

    my $v = Changes::Version->new( ... ) || die( Changes::Version->error );

would be dangerous, because you would be assessing the return version object in a boolean context that could return false if the version was 0.

It supports the following options that can also be accessed or changed with their corresponding method.

  • alpha

    Specifies the alpha fragment integer of the version. See "alpha" for more information.

        my $v = Changes::Version->new(
            major => 1,
            minor => 2,
            patch => 3,
            alpha => 4,
        );
        my $alpha = $v->alpha; # 4
        $v->alpha(7);
        say "$v"; # v1.2.3_7
  • beta

    Specifies the beta fragment integer of the version. See "beta" for more information.

    Currently unused and reserved for future release.

  • compat

    Boolean. When enabled, this will ensure the version formatting is strictly compliant with the version module. Default to false.

  • default_frag

    Specifies the fragment name or integer value used by overloaded operations.

        my $v = Changes::Version->new( 'v1.2.3_4' );
        my $default = $v->default_frag; # By default 'minor'
        $v->default_frag( 'major' );
        $v++; # Version is now v2.2.3_4
  • extra

    Specifies the array reference of version fragments beyond patch

        my $v = Changes::Version->new(
            major => 1,
            minor => 2,
            patch => 3,
            alpha => 12,
            extra => [qw( 4 5 6 7 )],
        );
        say "$v"; # v1.2.3.4.5.6.7_12
        my $a = $v->extra; # contains 4, 5, 6, 7
  • major

    Specifies the major fragment of the version string.

        my $v = Changes::Version->new(
            major => 1,
            minor => 2,
            patch => 3,
            alpha => 4,
        );
        my $major = $v->major; # 1
        say "$v"; # v1.2.3_4
        $v->major(3);
        say "$v"; # v3.0.0
  • minor

    Specifies the minor fragment of the version string.

        my $v = Changes::Version->new(
            major => 1,
            minor => 2,
            patch => 3,
            alpha => 4,
        );
        my $minor = $v->minor; # 2
        say "$v"; # v1.2.3_4
        $v->minor(3);
        say "$v"; # v1.3.0
  • original

    Specifies an original version string. This is normally set by "parse" and used by "as_string" to bypass any formatting when nothing has been changed.

  • padded

    Specifies whether version string of type decimal should be zero padded or not. Default to true.

        my $v = Change::Version->new(
            major => 1,
            minor => 20,
            patch => 300,
            type => 'decimal',
        );
        say "$v"; # 1.020300
        $v->padded(0);
        say "$v"; # 1.0203
  • patch

    Specifies the patch fragment of the version string.

        my $v = Changes::Version->new(
            major => 1,
            minor => 2,
            patch => 3,
            alpha => 4,
        );
        my $patch = $v->patch; # 3
        say "$v"; # v1.2.3_4
        $v->patch(7);
        say "$v"; # v1.3.7
  • pretty

    Specifies whether version string of type decimal should be formatted with an underscore (_) separating thousands in the fraction part.

        my $v = Change::Version->new(
            major => 1,
            minor => 20,
            patch => 300,
            type => 'decimal',
            pretty => 1,
        );
        say "$v"; # 1.020_300
        $v->pretty(0);
        say "$v"; # 1.020300
  • qv

    Specifies whether version string of type dotted should be formatted with the prefix v. Defaults to true.

        my $v = Changes::Version->new(
            major => 1,
            minor => 2,
            patch => 3,
            alpha => 4,
        );
        say "$v"; # v1.2.3_4
        $v->qv(0);
        say "$v"; # 1.2.3_4
  • rc

    Specifies the release candidate value. This is currently unused and reserved for future release.

  • target

    Specifies the target formatting for the version string. By default this is perl and is the only supported value for now. In future release, other format types will be supported, such as opensource.

  • type

    Specifies the version type. Possible values are dotted for dotted decimal versions such as v1.2.3 or decimal for decimal versions such as 1.002003

parse

Provided with a version string, and this will parse it and return a new Changes::Version object.

Currently, only 2 version types are supported: dotted decimal and decimal

    v1.2
    1.2345.6
    v1.23_4
    1.2345
    1.2345_01

are all legitimate version strings.

If an error occurred, this will return an error.

METHODS

alpha

Sets or gets the alpha fragment integer of the version.

Setting this to undef effectively removes it.

Returns a number object

as_string

Returns a version string properly formatted according to the type set with "type" and other parameters sets such as "qv", "padded" and "pretty"

Resulting value is cached, which means the second time this is called, the cached value will be returned for speed.

Any change to the version object parameters, and this will force the re-formatting of the version string.

For example:

    my $v = Changes::Version->new( 'v1.2.3_4' );
    # This is a version of type 'dotted' for dotted decimal
    say "$v"; # v1.2.3_4
    # Changing the patch level
    $v->inc( 'patch' );
    # Now forced to re-format
    say "$v"; # v1.2.4
    # No change, using the cache
    say "$v"; # v1.2.4

beta

The beta fragment integer of the version. This is currently unused and reserved for future release of this class.

compat

Boolean. When enabled, this will ensure the version formatting is strictly compliant with the version module. Default to false.

dec

Provided with a version fragment, and an optiona integer, and this will decrease the version fragment value by as much. If no integer is provided, the default decrement is 1.

    my $v = Changes::Version->new(
        major => 1,
        minor => 2,
        patch => 3,
        alpha => 4,
    );
    say "$v"; # v1.2.3_4;
    $v->dec( 'alpha' );
    say "$v"; # v1.2.3_3;
    $v->dec( 'patch', 2 );
    say "$v"; # v1.2.1

    my $v = Changes::Version->new( 'v1.2.3.4.5.6.7_8' );
    # Decrease the 5th fragment
    $v->dec(5);
    say "$v"; # v1.2.3.4.4.0.0

Any change to a fragment value will reset the lower fragment values to zero. Thus:

  • changing the major value will reset minor and patch to 0 and alpha to undef

  • changing the minor value will reset patch to 0 and alpha to undef

  • changing the patch value will reset alpha to undef

  • changing the nth fragment value will reset all fragment value after that to 0

If you pass a fragment that is an integer and it is outside the maximum number of fragments, it will automatically expand the number of version fragments and initialise the intermediary fragments to 0. A fragment as an integer starts at 1.

Using the example above:

    $v->dec(10);
    say "$v"; # v1.2.3.4.5.6.7.0.0.0

The 10th element is set to 0 because it does not exist, so it cannot be decreased.

dec_alpha

This is a shortcut for calling "dec" on fragment alpha

dec_beta

This is a shortcut for calling "dec" on fragment beta

dec_major

This is a shortcut for calling "dec" on fragment major

dec_minor

This is a shortcut for calling "dec" on fragment minor

dec_patch

This is a shortcut for calling "dec" on fragment patch

default_frag

    my $v = Changes::Version->new( 'v1.2.3_4' );
    my $default = $v->default_frag; # By default 'minor'
    $v->default_frag( 'major' );
    $v++; # Version is now v2.2.3_4

String. Sets or gets the name or the integer value for the version fragment. Supported value can be major, minor. patch, alpha, or an integer.

Returns a scalar object

extra

Sets or gets an array reference of version fragments starting from 1 for major, 2 for minor, 3 for patch, etc. For example:

    my $v = Changes::Version->new( 'v1.2.3.4.5.6.7_8' );
    my $a = $v->extra; # contains 4, 5, 6, 7

Note that alpha is not accessible via digits, but only using "alpha"

You should not be accessing this directly.

Returns an array object

format

    my $v = Changes::Version->parse( "5.0.6_2" );
    say $v->format( "%R%d" ); # 5.0.6

This formats the version string. It takes a string representing a pattern, or an array reference of pattern elements and returns a regular string.

If an error occurred, it sets an error object and returns undef in scalar context, or an empty list in list context.

See also "pattern" to get or set a pattern used by "as_string"

See also below the possible patterns

inc

Same as "dec", but increasing instead of decreasing.

inc_alpha

This is a shortcut for calling "inc" on fragment alpha

inc_beta

This is a shortcut for calling "inc" on fragment beta

inc_major

This is a shortcut for calling "inc" on fragment major

inc_minor

This is a shortcut for calling "inc" on fragment minor

inc_patch

This is a shortcut for calling "inc" on fragment patch

is_alpha

Returns true if "alpha" has a value set.

is_qv

Returns true if "qv" is set to true, false otherwise.

major

Sets or gets the major fragment of the version string.

    my $v = Changes::Version->new( 'v1.2.3_4' );
    my $major = $v->major; # 1
    $v->major(3);
    say "$v"; # v3.2.3_4

Setting this to undef effectively removes it.

Returns a number object

minor

Sets or gets the minor fragment of the version string.

    my $v = Changes::Version->new( 'v1.2.3_4' );
    my $minor = $v->minor; # 2
    $v->minor(3);
    say "$v"; # v1.3.3_4

Setting this to undef effectively removes it.

Returns a number object

normal

Returns a new Changes::Version object as a normalised version, which is a dotted decimal format with the v prefix.

If an error occurred, an error is returned.

numify

Returns a new Changes::Version object as a number, which represent a decimal-type version

Contrary to version if there is an alpha value set, it will add it to the numified version.

    my $v = Changes::Version->new(
        major => 1,
        minor => 2,
        patch => 3,
        alpha => 4,
    );
    say $v->numify; # 1.002003_4

version would yields a different, albeit wrong result:

    perl -Mversion -lE 'say version->parse("v1.2.3_4")->numify'

would wrongly return 1.002034 and not 1.002003_4

    perl -Mversion -lE 'say version->parse("1.002034")->normal'

then yields v1.2.34

If an error occurred, an error is returned.

original

Sets or gets the original string. This is set by "parse"

Returns a scalar object

padded

Boolean. Sets or ges whether the resulting version string of type decimal should be '0' padded or not. Default to pad with zeroes decimal numbers.

For example:

    my $v = Changes::Version->new(
        major => 1,
        minor => 2,
        patch => 30,
        type => 'decimal',
        padded => 1,
    );
    say "$v"; # 1.002030
    $v->padded(0);
    say "$v"; # 1.00203

Returns a boolean object

patch

Sets or gets the patch fragment of the version string.

    my $v = Changes::Version->new( 'v1.2.3_4' );
    my $patch = $v->patch; # 3
    $v->patch(5);
    say "$v"; # v1.3.5_4

Returns a number object

pattern

Sets or gets a format pattern. This returns a regular string, or undef if no pattern has been set.

See also the list of patterns

pretty

Boolean. When enabled, this will render version number for decimal type a bit cleaner by separating blocks of 3 digits by an underscore (_). This does not work on dotted decimal version numbers such as v1.2.3 or on version that have an alpha set up.

    my $v = Changes::Version->new(
        major => 1,
        minor => 2,
        patch => 30,
        type => 'decimal',
    );

Returns a boolean object

qv

Boolean. When enabled, this will prepend the dotted decimal version strings with v. This is true by default.

    my $v = Changes::Version->new(
        major => 1,
        minor => 2,
        patch => 3,
        alpha => 4,
    );
    say "$v"; # v1.2.3_4
    $v->qv(0);
    say "$v"; # 1.2.3_4

Returns a boolean object

rc

Sets or gets the release candidate value. This is currently unused and reserved for future releases.

Returns a scalar object

satisfy

    $v->satisfy( $predicate );

    $v = Changes::Version->parse( '0.1.1' );
    $v->satisfy( '0.1.1' ); # true
    $v->satisfy( '0.1.1', '> 0, < 0.2, != 0.1.0' ); # true
    $v = Changes::Version->parse( '0.2.4' );
    $v->satisfy( '0.2.5..0.3.4' ); # false
    # or, using it as a class function:
    Changes::Version->satisfy( '0.1.1', '0.1.1' ); # true
    Changes::Version->satisfy( '0.1.1', '> 0, < 0.2, != 0.1.0' ); # true
    Changes::Version->satisfy( '0.2.4', '0.2.5..0.3.4' ); # false

Determines if a v-string satisfy a predicate. The predicate is a list of simple predicates, each one must be satisfied (that is, an and). Simple predicates takes one of three forms:

    '0.1.2'       - exact match 
    '>= 3.14.15'  - (relational operator) (v-string)
    '5.6 .. 10.8' - meaning '>= 5.6, <= 10.8'

A grammar for predicates in Parse::RecDescent-like syntax is:

    <p> : <p0> (',' <p>)*

    <p0>: <v-string>                # the same as '==' <v-string>
      | <op> <v-string> 
      | <v-string> '..' <v-string>  # the same as ">= <v-string1>, <= <v-string2>"

    <op>: '==' | '!=' | '<=' | '>=' | '<' | '>'

Spaces are irrelevant in predicates.

stringify

This is an alias for "as_string"

target

Sets or gets the target format. By default this is perl. This means that "as_string" will format the version string for perl. In future release of this class, other format wil be supported, such as opensource

Returns a scalar object

type

Sets or gets the version type. Currently, supported values are dotted for dotted decimal versions such as v1.2.3, and decimal for decimal versions such as 1.002003.

Returns a scalar object

OVERLOADED OPERATIONS

The following operations are overloaded, and internally relies on version to return the value. See also overload for more information.

Note that calling the version object with any operations other than those listed below will trigger a warning, if warnings are enabled with warnings and undef is return in scalar context or an empty list in list context.

  • stringification

    Returns value from "as_string"

  • 0+

    Returns value from "numify"

  • <=>

    Compares two versions. If the other version being compared is not a Changes::Version, it is made one before comparison actually occurs.

    Note that, version core module states in its documentation that: "alpha" version objects (where the version string contains a trailing underscore segment) compare as less than the equivalent version without an underscore."

        $bool = version->parse("1.23_45") < version->parse("1.2345"); # TRUE

    However, as of perl v5.10, this is not true. The above will actually return false, not true. And so will the following:

        perl -Mversion -lE 'say version->parse("v1.002003") > version->parse("v1.002003_4");'

    This is on my bucket list of things to improve.

  • cmp

    Same as above.

  • bool

  • +, -, *, /

    When performing those operations, it will use the value of the fragment of the version set with "default_frag", which, by default, is minor.

    It returns a new Changes::Version object reflecting the new version value. However, if the operation is swapped, with the version object on the right-hand side instead of the left-hand side, this will return a regular number.

        my $vers = Changes::Version->new( 'v1.2.3_4' );
        my $new_version_object = $vers + 2; # Now v1.4.3_4 (minor has been bumped up by 2)
        $vers->default_frag( 'major' );
        my $new_version_object = $vers + 2; # Now v3.2.3_4 (this time, 'major' was increased)

    But, when swapped:

        my $vers = Changes::Version->new( 'v1.2.3_4' );
        my $n = 3 + $vers; # yields 5 (using the 'minor' fragment by default)
        $vers->default_frag( 'major' );
        my $n = 3 + $vers; # yields 4 (this time, using the 'major' fragment)
  • +=, -=, *=, /=

    In this operations, it modifies the current object with the operand provided and returns the current object, instead of creating a new one.

        my $vers = Changes::Version->new( 'v1.2.3_4' );
        # By default, using the 'minor' fragment
        $vers += 1; # version is now v2.2.3_4
        $vers->default_frag( 'alpha' );
        $vers /= 2; # version is now v1.2.3_2
  • ++, --

    When using those operations, it updates the current object directly and returns it. For example:

        my $vers = Changes::Version->new( 'v1.2.3_4' );
        # By default, using the 'minor' fragment
        $vers++; # version is now v1.3.3_4

PATTERNS

The following patterns can be used to format the version string.

  • %A

        my $v = Changes::Version->parse( "5.0.6_2" );
        say $v->format( '%A' ); # _2

    This will return the alpha version, if any, prepended with an underscore.

    If there is no alpha version, it returns an empty string.

  • %a

        my $v = Changes::Version->parse( "5.0.6_2" );
        say $v->format( '%a' ); # 2

    This will return the alpha fragment value, if any.

    If there is no alpha fragment value, it returns an empty string.

  • %D

        my $v = Changes::Version->parse( "5.0.6.1.2.3.4_2" );
        say $v->format( '%D' ); # 0.6.1.2.3.4
        my $v = Changes::Version->parse( "5.0.6" );
        say $v->format( '%D' ); # 0.6

    This will return the minor, patch, and any extra fragments.

    This is designed for dotted-decimal types, and minor, and patch will always return a number, possibly 0

  • %d

        my $v = Changes::Version->parse( "5.0.6.1.2.3.4_2" );
        say $v->format( '%D' ); # .0.6.1.2.3.4
        my $v = Changes::Version->parse( "5.0.6" );
        say $v->format( '%D' ); # .0.6

    This is similar to %D, but will prepend a dot if the value is not null.

    This is designed so you can write:

        my $v = Changes::Version->parse( "5.0.6.1.2.3.4_2" );
        say $v->format( '%R%d%A' ); # 5.0.6.1.2.3.4_2
        my $v = Changes::Version->parse( "5" );
        say $v->format( '%R%d%A' ); # 5.0.0
  • %M

        my $v = Changes::Version->parse( "5.2.6_3" );
        say $v->format( '%M' ); # 2

    This returns the minor part of the version.

    If there is no minor fragment value, it returns an empty string.

  • %m

        my $v = Changes::Version->parse( "5.2.6_3" );
        say $v->format( '%m' ); # .2

    This is similar to %M, but will prepend a dot if the value is not null.

  • %N

        my $v = Changes::Version->parse( "5.2.6" ):
        say $v->format( '%R.%N' ); # 5.002006

    This returns the minor and patch value of a dotted-decimal version as numified version.

  • %n

        my $v = Changes::Version->parse( "5.2.6" ):
        say $v->format( '%R%n' ); # 5.002006
        say $v->format( '%n' ); # .002006

    This is similar to %N, but will prepend a dot if the value is not null.

  • %P

    This returns the patch fragment value of the version, if any.

    If there is no patch fragment value, it returns an empty string.

  • %R

    This returns the major fragment value of the version, if any.

    If there is no major fragment value, it returns an empty string.

  • %U

        my $v = Changes::Version->parse( "5.2.6" ):
        say $v->format( '%R.%U' ); # 5.002_006
        say $v->format( '%U' ); # 002_006

    This returns the minor and patch value of a dotted-decimal version as numified version using the underscore to separate the minor and the patch fragments.

  • %u

        my $v = Changes::Version->parse( "5.2.6" ):
        say $v->format( '%R%u' ); # 5.002_006
        say $v->format( '%u' ); # .002_006

    This is similar to %U, but will prepend a dot if the value is not null.

AUTHOR

Jacques Deguest <jack@deguest.jp>

SEE ALSO

Changes, Changes::Release, Changes::Group, Changes::Change and Changes::NewLine

version, Perl::Version, version::Internals, Data::VString, "Version Strings" in perldata

"Version Formats" in CPAN::Meta::Spec

http://www.modernperlbooks.com/mt/2009/07/version-confusion.html

https://xdg.me/version-numbers-should-be-boring/

https://en.wikipedia.org/wiki/Software_versioning

COPYRIGHT & LICENSE

Copyright(c) 2022 DEGUEST Pte. Ltd.

All rights reserved

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.