1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
# frozen_string_literal: true
# Class that describes a version that can be compared to another version in a generic way.
#
# A version is made of +tokens+ and an optional +addition+.
# Tokens and additions must be comparable using the spaceship operator.
# An addition behaves like a version and must respond to +tokens+.
#
# Tokens are used to represent the dot separated list of segments
# like 1.2.3 (semantic version) or alpha.1 (pre-release tag).
#
# Version 1.2.3-alpha.1-2024.03.25 is made of 3 +Version+ objects
# whose tokens are represented as 1.2.3, alpha.1, 2024.03.25.
# Version alpha.1 is the addition of version 1.2.3,
# and version 2024.03.25 is the addition of version alpha.1.
#
# This class can support of the comparison logic of many syntaxes
# by implementing specific token classes.
#
module SemverDialects
class BaseVersion
include Comparable
attr_reader :tokens, :addition
def initialize(tokens, addition: nil)
@tokens = tokens
@addition = addition
end
def to_s
main = tokens.join('.')
main += "-#{addition}" if addition
main
end
def <=>(other)
cmp = compare_tokens(tokens, other.tokens)
return cmp unless cmp == 0
compare_additions(addition, other.addition)
end
# Returns true if the version tokens are equivalent to zero
# and the addition is also equivalent to zero.
def is_zero?
return false if compare_tokens(tokens, [0]) != 0
return true if addition.nil?
addition.is_zero?
end
private
def compare_tokens(a, b) # rubocop:disable Naming/MethodParameterName
max_idx = [a.size, b.size].max - 1
(0..max_idx).each do |idx|
cmp = compare_token_pair(a[idx], b[idx])
return cmp unless cmp == 0
end
0
end
def compare_token_pair(a, b) # rubocop:disable Naming/MethodParameterName
(a || 0) <=> (b || 0)
end
def compare_additions(a, b) # rubocop:disable Naming/MethodParameterName
return 0 if a.nil? && b.nil?
(a || empty_addition).<=>(b || empty_addition)
end
def empty_addition
self.class.new([])
end
end
end
|