Class: SemanticPuppet::Version

Inherits:
Numeric
  • Object
show all
Includes:
Comparable
Defined in:
lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb

Overview

Note:

SemanticPuppet::Version subclasses Numeric so that it has sane Range semantics in Ruby 1.9+.

Defined Under Namespace

Classes: ValidationFailure

Constant Summary collapse

REGEX_NUMERIC =

Version string matching regexes

'(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)'.freeze
REGEX_PRE =

Major . Minor . Patch

'(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?'.freeze
REGEX_BUILD =

Prerelease

'(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?'.freeze
REGEX_FULL =

Build

REGEX_NUMERIC + REGEX_PRE + REGEX_BUILD.freeze
REGEX_FULL_RX =
/\A#{REGEX_FULL}\Z/.freeze
MIN =

The lowest precedence Version possible

self.new(0, 0, 0, [].freeze).freeze
MAX =

The highest precedence Version possible

self.new(Float::INFINITY, 0, 0).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(major, minor, patch, prerelease = nil, build = nil) ⇒ Version

Returns a new instance of Version.



55
56
57
58
59
60
61
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 55

def initialize(major, minor, patch, prerelease = nil, build = nil)
  @major      = major
  @minor      = minor
  @patch      = patch
  @prerelease = prerelease
  @build      = build
end

Instance Attribute Details

#majorObject (readonly)

Returns the value of attribute major.



53
54
55
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 53

def major
  @major
end

#minorObject (readonly)

Returns the value of attribute minor.



53
54
55
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 53

def minor
  @minor
end

#patchObject (readonly)

Returns the value of attribute patch.



53
54
55
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 53

def patch
  @patch
end

Class Method Details

.parse(ver) ⇒ Version

Parse a Semantic Version string.

Parameters:

  • ver (String)

    the version string to parse

Returns:

Raises:



15
16
17
18
19
20
21
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 15

def self.parse(ver)
  match, major, minor, patch, prerelease, build = *ver.match(REGEX_FULL_RX)

  raise ValidationFailure, _("Unable to parse '%{version}' as a semantic version identifier") % {version: ver} unless match

  new(major.to_i, minor.to_i, patch.to_i, parse_prerelease(prerelease), parse_build(build)).freeze
end

.parse_build(build) ⇒ Object



37
38
39
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 37

def self.parse_build(build)
  build.nil? ? nil : build.split('.').freeze
end

.parse_prerelease(prerelease) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 41

def self.parse_prerelease(prerelease)
  return nil unless prerelease
  prerelease.split('.').map do |x|
    if x =~ /^\d+$/
      raise ValidationFailure, _('Numeric pre-release identifiers MUST NOT contain leading zeroes') if x.length > 1 && x.start_with?('0')
      x.to_i
    else
      x
    end
  end.freeze
end

.valid?(ver) ⇒ bool

Validate a Semantic Version string.

Parameters:

  • ver (String)

    the version string to validate

Returns:

  • (bool)

    whether or not the string represents a valid Semantic Version



27
28
29
30
31
32
33
34
35
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 27

def self.valid?(ver)
  match = ver.match(REGEX_FULL_RX)
  if match.nil?
    false
  else
    prerelease = match[4]
    prerelease.nil? || prerelease.split('.').all? { |x| !(x =~ /^0\d+$/) }
  end
end

Instance Method Details

#<=>(other) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 94

def <=>(other)
  return nil unless other.is_a?(Version)
  cmp = @major <=> other.major
  if cmp == 0
    cmp = @minor <=> other.minor
    if cmp == 0
      cmp = @patch <=> other.patch
      if cmp == 0
        cmp = compare_prerelease(other)
      end
    end
  end
  cmp
end

#buildString

Returns the ‘build` identifier as a string without the leading ’+‘.

Returns:

  • (String)

    the ‘build` identifier as a string without the leading ’+‘



90
91
92
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 90

def build
  (@build.nil? || @build.empty?) ? nil : @build.join('.')
end

#compare_prerelease(other) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 150

def compare_prerelease(other)
  mine = @prerelease

  # Need to use the instance variable here to avoid getting a string
  yours = other.instance_variable_get(:@prerelease)

  # A version that has a prerelease is always less than a version that doesn't
  if mine.nil?
    yours.nil? ? 0 : 1
  elsif yours.nil?
    -1
  else
    # Compare all prerelease identifier segments that can be compared. Should
    # all segments compare equal up to the point where one of the prereleases
    # have no more segments, then the one with more segements is greater.
    your_max = yours.size
    mine.each_with_index do |x, idx|
      # 'mine' win if 'your' list of segments is exhausted
      return 1 if idx >= your_max
      y = yours[idx]

      # Integer always wins over String
      cmp = if x.is_a?(Integer)
        y.is_a?(Integer) ? x <=> y : -1
      elsif y.is_a?(Integer)
        1
      else
        x <=> y
      end

      # No need to continue if a diff is found
      return cmp unless cmp == 0
    end

    # All segments, up to the point where at least one list of segement is exhausted,
    # compared equal. The one with the highest segment count wins.
    mine.size <=> your_max
  end
end

#eql?(other) ⇒ Boolean Also known as: ==

Returns:

  • (Boolean)


109
110
111
112
113
114
115
116
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 109

def eql?(other)
  other.is_a?(Version) &&
    @major.eql?(other.major) &&
    @minor.eql?(other.minor) &&
    @patch.eql?(other.patch) &&
    @prerelease.eql?(other.instance_variable_get(:@prerelease)) &&
    @build.eql?(other.instance_variable_get(:@build))
end

#hashObject



146
147
148
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 146

def hash
  (((((@major * 0x100) ^ @minor) * 0x100) ^ @patch) * 0x100) ^ @prerelease.hash
end

#next(part) ⇒ Object



63
64
65
66
67
68
69
70
71
72
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 63

def next(part)
  case part
  when :major
    self.class.new(@major.next, 0, 0)
  when :minor
    self.class.new(@major, @minor.next, 0)
  when :patch
    self.class.new(@major, @minor, @patch.next)
  end
end

#prereleaseString

Returns the ‘prerelease` identifier as a string without the leading ’-‘.

Returns:

  • (String)

    the ‘prerelease` identifier as a string without the leading ’-‘



75
76
77
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 75

def prerelease
  (@prerelease.nil? || @prerelease.empty?) ? nil : @prerelease.join('.')
end

#stable?Boolean

Returns true if this is a stable release.

Returns:

  • (Boolean)

    true if this is a stable release



80
81
82
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 80

def stable?
  @prerelease.nil? || @prerelease.empty?
end

#to_sObject Also known as: inspect



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 119

def to_s
  s = "#{@major}.#{@minor}.#{@patch}"

  # Appending the @prerelease and @build in a thoroughly tested and optimized
  # way. Using interpolations and/or array joins may look simpler but will slows
  # things down. Don't change this code without measuring performance of new
  # solution.
  unless @prerelease.nil?
    s << '-' << @prerelease[0].to_s
    i = 0
    l = @prerelease.length
    while (i += 1) < l
      s << '.' << @prerelease[i].to_s
    end
  end
  unless @build.nil?
    s << '+' << @build[0].to_s
    i = 0
    l = @build.length
    while (i += 1) < l
      s << '.' << @build[i].to_s
    end
  end
  s
end

#to_stableVersion

Returns this version stripped from any prerelease identifier.

Returns:

  • (Version)

    this version stripped from any prerelease identifier.



85
86
87
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb', line 85

def to_stable
  @prerelease.nil? ? self : Version.new(@major, @minor, @patch, nil, @build)
end