lib/semantic/version.rb in semantic-1.4.1 vs lib/semantic/version.rb in semantic-1.5.0

- old
+ new

@@ -1,40 +1,64 @@ # See: http://semver.org module Semantic class Version - SemVerRegexp = /\A(\d+\.\d+\.\d+)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?\Z/ + SemVerRegexp = /\A(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?\Z/ + + attr_accessor :major, :minor, :patch, :pre, :build def initialize version_str - raise ArgumentError.new("#{version_str} is not a valid SemVer Version (http://semver.org)") unless version_str =~ SemVerRegexp + v = version_str.match(SemVerRegexp) - version, parts = version_str.split '-' - if not parts.nil? and parts.include? '+' - @pre, @build = parts.split '+' - elsif version.include? '+' - version, @build = version.split '+' - else - @pre = parts - end - - - @major, @minor, @patch = version.split('.').map(&:to_i) + raise ArgumentError.new("#{version_str} is not a valid SemVer Version (http://semver.org)") if v.nil? + @major = v[1].to_i + @minor = v[2].to_i + @patch = v[3].to_i + @pre = v[4] + @build = v[5] + @version = version_str end + def build=(b) @build = (!b.nil? && b.empty?) ? nil : b end + def identifiers(pre) + array = pre.split(".") + array.each_with_index {|e,i| array[i] = Integer(e) if /\A\d+\z/.match(e)} + return array + end + + def compare_pre(prea, preb) + if prea.nil? || preb.nil? + return 0 if prea.nil? && preb.nil? + return 1 if prea.nil? + return -1 if preb.nil? + end + a = identifiers(prea) + b = identifiers(preb) + smallest = a.size < b.size ? a : b + smallest.each_with_index do |e, i| + c = a[i] <=> b[i] + if c.nil? + return a[i].is_a?(Integer) ? -1 : 1 + elsif c != 0 + return c + end + end + return a.size <=> b.size + end + def to_a [@major, @minor, @patch, @pre, @build] end def to_s str = [@major, @minor, @patch].join '.' str << '-' << @pre unless @pre.nil? str << '+' << @build unless @build.nil? - str end def to_h keys = [:major, :minor, :patch, :pre, :build] @@ -43,23 +67,27 @@ alias to_hash to_h alias to_array to_a alias to_string to_s - def <=> other_version - other_version = Version.new(other_version) if other_version.is_a? String + def hash + to_a.hash + end - v1 = self.dup - v2 = other_version.dup + def eql? other_version + self.hash == other_version.hash + end - # The build must be excluded from the comparison, so that e.g. 1.2.3+foo and 1.2.3+bar are semantically equal. - # "Build metadata SHOULD be ignored when determining version precedence". - # (SemVer 2.0.0-rc.2, paragraph 10 - http://www.semver.org) - v1.build = nil - v2.build = nil - - compare_recursively(v1.to_a, v2.to_a) + def <=> other_version + other_version = Version.new(other_version) if other_version.is_a? String + [:major, :minor, :patch].each do |part| + c = (self.send(part) <=> other_version.send(part)) + if c != 0 + return c + end + end + return compare_pre(self.pre, other_version.pre) end def > other_version (self <=> other_version) == 1 end @@ -101,10 +129,11 @@ [:major, :minor, :patch].each do |term| define_method("#{term}!") { increment!(term) } end def increment!(term) + term = term.to_sym new_version = clone new_value = send(term) + 1 new_version.send("#{term}=", new_value) new_version.minor = 0 if term == :major @@ -136,32 +165,7 @@ else self.send comparator, other_version_string end end - def compare_recursively ary1, ary2 - # Short-circuit the recursion entirely if they're just equal - return 0 if ary1 == ary2 - - a = ary1.shift; b = ary2.shift - - # Reached the end of the arrays, equal all the way down - return 0 if a.nil? and b.nil? - - # Mismatched types (ie. one has a pre and the other doesn't) - if a.nil? and not b.nil? - return 1 - elsif not a.nil? and b.nil? - return -1 - end - - if a < b - return -1 - elsif a > b - return 1 - end - - # Versions are equal thus far, so recurse down to the next part. - compare_recursively ary1, ary2 - end end end