class SemanticPuppet::Version

@note SemanticPuppet::Version subclasses Numeric so that it has sane Range

semantics in Ruby 1.9+.

Constants

MAX

The highest precedence Version possible

MIN

The lowest precedence Version possible

REGEX_BUILD
REGEX_FULL
REGEX_FULL_RX
REGEX_NUMERIC

Version string matching regexes

REGEX_PRE

Attributes

major[R]
minor[R]
patch[R]

Public Class Methods

new(major, minor, patch, prerelease = nil, build = nil) click to toggle source
# File 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
parse(ver) click to toggle source

Parse a Semantic Version string.

@param ver [String] the version string to parse @return [Version] a comparable {Version} object

# File 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 '#{ver}' as a semantic version identifier" unless match

  new(major.to_i, minor.to_i, patch.to_i, parse_prerelease(prerelease), parse_build(build)).freeze
end
parse_build(build) click to toggle source
# File lib/semantic_puppet/version.rb, line 37
def self.parse_build(build)
  build.nil? ? nil : build.split('.').freeze
end
parse_prerelease(prerelease) click to toggle source
# File 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) click to toggle source

Validate a Semantic Version string.

@param ver [String] the version string to validate @return [bool] whether or not the string represents a valid Semantic Version

# File 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

Public Instance Methods

<=>(other) click to toggle source
# File 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
==(other)
Alias for: eql?
build() click to toggle source

@return [String] the `build` identifier as a string without the leading '+'

# File lib/semantic_puppet/version.rb, line 90
def build
  (@build.nil? || @build.empty?) ? nil : @build.join('.')
end
compare_prerelease(other) click to toggle source
# File 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) click to toggle source
# File 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
Also aliased as: ==
hash() click to toggle source
# File lib/semantic_puppet/version.rb, line 146
def hash
  (((((@major * 0x100) ^ @minor) * 0x100) ^ @patch) * 0x100) ^ @prerelease.hash
end
inspect()
Alias for: to_s
next(part) click to toggle source
# File 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
prerelease() click to toggle source

@return [String] the `prerelease` identifier as a string without the leading '-'

# File lib/semantic_puppet/version.rb, line 75
def prerelease
  (@prerelease.nil? || @prerelease.empty?) ? nil : @prerelease.join('.')
end
stable?() click to toggle source

@return [Boolean] true if this is a stable release

# File lib/semantic_puppet/version.rb, line 80
def stable?
  @prerelease.nil? || @prerelease.empty?
end
to_s() click to toggle source
# File 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
Also aliased as: inspect
to_stable() click to toggle source

@return [Version] this version stripped from any prerelease identifier.

# File lib/semantic_puppet/version.rb, line 85
def to_stable
  @prerelease.nil? ? self : Version.new(@major, @minor, @patch, nil, @build)
end