Class: Ukiryu::Models::SemanticVersion

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

Overview

Semantic version value object for proper version comparison.

Handles version strings like “10.0”, “9.5.1”, “1.2.3” and provides proper semantic comparison (10.0 > 9.5, not alphabetical).

This class ensures that version selection uses actual semantic meaning rather than string comparison, which would incorrectly sort “9.5” > “10.0”.

Examples:

v1 = Ukiryu::Models::SemanticVersion.new("10.0")
v2 = Ukiryu::Models::SemanticVersion.new("9.5")
v1 > v2  # => true (correct)
"10.0" > "9.5"  # => false (wrong - alphabetical)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version_string) ⇒ SemanticVersion

Create a new SemanticVersion from a version string

Parameters:



63
64
65
66
# File 'lib/ukiryu/models/semantic_version.rb', line 63

def initialize(version_string)
  @original = version_string.respond_to?(:to_s) ? version_string.to_s : nil
  @segments = self.class.parse(@original)
end

Instance Attribute Details

#originalString? (readonly)

Returns the original version string.

Returns:

  • (String, nil)

    the original version string



58
59
60
# File 'lib/ukiryu/models/semantic_version.rb', line 58

def original
  @original
end

#segmentsArray<Integer> (readonly)

Returns the numeric segments of this version.

Returns:

  • (Array<Integer>)

    the numeric segments of this version



55
56
57
# File 'lib/ukiryu/models/semantic_version.rb', line 55

def segments
  @segments
end

Class Method Details

.compare(version_a, version_b) ⇒ Integer

Compare two version strings directly

Parameters:

  • version_a (String)

    first version string

  • version_b (String)

    second version string

Returns:

  • (Integer)

    -1, 0, or 1



43
44
45
46
47
48
49
50
51
52
# File 'lib/ukiryu/models/semantic_version.rb', line 43

def self.compare(version_a, version_b)
  segments1 = parse(version_a)
  segments2 = parse(version_b)

  max_length = [segments1.length, segments2.length].max
  padded1 = segments1 + [0] * (max_length - segments1.length)
  padded2 = segments2 + [0] * (max_length - segments2.length)

  padded1 <=> padded2
end

.parse(version_string) ⇒ Array<Integer>

Parse a version string into segments

Parameters:

  • version_string (String, nil)

    the version string to parse

Returns:

  • (Array<Integer>)

    array of numeric segments



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/ukiryu/models/semantic_version.rb', line 26

def self.parse(version_string)
  return [0] if version_string.nil? || version_string.to_s.empty?

  version_string.to_s
                .split('.')
                .map do |part|
                  part.to_i
  rescue StandardError
    0
  end
end

Instance Method Details

#<(other) ⇒ Boolean

Check if this version is less than another

Parameters:

Returns:

  • (Boolean)


120
121
122
# File 'lib/ukiryu/models/semantic_version.rb', line 120

def <(other)
  (self <=> other) == -1
end

#<=(other) ⇒ Boolean

Check if this version is less than or equal to another

Parameters:

Returns:

  • (Boolean)


137
138
139
140
# File 'lib/ukiryu/models/semantic_version.rb', line 137

def <=(other)
  result = self <=> other
  [-1, 0].include?(result)
end

#<=>(other) ⇒ Integer?

Compare this version with another

Parameters:

Returns:

  • (Integer, nil)

    -1, 0, 1, or nil if not comparable



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/ukiryu/models/semantic_version.rb', line 72

def <=>(other)
  return nil unless other

  other_segments = case other
                   when SemanticVersion
                     other.segments
                   when String, Integer
                     self.class.parse(other)
                   else
                     return nil
                   end

  # Compare segment by segment
  # [10, 0] <=> [9, 5] should return 1 (10.0 > 9.5)
  max_length = [segments.length, other_segments.length].max

  max_length.times do |i|
    a = segments[i] || 0
    b = other_segments[i] || 0

    return a <=> b unless a == b
  end

  0 # All segments equal
end

#==(other) ⇒ Boolean

Check equality with another version

Parameters:

  • other (Object)

    the other object

Returns:

  • (Boolean)


102
103
104
105
106
# File 'lib/ukiryu/models/semantic_version.rb', line 102

def ==(other)
  return false unless other

  (self <=> other).zero?
end

#>(other) ⇒ Boolean

Check if this version is greater than another

Parameters:

Returns:

  • (Boolean)


112
113
114
# File 'lib/ukiryu/models/semantic_version.rb', line 112

def >(other)
  (self <=> other) == 1
end

#>=(other) ⇒ Boolean

Check if this version is greater than or equal to another

Parameters:

Returns:

  • (Boolean)


128
129
130
131
# File 'lib/ukiryu/models/semantic_version.rb', line 128

def >=(other)
  result = self <=> other
  [1, 0].include?(result)
end

#eql?(other) ⇒ Boolean

Equality for hash key usage

Parameters:

  • other (Object)

Returns:

  • (Boolean)


167
168
169
170
171
# File 'lib/ukiryu/models/semantic_version.rb', line 167

def eql?(other)
  return false unless other.is_a?(SemanticVersion)

  segments == other.segments
end

#hashInteger

Hash for use as hash key

Returns:

  • (Integer)


159
160
161
# File 'lib/ukiryu/models/semantic_version.rb', line 159

def hash
  segments.hash
end

#inspectString

Return a human-readable representation

Returns:

  • (String)


152
153
154
# File 'lib/ukiryu/models/semantic_version.rb', line 152

def inspect
  "#<Ukiryu::Models::SemanticVersion #{self}>"
end

#to_sString

Return the version as a string

Returns:

  • (String)

    the version string



145
146
147
# File 'lib/ukiryu/models/semantic_version.rb', line 145

def to_s
  segments.join('.')
end