Class: SemverDialects::SemanticVersion

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/semver_dialects/semantic_version.rb

Overview

SemanticVersion is a generic version class. It parses and compares versions of any syntax. It can’t always be accurate because a single comparison logic can’t possibly handle all the supported syntaxes. Since it’s generic, it doesn’t validate versions.

Constant Summary collapse

ANY_NUMBER =
'x'
VERSION_PATTERN =

String to build a regexp that matches a version.

A version might start with a leading “v”, then it must have a digit, then it might have any sequence made of alphanumerical characters, underscores, dots, dashes, and wildcards.

'v?[0-9][a-zA-Z0-9_.*+-]*'
VERSION_ONLY_REGEXP =

Regexp for a string that only contains a single version string.

Regexp.new("\\A#{VERSION_PATTERN}\\z").freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version_string) ⇒ SemanticVersion

Returns a new instance of SemanticVersion.



28
29
30
31
32
33
34
35
36
# File 'lib/semver_dialects/semantic_version.rb', line 28

def initialize(version_string)
  raise InvalidVersionError, version_string unless VERSION_ONLY_REGEXP.match version_string

  @version_string = version_string
  @prefix_segments = []
  @suffix_segments = []
  version, = version_string.delete_prefix('v').split('+')
  @segments = split_version_string!(version)
end

Instance Attribute Details

#prefix_segmentsObject (readonly)

Returns the value of attribute prefix_segments.



16
17
18
# File 'lib/semver_dialects/semantic_version.rb', line 16

def prefix_segments
  @prefix_segments
end

#segmentsObject (readonly)

Returns the value of attribute segments.



16
17
18
# File 'lib/semver_dialects/semantic_version.rb', line 16

def segments
  @segments
end

#suffix_segmentsObject (readonly)

Returns the value of attribute suffix_segments.



16
17
18
# File 'lib/semver_dialects/semantic_version.rb', line 16

def suffix_segments
  @suffix_segments
end

#version_stringObject (readonly)

Returns the value of attribute version_string.



16
17
18
# File 'lib/semver_dialects/semantic_version.rb', line 16

def version_string
  @version_string
end

Instance Method Details

#<=>(other) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/semver_dialects/semantic_version.rb', line 111

def <=>(other)
  return nil unless other.is_a?(SemanticVersion)

  self_array, other_array = get_equalized_arrays_for(self, other)
  zipped_arrays = self_array.zip(other_array)
  zipped_arrays.each do |(a, b)|
    return 0 if a.wildcard? || b.wildcard?

    cmp = a <=> b
    return cmp if cmp != 0
  end
  0
end

#_get_equalized_arrays_for(array_a, array_b) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/semver_dialects/semantic_version.rb', line 74

def _get_equalized_arrays_for(array_a, array_b)
  first_array = array_a.clone
  second_array = array_b.clone
  if first_array.size < second_array.size
    (second_array.size - first_array.size).times do
      first_array << SemanticVersionSegment.new('0')
    end
  elsif first_array.size > second_array.size
    (first_array.size - second_array.size).times do
      second_array << SemanticVersionSegment.new('0')
    end
  end
  [first_array, second_array]
end

#get_equalized_arrays_for(semver_a, semver_b) ⇒ Object



89
90
91
92
93
94
95
96
97
# File 'lib/semver_dialects/semantic_version.rb', line 89

def get_equalized_arrays_for(semver_a, semver_b)
  first_array_prefix = semver_a.prefix_segments.clone
  second_array_prefix = semver_b.prefix_segments.clone
  first_array_suffix = semver_a.suffix_segments.clone
  second_array_suffix = semver_b.suffix_segments.clone
  first_array_prefix, second_array_prefix = _get_equalized_arrays_for(first_array_prefix, second_array_prefix)
  first_array_suffix, second_array_suffix = _get_equalized_arrays_for(first_array_suffix, second_array_suffix)
  [first_array_prefix.concat(first_array_suffix), second_array_prefix.concat(second_array_suffix)]
end

#is_zero?Boolean

rubocop:todo Naming/PredicateName

Returns:

  • (Boolean)


99
100
101
# File 'lib/semver_dialects/semantic_version.rb', line 99

def is_zero? # rubocop:todo Naming/PredicateName
  @prefix_segments.empty? || @prefix_segments.all?(&:is_zero?)
end

#majorObject



137
138
139
# File 'lib/semver_dialects/semantic_version.rb', line 137

def major
  @prefix_segments.size >= 2 ? @prefix_segments[0].to_s : '0'
end

#minorObject



133
134
135
# File 'lib/semver_dialects/semantic_version.rb', line 133

def minor
  @prefix_segments.size >= 1 ? @prefix_segments[1].to_s : '0'
end

#patchObject



141
142
143
# File 'lib/semver_dialects/semantic_version.rb', line 141

def patch
  @prefix_segments.size >= 3 ? @prefix_segments[2].to_s : '0'
end

#post_release?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/semver_dialects/semantic_version.rb', line 107

def post_release?
  @suffix_segments.any?(&:is_post_release)
end

#pre_release?Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/semver_dialects/semantic_version.rb', line 103

def pre_release?
  @suffix_segments.any?(&:is_pre_release)
end

#split_version_string!(version_string) ⇒ Object



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
# File 'lib/semver_dialects/semantic_version.rb', line 38

def split_version_string!(version_string)
  delim_pattern = /[.-]/
  split_array = version_string.split(delim_pattern).map do |grp|
    grp.split(/(\d+)/).reject { |cell| cell.nil? || cell.empty? }
  end.flatten

  # go as far to the right as possible considering numbers and placeholders
  prefix_delimiter = 0
  (0..split_array.size - 1).each do |i|
    break unless split_array[i].number? || split_array[i] == 'X' || split_array[i] == 'x'

    prefix_delimiter = i
  end

  # remove redundant trailing zeros
  prefix_delimiter.downto(0).each do |i|
    break unless split_array[i] == '0'

    split_array.delete_at(i)
    prefix_delimiter -= 1
  end

  unless prefix_delimiter.negative?
    @prefix_segments = split_array[0..prefix_delimiter].map do |group_string|
      SemanticVersionSegment.new(group_string)
    end
  end
  if split_array.size - 1 >= prefix_delimiter + 1
    @suffix_segments = split_array[prefix_delimiter + 1, split_array.size].map do |group_string|
      SemanticVersionSegment.new(group_string)
    end
  end

  @prefix_segments.clone.concat(@suffix_segments)
end

#to_normalized_sObject



125
126
127
# File 'lib/semver_dialects/semantic_version.rb', line 125

def to_normalized_s
  @segments.map(&:to_normalized_s).join(':')
end

#to_sObject



129
130
131
# File 'lib/semver_dialects/semantic_version.rb', line 129

def to_s
  @version_string
end