Changes

 view release on metacpan or  search on metacpan

lib/Changes/Version.pm  view on Meta::CPAN

use strict;
use warnings;

sub init
{
    my $self = shift( @_ );
    $self->{alpha}  = undef;
    # Used for other version types
    $self->{beta}   = undef;
    $self->{compat} = 0;
    # What version fragment to increase/decrease by default, such as when we do operations like $v++ or $v--
    $self->{default_frag} = 'minor';
    $self->{extra}  = [];
    $self->{major}  = undef;
    $self->{minor}  = undef;
    $self->{original} = undef;
    $self->{padded} = 1;
    $self->{patch}  = undef;
    $self->{pattern} = undef;
    $self->{pretty} = 0;
    $self->{qv}     = 0;
    # Release candidate used by non-perl open source softwares
    $self->{rc}     = undef;
    $self->{target} = 'perl';
    $self->{type}   = undef;
    my $keys = [qw( alpha beta compat default_frag extra  major minor original patch qv rc target type _version )];
    my $vstr;
    # Changes::Version->new( 'v0.1.2_3' ); or
    # Changes::Version->new( 'v0.1.2_3', alpha => 4 ); or
    # Changes::Version->new( 'v0.1.2_3', { alpha => 4 } ); or
    # Changes::Version->new( major => 0, minor => 1, patch => 2, alpha => 3, qv => 1 ); or
    # Changes::Version->new({ major => 0, minor => 1, patch => 2, alpha => 3, qv => 1 }); or
    if( ( @_ == 1 && ref( $_[0] ) ne 'HASH' ) ||
        ( @_ > 1 && ref( $_[0] ) ne 'HASH' && ( ( @_ % 2 ) || ref( $_[1] ) eq 'HASH' ) ) )
    {
        $vstr = shift( @_ );

lib/Changes/Version.pm  view on Meta::CPAN


# For non-perl open source softwares
sub dec_beta { return( shift->_inc_dec( 'dec' => 'beta', @_ ) ); }

sub dec_major { return( shift->_inc_dec( 'dec' => 'major', @_ ) ); }

sub dec_minor { return( shift->_inc_dec( 'dec' => 'minor', @_ ) ); }

sub dec_patch { return( shift->_inc_dec( 'dec' => 'patch', @_ ) ); }

sub default_frag { return( shift->_set_get_scalar_as_object( 'default_frag', @_ ) ); }

sub extra { return( shift->_set_get_array_as_object( 'extra', @_ ) ); }

sub format
{
    my $self = shift( @_ );
    my $fmt  = shift( @_ ) ||
        return( $self->error( "No pattern was provided to format this version." ) );
    # NOTE: numify()
    my $numify = sub

lib/Changes/Version.pm  view on Meta::CPAN

sub parse
{
    my $self = shift( @_ );
    my $str  = shift( @_ );
    return( $self->error( "No version string was provided." ) ) if( !defined( $str ) || !length( "$str" ) );
    if( $] >= 5.008_001 && ref( \$str ) eq 'VSTRING' )
    {
        my $def = { original => $str };
        $def->{type} = 'dotted';
        $def->{qv} = 1;
        my @frags = map{ ord( $_ ) } split( //, $str );
        @$def{qw( major minor patch )} = splice( @frags, 0, 3 );
        $def->{extra} = \@frags;
        $def->{pattern} = '%R%d';
        my $new = $self->new( %$def );
        $new->{_version} = version->parse( $str );
        return( $new );
    }

    if( $str =~ /^$VERSION_LAX_REGEX$/ )
    {
        my $re = { %+ };
        my $def = { original => $str };

lib/Changes/Version.pm  view on Meta::CPAN

                my $vstr = $v->normal;
                if( $vstr =~ /^$VERSION_LAX_REGEX$/ )
                {
                    my $re2 = { %+ };
                    if( defined( $re2->{dotted} ) && length( $re2->{dotted} ) )
                    {
                        if( defined( $re2->{minor_patch} ) )
                        {
                            # delete( $def->{alpha} );
                            $def->{major} = $re2->{major};
                            my @frags = split( /\./, $re2->{minor_patch} );
                            shift( @frags );
                            $def->{minor} = shift( @frags );
                            $def->{patch} = shift( @frags );
                            $def->{extra} = \@frags;
                        }
                    }
                }
            }
            else
            {
                $v = version->parse( $re->{dotted} );
                # Same as %M%P%E -> 5.3.4.5.6.7.8
                push( @$fmt, '%d' );
                push( @$fmt, '%a' ) if( defined( $def->{alpha} ) && length( $def->{alpha} ) );
                if( defined( $re->{minor_patch} ) )
                {
                    my @frags = split( /\./, $re->{minor_patch} );
                    # throw away the empty data because of the leading dot
                    shift( @frags );
                    $def->{minor} = shift( @frags );
                    $def->{patch} = shift( @frags );
                    $def->{extra} = \@frags;
                }
            }
            $def->{pattern} = join( '', @$fmt );
        }
        elsif( $def->{type} eq 'decimal' )
        {
            # $def->{minor} = $re->{minor} if( defined( $re->{minor} ) );
            # $re->{release} is the decimal version without the alpha information if it is smaller than 3
            # This issue stems from decimal number having an underscore can either mean they have a version like
            # 5.006_002 which would be equivalent v5.6.2 and in this case, "_002" is not an alpha information; and

lib/Changes/Version.pm  view on Meta::CPAN

            #     my $vstr = $v->normal;
            #     if( $vstr =~ /^$VERSION_LAX_REGEX$/ )
            #     {
            #         my $re2 = { %+ };
            #         if( defined( $re2->{dotted} ) && length( $re2->{dotted} ) )
            #         {
            #             if( defined( $re2->{minor_patch} ) )
            #             {
            #                 # delete( $def->{alpha} );
            #                 $def->{major} = $re2->{major};
            #                 my @frags = split( /\./, $re2->{minor_patch} );
            #                 shift( @frags );
            #                 $def->{minor} = shift( @frags );
            #                 $def->{patch} = shift( @frags );
            #                 $def->{extra} = \@frags;
            #             }
            #         }
            #     }
            # }
        }
        my $new = $self->new( %$def );
        $new->{_version} = $v if( defined( $v ) );
        return( $self->pass_error ) if( !defined( $new ) );
        CORE::delete( $new->{_reset} );
        return( $new );

lib/Changes/Version.pm  view on Meta::CPAN

sub _bool
{
    my $self = shift( @_ );
    # return( $self->_compare( $self->_version, version->new("0"), 1 ) );
    return( $self->_compare( $self, "0", 1 ) );
}

sub _bubble
{
    my $self = shift( @_ );
    my $frag = shift( @_ );
    my $val  = shift( @_ );
    # We die, because this is an internal method and those cases should not happen unless this were a design bug
    if( !defined( $frag ) || !length( $frag ) )
    {
        die( "No fragment was provided to cascade" );
    }
    elsif( $frag !~ /^(major|minor|patch|alpha|\d+)$/ )
    {
        die( "Unsupported version fragment '$frag'. Only use 'major', 'minor', 'patch' or 'alpha' or a number starting from 1 (1 = major, 2 = minor, etc)." );
    }
    # Not for us. We bubble only when a value is negative resulting from a cascading decrease
    # e.g. 3.12.-1 -> 3.11.0, or 3.0.-1 -> 2.9.0, or 2.-1 -> 1.0
    elsif( $val >= 0 )
    {
        return;
    }
    my $type = $self->type;
    my $extra = $self->extra;
    my $frag_is_int = ( $frag =~ /^\d+$/ ? 1 : 0 );
    my $frag2num =
    {
        major => 1,
        minor => 2,
        patch => 3,
    };
    my $num2frag =
    {
        1 => 'major',
        2 => 'minor',
        3 => 'patch',
    };

    if( $frag eq 'alpha' )
    {
        $self->alpha( undef );
        return;
    }
    die( "Fragment provided '$frag' cannot be 0." ) if( $frag_is_int && $frag == 0 );
    my $level = $frag_is_int ? $frag : $frag2num->{ $frag };

    # Should not be happening
    if( $type eq 'decimal' && $level > 2 )
    {
        $self->patch( undef );
        $self->alpha( undef );
        @$extra = ();
        return;
    }

    for( my $i = $level; $level >= 1; $i-- )
    {
        if( $val < 0 )
        {
            my $new_val = 0;
            unless( $i == 1 )
            {
                my $up_val;
                my $j = $i - 1;
                if( exists( $num2frag->{ $j } ) )
                {
                    my $coderef = $self->can( $num2frag->{ $j } ) ||
                        die( "Cannot find reference for method ", $num2frag->{ $j } );
                    $up_val = $coderef->( $self );
                }
                else
                {
                    $up_val = $extra->[ $j - 4 ];
                }
                # Set value for next iteration
                $val = ( $up_val // 0 ) - 1;
                $new_val = ( $up_val > 0 ) ? 9 : 0;
            }

            if( exists( $num2frag->{ $i } ) )
            {
                # my $coderef = $self->can( $num2frag->{ $i } ) ||
                #     die( "Cannot find reference for method ", $num2frag->{ $i } );
                # $coderef->( $self, 0 );
                $self->{ $num2frag->{ $i } } = $new_val;
            }
            else
            {
                $extra->[ $i - 4 ] = $new_val;
            }
        }
        else
        {
            if( exists( $num2frag->{ $i } ) )
            {
                # my $coderef = $self->can( $num2frag->{ $i } ) ||
                #     die( "Cannot find reference for method ", $num2frag->{ $i } );
                # $coderef->( $self, 0 );
                $self->{ $num2frag->{ $i } } = $val;
            }
            else
            {
                $extra->[ $i - 4 ] = $val;
            }
            last;
        }
    }
    $self->_cascade( $level );
}

sub _cascade
{
    my $self = shift( @_ );
    my $frag = shift( @_ );
    # We die, because this is an internal method and those cases should not happen unless this were a design bug
    if( !defined( $frag ) || !length( $frag ) )
    {
        die( "No fragment was provided to cascade" );
    }
    elsif( $frag !~ /^(major|minor|patch|alpha|\d+)$/ )
    {
        die( "Unsupported version fragment '$frag'. Only use 'major', 'minor', 'patch' or 'alpha' or a number starting from 1 (1 = major, 2 = minor, etc)." );
    }
    my $type = $self->type;
    my $extra = $self->extra;
    my $frag_is_int = ( $frag =~ /^\d+$/ ? 1 : 0 );
    if( $frag eq 'major' || ( $frag_is_int && $frag == 1 ) )
    {
        $self->alpha( undef );
        $self->patch(0);
        # $self->patch( $type eq 'decimal' ? undef : 0 );
        $self->minor(0);
    }
    elsif( $frag eq 'minor' || ( $frag_is_int && $frag == 2 ) )
    {
        $self->alpha( undef );
        $self->patch(0);
        # $self->patch( $type eq 'decimal' ? undef : 0 );
    }
    elsif( $frag eq 'patch' || ( $frag_is_int && $frag == 3 ) )
    {
        $self->alpha( undef );
    }
    elsif( $frag eq 'alpha' )
    {
        # Nothing to do
    }
    elsif( $type eq 'dotted' && $frag_is_int )
    {
        my $offset = ( $frag - 4 );
        my $len = $extra->length;
        # Before the fragment offset, we set the value to 0 if it is undefined or empty, and
        # after the fragment offset everything else is reset to 0
        for( my $i = 0; $i < ( $offset < $len ? $len : $offset ); $i++ )
        {
            if( (
                    $i < $offset && 
                    ( !defined( $extra->[$i] ) || !length( $extra->[$i] ) )
                ) || $i > $offset )
            {
                $extra->[$i] = 0;
            }
        }

lib/Changes/Version.pm  view on Meta::CPAN

    # return( $left->{_version} == $right->{_version} );
    # return( $lv == $rv );
    return( $lv <=> $rv );
}

sub _compute
{
    my $self = shift( @_ );
    my $opts = pop( @_ );
    my( $other, $swap, $nomethod, $bitwise ) = @_;
    my $frag = $self->default_frag // 'minor';
    $frag = 'minor' if( $frag !~ /^(major|minor|patch|alpha|\d+)$/ );
    if( !defined( $opts ) || 
        ref( $opts ) ne 'HASH' || 
        !exists( $opts->{op} ) || 
        !defined( $opts->{op} ) || 
        !length( $opts->{op} ) )
    {
        die( "No argument 'op' provided" );
    }
    my $op = $opts->{op};
    my $clone = $self->clone;
    my $extra = $self->extra;
    my $frag_is_int = ( $frag =~ /^\d+$/ ? 1 : 0 );
    my $map =
    {
    1 => 'major',
    2 => 'minor',
    3 => 'patch',
    };
    my $coderef;
    if( ( $frag_is_int && exists( $map->{ $frag } ) ) || !$frag_is_int )
    {
        $coderef = $self->can( $map->{ $frag } // $frag ) ||
            die( "Cannot find code reference for method ", ( $frag_is_int ? $map->{ $frag } : $frag ) );
    }
    my $val = defined( $coderef ) ? $coderef->( $self ) : $extra->[ $frag - 4 ];
    my $err;
    if( !defined( $val ) )
    {
        $val = $self->new_number(0);
    }
    elsif( !$self->_is_a( $val => 'Module::Generic::Number' ) )
    {
        $val = $self->new_number( "$val" );
        if( !defined( $val ) )
        {

lib/Changes/Version.pm  view on Meta::CPAN

            $new = $self;
            $new_val = $n;
        }
        else
        {
            $new_val = int( $rv );
        }

        if( $new_val < 0 )
        {
            $new->_bubble( $frag, $new_val );
        }
        else
        {
            if( defined( $coderef ) )
            {
                $coderef->( $new, $new_val );
            }
            else
            {
                $extra->[( $frag - 4 )] = $new_val;
            }
            $new->_cascade( $frag );
        }
        $new->reset(1);
        return( $new );
    }
}

sub _inc_dec
{
    my $self = shift( @_ );
    my $op = shift( @_ ) || return( $self->error( "No op was provided." ) );
    return( $self->error( "Op can only be 'inc' or 'dec'" ) ) if( $op !~ /^(inc|dec)$/ );
    my $frag = shift( @_ );
    my $unit = shift( @_ );
    if( !defined( $frag ) || !length( "$frag" ) )
    {
        return( $self->error( "No version fragment was specified to ", ( $op eq 'inc' ? 'increase' : 'decrease' ), " the version number." ) );
    }
    elsif( $frag !~ /^(major|minor|patch|alpha|\d+)$/ )
    {
        return( $self->error( "Unsupported version fragment '$frag' to ", ( $op eq 'inc' ? 'increase' : 'decrease' ), ". Only use 'major', 'minor', 'patch' or 'alpha' or a number starting from 1 (1 = major, 2 = minor, etc)." ) );
    }
    if( defined( $unit ) && $unit !~ /^\d+$/ )
    {
        return( $self->error( "Unit to ", ( $op eq 'inc' ? 'increase' : 'decrease' ), " fragment $frag value must be an integer." ) );
    }
    my $extra = $self->extra;
    my $frag_is_int = ( $frag =~ /^\d+$/ ? 1 : 0 );
    my $map =
    {
    1 => 'major',
    2 => 'minor',
    3 => 'patch',
    };
    my $coderef;
    if( ( $frag_is_int && exists( $map->{ $frag } ) ) || !$frag_is_int )
    {
        $coderef = $self->can( $map->{ $frag } // $frag ) ||
            die( "Cannot find code reference for method ", ( $frag_is_int ? $map->{ $frag } : $frag ) );
    }
    my $n = defined( $coderef ) ? $coderef->( $self ) : $extra->[ $frag - 4 ];
    # The offset specified is out of bound
    if( $frag_is_int && ( $frag - 4 ) > $extra->size )
    {
        $n = (
            $op eq 'inc'
                ? ( defined( $unit ) ? $unit : 1 )
                : 0
        );
    }
    elsif( defined( $unit ) && $unit == 1 )
    {
        $op eq 'inc' ? ( $n += $unit ) : ( $n -= $unit );

lib/Changes/Version.pm  view on Meta::CPAN

    {
        $op eq 'inc' ? $n++ : $n--;
    }

    if( defined( $coderef ) )
    {
        $coderef->( $self, $n );
    }
    else
    {
        $extra->[( $frag - 4 )] = $n;
    }
    $self->_cascade( $frag );
    $self->reset(1);
    return( $self );
}

sub _noop
{
    my( $self, $other, $swap, $nomethod, $bitwise ) = @_;
    warn( "This operation $nomethod is not supported by Changes::Version\n" ) if( $self->_warnings_is_enabled );
}

lib/Changes/Version.pm  view on Meta::CPAN

    }
    my $ok = 0;
    if( !$self->extra->is_empty )
    {
        $ok++;
        $comp->push( $self->extra->list );
    }
    for( qw( patch minor major ) )
    {
        next if( !length( $def->{ $_ } ) && !$ok );
        # We stop skipping version fragments as soon as one is defined
        $ok++;
        $comp->unshift( $def->{ $_ } );
    }
    my $v = ( $self->qv ? 'v' : '' ) . $comp->map(sub{ 0 + $_ })->join( '.' )->scalar;
    $v .= '_' . $def->{alpha} if( defined( $def->{alpha} ) && length( $def->{alpha} ) );
    return( $v );
}

sub _verify
{

lib/Changes/Version.pm  view on Meta::CPAN

    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" );

lib/Changes/Version.pm  view on Meta::CPAN

    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 C<0>.

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

=over 4

=item * C<alpha>

Specifies the alpha fragment integer of the version. See L</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

=item * C<beta>

Specifies the beta fragment integer of the version. See L</beta> for more information.

Currently unused and reserved for future release.

=item * C<compat>

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

=item * C<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

=item * C<extra>

Specifies the array reference of version fragments beyond C<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

=item * C<major>

Specifies the C<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

=item * C<minor>

Specifies the C<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);

lib/Changes/Version.pm  view on Meta::CPAN

        minor => 20,
        patch => 300,
        type => 'decimal',
    );
    say "$v"; # 1.020300
    $v->padded(0);
    say "$v"; # 1.0203

=item * C<patch>

Specifies the C<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);

lib/Changes/Version.pm  view on Meta::CPAN

    1.2345_01

are all legitimate version strings.

If an error occurred, this will return an L<error|Module::Generic/error>.

=head1 METHODS

=head2 alpha

Sets or gets the C<alpha> fragment integer of the version.

Setting this to C<undef> effectively removes it.

Returns a L<number object|Module::Generic::Number>

=head2 as_string

Returns a version string properly formatted according to the C<type> set with L</type> and other parameters sets such as L</qv>, L</padded> and L</pretty>

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

lib/Changes/Version.pm  view on Meta::CPAN

    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

=head2 beta

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

=head2 compat

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

=head2 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:

=over 4

=item * changing the C<major> value will reset C<minor> and C<patch> to 0 and C<alpha> to C<undef>

=item * changing the C<minor> value will reset C<patch> to 0 and C<alpha> to C<undef>

=item * changing the C<patch> value will reset C<alpha> to C<undef>

=item * changing the nth fragment value will reset all fragment value after that to 0

=back

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.

=head2 dec_alpha

This is a shortcut for calling L</dec> on fragment C<alpha>

=head2 dec_beta

This is a shortcut for calling L</dec> on fragment C<beta>

=head2 dec_major

This is a shortcut for calling L</dec> on fragment C<major>

=head2 dec_minor

This is a shortcut for calling L</dec> on fragment C<minor>

=head2 dec_patch

This is a shortcut for calling L</dec> on fragment C<patch>

=head2 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 C<major>, C<minor>. C<patch>, C<alpha>, or an integer.

Returns a L<scalar object|Module::Generic::Scalar>

=head2 extra

Sets or gets an array reference of version fragments starting from C<1> for C<major>, C<2> for C<minor>, C<3> for C<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 C<alpha> is not accessible via digits, but only using L</alpha>

You should not be accessing this directly.

Returns an L<array object|Module::Generic::Array>

lib/Changes/Version.pm  view on Meta::CPAN

See also L</pattern> to get or set a pattern used by L</as_string>

See also below the L<possible patterns|/"PATTERNS">

=head2 inc

Same as L</dec>, but increasing instead of decreasing.

=head2 inc_alpha

This is a shortcut for calling L</inc> on fragment C<alpha>

=head2 inc_beta

This is a shortcut for calling L</inc> on fragment C<beta>

=head2 inc_major

This is a shortcut for calling L</inc> on fragment C<major>

=head2 inc_minor

This is a shortcut for calling L</inc> on fragment C<minor>

=head2 inc_patch

This is a shortcut for calling L</inc> on fragment C<patch>

=head2 is_alpha

Returns true if L</alpha> has a value set.

=head2 is_qv

Returns true if L</qv> is set to true, false otherwise.

=head2 major

Sets or gets the C<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 C<undef> effectively removes it.

Returns a L<number object|Module::Generic::Number>

=head2 minor

Sets or gets the C<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 C<undef> effectively removes it.

Returns a L<number object|Module::Generic::Number>

lib/Changes/Version.pm  view on Meta::CPAN

        padded => 1,
    );
    say "$v"; # 1.002030
    $v->padded(0);
    say "$v"; # 1.00203

Returns a L<boolean object|Module::Generic::Boolean>

=head2 patch

Sets or gets the C<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 L<number object|Module::Generic::Number>

=head2 pattern

lib/Changes/Version.pm  view on Meta::CPAN

This is on my bucket list of things to improve.

=item * C<cmp>

Same as above.

=item * C<bool>

=item * C<+>, C<->, C<*>, C</>

When performing those operations, it will use the value of the fragment of the version set with L</default_frag>, which, by default, is C<minor>.

It returns a new L<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)

=item * C<+=>, C<-=>, C<*=>, C</=>

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

=item * C<++>, C<-->

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

=back

=head1 PATTERNS

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

=over 4

lib/Changes/Version.pm  view on Meta::CPAN


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

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

=item * C<%a>

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

This will return the C<alpha> fragment value, if any.

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

=item * C<%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 C<minor>, C<patch>, and any extra fragments.

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

=item * C<%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

lib/Changes/Version.pm  view on Meta::CPAN

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

=item * C<%M>

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

This returns the C<minor> part of the version.

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

=item * C<%m>

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

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

=item * C<%N>

lib/Changes/Version.pm  view on Meta::CPAN

=item * C<%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 C<%N>, but will prepend a dot if the value is not null.

=item * C<%P>

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

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

=item * C<%R>

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

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

=item * C<%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 C<minor> and C<patch> value of a dotted-decimal version as numified version using the underscore to separate the C<minor> and the C<patch> fragments.

=item * C<%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 C<%U>, but will prepend a dot if the value is not null.

=back

t/006_version.t  view on Meta::CPAN

can_ok( $v, 'alpha' );
can_ok( $v, 'as_string' );
can_ok( $v, 'beta' );
can_ok( $v, 'compat' );
can_ok( $v, 'dec' );
can_ok( $v, 'dec_alpha' );
can_ok( $v, 'dec_beta' );
can_ok( $v, 'dec_major' );
can_ok( $v, 'dec_minor' );
can_ok( $v, 'dec_patch' );
can_ok( $v, 'default_frag' );
can_ok( $v, 'extra' );
can_ok( $v, 'inc' );
can_ok( $v, 'inc_alpha' );
can_ok( $v, 'inc_beta' );
can_ok( $v, 'inc_major' );
can_ok( $v, 'inc_minor' );
can_ok( $v, 'inc_patch' );
can_ok( $v, 'is_alpha' );
can_ok( $v, 'is_qv' );
can_ok( $v, 'major' );

t/006_version.t  view on Meta::CPAN

    # Those will not work
#     '+=' => { version => $v, operand => 1, expect => [qw( )] },
#     '-=' => { version => $v, operand => 1, expect => [qw( )] },
#     '*=' => { version => $v, operand => 2, expect => [qw( )] },
#     '/=' => { version => $v, operand => 2, expect => [qw( )] },
#     '++' => { version => $v, expect => [qw( )] },
#     '--' => { version => $v, expect => [qw( )] },
    ],
};

