# $Id$ class PkgVersion include Comparable attr_accessor :version, :revision, :epoch def initialize(pkgversion) if /[\s-]/ =~ pkgversion raise ArgumentError, "#{pkgversion}: Must not contain a '-' or whitespace." end if /^([^_,]+)(?:_(\d+))?(?:,(\d+))?$/ !~ pkgversion raise ArgumentError, "#{pkgversion}: Not in due form: '[_][,]'." end @version = $1 @revision = $2 ? $2.to_i : 0 @epoch = $3 ? $3.to_i : 0 end def to_s s = @version s += '_' + @revision.to_s if @revision.nonzero? s += ',' + @epoch.to_s if @epoch.nonzero? s end def coerce(other) case other when PkgVersion return other, self when String return PkgVersion.new(other), self else raise TypeError, "Coercion between #{other.class} and #{self.class} is not supported." end end def <=>(other) case other when PkgVersion # ok when String other = PkgVersion.new(other) else a, b = other.coerce(self) return a <=> b end (@epoch <=> other.epoch).nonzero? || PkgVersion.compare_numbers(@version, other.version).nonzero? || @revision <=> other.revision end def PkgVersion::compare_numbers(n1, n2) n1 ||= '' n2 ||= '' # ignore padded 0's n1 = n1.gsub(/(^|\D)0+(\d)/, "\\1\\2") n2 = n2.gsub(/(^|\D)0+(\d)/, "\\1\\2") # Short-cut in case of equality if n1 == n2 return 0 end # Split into subnumbers a1 = n1.split('.') a2 = n2.split('.') s1 = nil s2 = nil begin break if a1.empty? && a2.empty? s1 = a1.shift s2 = a2.shift end while s1 == s2 s1 ||= '' s2 ||= '' # Short-cut in case of equality if s1 == s2 return 0 end # Split into sub-subnumbers a1 = s1.split(/(\D+)/) a2 = s2.split(/(\D+)/) a1.shift if /^\D/ =~ s1 a2.shift if /^\D/ =~ s2 # Sub-subnumbers x1 = a1.shift x2 = a2.shift # Check for alpha, beta, or pre if /^\D/ =~ x1 # x1: non-number if /^\D/ !~ x2 # vs. x2: number or null return -1 # -> x2 wins end if x1 != x2 # vs. x2: non-number return x1 <=> x2 # -> Compare in dictionary order end elsif /^\D/ =~ x2 # x1: number or null vs. x2: non-number return 1 # -> x1 wins end # Seek for the difference while x1 == x2 break if a1.empty? && a2.empty? x1 = a1.shift x2 = a2.shift end x1 ||= '' x2 ||= '' # Short-cut in case of equality if x1 == x2 return 0 end if /^\d/ =~ x1 # x1: number if /^\d/ =~ x2 # vs. x2: number return x1.to_i <=> x2.to_i # -> Compare numerically end # vs. x2: non-number or null return 1 # -> x1 wins end # x1: non-number or null if /^\d/ =~ x2 # vs. x2: number return -1 # -> x2 wins end # vs. x2: non-number or null return x1 <=> x2 # -> Compare in dictionary order end end