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
WILDCARD_HIT =
:__wildcard_hit__

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



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

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

  cmp = compare_segments(@prefix_segments, other.prefix_segments)
  return 0 if cmp.equal?(WILDCARD_HIT)
  return cmp unless cmp.zero?

  cmp = compare_segments(@suffix_segments, other.suffix_segments)
  return 0 if cmp.equal?(WILDCARD_HIT)

  cmp
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



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

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

#minorObject



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

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

#patchObject



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

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



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

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

#to_sObject



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

def to_s
  @version_string
end