my $frag2pos =
{
    major => 0,
    minor => 1,
    patch => 2,
    alpha => 3,
};

# foreach my $type ( qw( dotted decimal ) )
foreach my $type ( sort( keys( %$tests_dict ) ) )
{

t/006_version.t  view on Meta::CPAN

            my $vers;
            if( ref( $def->{version} ) )
            {
                $vers = $def->{version}->clone;
            }
            else
            {
                $vers = Changes::Version->new( $def->{version}, debug => $DEBUG );
            }
            my $orig = $vers->clone;
            foreach my $frag (qw( major minor patch alpha ))
            {
                diag( "Using version '$vers' for test of type '$type' with fragment '$frag' and with operator '$op'" ) if( $DEBUG );
                my $expect = $def->{expect}->[ $frag2pos->{ $frag } ];
                $vers->default_frag( $frag );
                my $eval;
                if( $def->{swapped} )
                {
                    $eval = "$def->{operand} ${op} \$vers";
                }
                else
                {
                    $eval = "\$vers" . ( exists( $def->{operand} ) ? " ${op} $def->{operand}" : $op );
                }
                my $rv = eval( $eval );

t/006_version.t  view on Meta::CPAN

                }
        
                # ++, --
                if( !exists( $def->{operand} ) )
                {
                    is( "$vers" => $expect, "${orig}${op} -> ${expect}" );
                }
                # Others returns a new object
                else
                {
                    is( "$rv" => $expect, ( $def->{swapped} ? "$def->{operand} ${op} ${orig}" : "${orig} ${op} $def->{operand}" ) . " -> ${expect} (using $frag)" );
                }
                $vers = $orig->clone;
            }
        }
    };
}

subtest "satisfy" => sub
{
    ok( Changes::Version->satisfy( '0', '0' ), "'0' satisfies '0'" );



( run in 0.984 second using v1.01-cache-2.11-cpan-364913b4093 )