Changes
view release on metacpan or search on metacpan
lib/Changes/Version.pm view on Meta::CPAN
next if( $vers == version->parse( $1 ) );
return(0);
}
if( /^([=!<>]=|[<>])(\d+([._]\d+)*)$/ )
{
next if( $cmp->{ $1 }->( $vers, version->parse( $2 ) ) );
return(0);
}
if( /^(\d+([._]\d+)*)\.\.(\d+([._]\d+)*)$/ )
{
if( ( version->parse( $1 ) <= $vers ) &&
( $vers <= version->parse( $3 ) ) )
{
next;
}
return(0);
}
return( $self->error( "Bad predicate '$_'" ) );
}
return(1);
}
sub target { return( shift->_set_get_scalar_as_object( 'target', @_ ) ); }
sub type { return( shift->reset(@_)->_set_get_scalar_as_object({
field => 'type',
callbacks =>
{
add => sub
{
my $self = shift( @_ );
if( $self->{type} eq 'decimal' )
{
$self->{qv} = 0;
}
elsif( $self->{type} eq 'dotted' )
{
# By default
$self->{qv} = 1;
}
return( $self->{type} );
}
}
}, @_ ) ); }
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;
}
}
$self->alpha( undef );
}
}
sub _compare
{
my( $left, $right, $swap ) = @_;
my $class = ref( $left );
return(0) if( ${^GLOBAL_PHASE} eq 'DESTRUCT' );
unless( $left->_is_a( $right => $class ) )
{
$right = $class->new( $right, debug => $left->debug );
}
if( $swap )
lib/Changes/Version.pm view on Meta::CPAN
elsif( !$self->_is_a( $val => 'Module::Generic::Number' ) )
{
$val = $self->new_number( "$val" );
if( !defined( $val ) )
{
$err = $self->error->message;
}
}
my $n = $val->scalar;
my $eval;
if( $op eq '++' || $op eq '--' )
{
$eval = "\$n${op}";
}
else
{
$eval = $swap ? ( defined( $other ) ? $other : 'undef' ) . "${op} \$n" : "\$n ${op} " . ( defined( $other ) ? $other : 'undef' );
}
my $rv = eval( $eval );
$err = $@ if( $@ );
if( defined( $err ) )
{
warn( $err, "\n" ) if( $self->_warnings_is_enabled );
# Return unchanged
# return( $swap ? $other : $self );
return;
}
if( $swap )
{
return( ref( $rv ) ? $rv->scalar : $rv );
}
else
{
my $new = $clone;
my $new_val;
if( $op eq '++' || $op eq '--' )
{
$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 );
}
else
{
$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 );
}
sub _stringify
{
my $self = shift( @_ );
my $comp = $self->new_array;
my $def = {};
for( qw( major minor patch alpha ) )
{
$def->{ $_ } = $self->$_;
}
my $type = $self->type;
$def->{major} = 0 if( !defined( $def->{major} ) || !length( $def->{major} ) );
if( $self->qv || ( ( $type // '' ) eq 'dotted' ) )
{
$def->{minor} = 0 if( !defined( $def->{minor} ) || !length( "$def->{minor}" ) );
$def->{patch} = 0 if( !defined( $def->{patch} ) || !length( "$def->{patch}" ) );
}
elsif( ( $type // '' ) eq 'decimal' )
{
# We need to avoid the scenario where we would have a major and alpha, but not minor.
# For example: 3_6 would trigger version error "Invalid version format (alpha without decimal)"
$def->{minor} = 0 if( ( !defined( $def->{minor} ) || !length( "$def->{minor}" ) ) && defined( $def->{alpha} ) && length( "$def->{alpha}" ) );
}
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
{
my $self = shift( @_ );
return(0) if( ${^GLOBAL_PHASE} eq 'DESTRUCT' );
unless( defined( $self ) && ref( $self ) eq 'Changes::Version' )
{
return(0);
}
if( eval{ exists( $self->{_version} ) } &&
Module::Generic->_is_a( $self->{_version} => 'version' ) )
( run in 0.616 second using v1.01-cache-2.11-cpan-df04353d9ac )