aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
authorJack Nagel2012-08-18 13:34:31 -0500
committerJack Nagel2012-08-18 15:53:04 -0500
commit6ccf2aa253bfad33d527e80f36832fab96601ff2 (patch)
tree438ec938bbcfd741d1a81ea6d093a9077e5cd737 /Library
parent41994f942380fa7eaad92b24b8e0e38be021f916 (diff)
downloadhomebrew-6ccf2aa253bfad33d527e80f36832fab96601ff2.tar.bz2
Version: build-in devel version comparisons
The heuristic used by the default version comparison is simple. A version string is scanned for strings of digits, split into an array of these strings, and then an element-wise comparison is done. This fails when presented with something like Version.new("1.0.0beta7") <=> Version.new("1.0.0") because the first three digits match, and the fourth digit of the receiver (7) is greater than the assumed fourth digit of the parameter (0). Fix this by defining an element-wise comparator on a new VersionElement class. This allows us to correctly compare "alpha", "beta", and "rc" style version strings, and keeps the logic out of the main version comparison. Signed-off-by: Jack Nagel <jacknagel@gmail.com>
Diffstat (limited to 'Library')
-rw-r--r--Library/Homebrew/test/test_versions.rb6
-rw-r--r--Library/Homebrew/version.rb78
2 files changed, 71 insertions, 13 deletions
diff --git a/Library/Homebrew/test/test_versions.rb b/Library/Homebrew/test/test_versions.rb
index 972ce130b..9811db57e 100644
--- a/Library/Homebrew/test/test_versions.rb
+++ b/Library/Homebrew/test/test_versions.rb
@@ -23,6 +23,12 @@ class VersionComparisonTests < Test::Unit::TestCase
assert_version_comparison 'HEAD', '==', 'HEAD'
assert_version_comparison 'HEAD', '>', '1.2.3'
assert_version_comparison '1.2.3', '<', 'HEAD'
+ assert_version_comparison '3.2.0b4', '<', '3.2.0'
+ assert_version_comparison '1.0beta6', '<', '1.0b7'
+ assert_version_comparison '1.0b6', '<', '1.0beta7'
+ assert_version_comparison '1.1alpha4', '<', '1.1beta2'
+ assert_version_comparison '1.1beta2', '<', '1.1rc1'
+ assert_nil Version.new('1.0') <=> 'foo'
end
def test_macos_version_comparison
diff --git a/Library/Homebrew/version.rb b/Library/Homebrew/version.rb
index 30e41392a..01053012f 100644
--- a/Library/Homebrew/version.rb
+++ b/Library/Homebrew/version.rb
@@ -1,3 +1,38 @@
+class VersionElement
+ include Comparable
+
+ attr_reader :elem
+
+ def initialize elem
+ elem = elem.to_s.downcase
+ @elem = case elem
+ when 'a', 'alpha' then 'alpha'
+ when 'b', 'beta' then 'beta'
+ when /\d+/ then elem.to_i
+ else elem
+ end
+ end
+
+ def <=>(other)
+ return unless other.is_a? VersionElement
+ return -1 if string? and other.numeric?
+ return 1 if numeric? and other.string?
+ return elem <=> other.elem
+ end
+
+ def to_s
+ @elem.to_s
+ end
+
+ def string?
+ @elem.is_a? String
+ end
+
+ def numeric?
+ @elem.is_a? Numeric
+ end
+end
+
class Version
include Comparable
@@ -11,30 +46,47 @@ class Version
@detected_from_url
end
+ def to_a
+ @array ||= @version.scan(/\d+|[a-zA-Z]+/).map { |e| VersionElement.new(e) }
+ end
+
def head?
@version == 'HEAD'
end
- def nums
- @version.scan(/\d+/).map { |d| d.to_i }
+ def devel?
+ alpha? or beta? or rc?
+ end
+
+ def alpha?
+ to_a.any? { |e| e.to_s == 'alpha' }
+ end
+
+ def beta?
+ to_a.any? { |e| e.to_s == 'beta' }
+ end
+
+ def rc?
+ to_a.any? { |e| e.to_s == 'rc' }
end
def <=>(other)
- return nil unless other.is_a? Version
- return 0 if self.head? and other.head?
- return 1 if self.head? and not other.head?
- return -1 if not self.head? and other.head?
- return 1 if other.nil?
+ # Return nil if objects aren't comparable
+ return unless other.is_a? Version
+ # Versions are equal if both are HEAD
+ return 0 if head? and other.head?
+ # HEAD is greater than any numerical version
+ return 1 if head? and not other.head?
+ return -1 if not head? and other.head?
- snums = self.nums
- onums = other.nums
+ stuple, otuple = to_a, other.to_a
- count = [snums.length, onums.length].max
+ max = [stuple.length, otuple.length].max
- snums.fill(0, snums.length, count - snums.length)
- onums.fill(0, onums.length, count - onums.length)
+ stuple.fill(VersionElement.new(0), stuple.length, max - stuple.length)
+ otuple.fill(VersionElement.new(0), otuple.length, max - otuple.length)
- snums <=> onums
+ stuple <=> otuple
end
def to_s