class XSemVer::SemVer

‘SemVer’ in global scope. Too Bad®. Use this symbol instead.
sometimes a library that you are using has already put the class

def self.parse(version_string, format = nil, allow_missing = true)

Parses a semver from a string and format.
def self.parse(version_string, format = nil, allow_missing = true)
  format ||= TAG_FORMAT
  regex_str = Regexp.escape format
  # Convert all the format characters to named capture groups
  regex_str = regex_str.gsub('%M', '(?<major>\d+)').
    gsub('%m', '(?<minor>\d+)').
    gsub('%p', '(?<patch>\d+)').
    gsub('%s', '(?:-(?<special>[A-Za-z][0-9A-Za-z\.]+))?')
  regex = Regexp.new(regex_str)
  match = regex.match version_string
  if match
      major = minor = patch = nil
      special = ''
      # Extract out the version parts
      major = match[:major].to_i if match.names.include? 'major'
      minor = match[:minor].to_i if match.names.include? 'minor'
      patch = match[:patch].to_i if match.names.include? 'patch'
      special = match[:special] || '' if match.names.include? 'special'
      # Failed parse if major, minor, or patch wasn't found
      # and allow_missing is false
      return nil if !allow_missing and [major, minor, patch].any? {|x| x.nil? }
      # Otherwise, allow them to default to zero
      major ||= 0
      minor ||= 0
      patch ||= 0
      SemVer.new major, minor, patch, special
  end
end

def <=> other

def <=> other
  maj = major.to_i <=> other.major.to_i
  return maj unless maj == 0
  min = minor.to_i <=> other.minor.to_i
  return min unless min == 0
  pat = patch.to_i <=> other.patch.to_i
  return pat unless pat == 0
  spe = special <=> other.special
  return spec unless spe == 0
  0
end

def format fmt

def format fmt
  fmt = fmt.gsub '%M', @major.to_s
  fmt = fmt.gsub '%m', @minor.to_s
  fmt = fmt.gsub '%p', @patch.to_s
  if @special.nil? or @special.length == 0 then
    fmt = fmt.gsub '%s', ''
  else
    fmt = fmt.gsub '%s', "-" + @special.to_s
  end
  fmt
end

def initialize major=0, minor=0, patch=0, special=''

def initialize major=0, minor=0, patch=0, special=''
  major.kind_of? Integer or raise "invalid major: #{major}"
  minor.kind_of? Integer or raise "invalid minor: #{minor}"
  patch.kind_of? Integer or raise "invalid patch: #{patch}"
  unless special.empty?
    special =~ /[A-Za-z][0-9A-Za-z\.]+/ or raise "invalid special: #{special}"
  end
  @major, @minor, @patch, @special = major, minor, patch, special
end

def load file

def load file
  @file = file
  hash = YAML.load_file(file) || {}
  @major = hash[:major] or raise "invalid semver file: #{file}"
  @minor = hash[:minor] or raise "invalid semver file: #{file}"
  @patch = hash[:patch] or raise "invalid semver file: #{file}"
  @special = hash[:special]  or raise "invalid semver file: #{file}"
end

def save file=nil

def save file=nil
  file ||= @file
  hash = {
    :major => @major,
    :minor => @minor,
    :patch => @patch,
    :special => @special
  }
  yaml = YAML.dump hash
  open(file, 'w') { |io| io.write yaml }
end

def to_s

def to_s
  format TAG_FORMAT
end