diff --git a/Library/Homebrew/test/version_spec.rb b/Library/Homebrew/test/version_spec.rb index 03b9ab7e88..4154cf125f 100644 --- a/Library/Homebrew/test/version_spec.rb +++ b/Library/Homebrew/test/version_spec.rb @@ -16,6 +16,28 @@ describe Version::Token do specify "#to_s" do expect(described_class.new("foo").to_s).to eq("foo") end + + it "can be compared against nil" do + expect(described_class.create("2")).to be > nil + expect(described_class.create("p194")).to be > nil + end + + it "can be compared against Version::NULL_TOKEN" do + expect(described_class.create("2")).to be > Version::NULL_TOKEN + expect(described_class.create("p194")).to be > Version::NULL_TOKEN + end + + it "can be compared against strings" do + expect(described_class.create("2")).to be == "2" + expect(described_class.create("p194")).to be == "p194" + expect(described_class.create("1")).to be == 1 + end + + specify "comparison returns nil for non-token" do + v = described_class.create("1") + expect(v <=> Object.new).to be nil + expect { v > Object.new }.to raise_error(ArgumentError) + end end describe Version::NULL do diff --git a/Library/Homebrew/version.rb b/Library/Homebrew/version.rb index 3a385f0868..4232513165 100644 --- a/Library/Homebrew/version.rb +++ b/Library/Homebrew/version.rb @@ -12,6 +12,30 @@ class Version class Token include Comparable + def self.create(val) + raise TypeError, "Token value must be a string; got a #{val.class} (#{val})" unless val.respond_to?(:to_str) + + case val + when /\A#{AlphaToken::PATTERN}\z/o then AlphaToken + when /\A#{BetaToken::PATTERN}\z/o then BetaToken + when /\A#{RCToken::PATTERN}\z/o then RCToken + when /\A#{PreToken::PATTERN}\z/o then PreToken + when /\A#{PatchToken::PATTERN}\z/o then PatchToken + when /\A#{NumericToken::PATTERN}\z/o then NumericToken + when /\A#{StringToken::PATTERN}\z/o then StringToken + end.new(val) + end + + def self.from(val) + case val + when Token then val + when String then Token.create(val) + when Integer then Token.create(val.to_s) + when nil then NULL_TOKEN + else NULL_TOKEN if val.respond_to?(:null?) && val.null? + end + end + attr_reader :value def initialize(value) @@ -37,6 +61,8 @@ class Version end def <=>(other) + return unless other = Token.from(other) + case other when NullToken 0 @@ -64,6 +90,8 @@ class Version end def <=>(other) + return unless other = Token.from(other) + case other when StringToken value <=> other.value @@ -81,6 +109,8 @@ class Version end def <=>(other) + return unless other = Token.from(other) + case other when NumericToken value <=> other.value @@ -106,6 +136,8 @@ class Version PATTERN = /alpha[0-9]*|a[0-9]+/i.freeze def <=>(other) + return unless other = Token.from(other) + case other when AlphaToken rev <=> other.rev @@ -121,6 +153,8 @@ class Version PATTERN = /beta[0-9]*|b[0-9]+/i.freeze def <=>(other) + return unless other = Token.from(other) + case other when BetaToken rev <=> other.rev @@ -138,6 +172,8 @@ class Version PATTERN = /pre[0-9]*/i.freeze def <=>(other) + return unless other = Token.from(other) + case other when PreToken rev <=> other.rev @@ -155,6 +191,8 @@ class Version PATTERN = /rc[0-9]*/i.freeze def <=>(other) + return unless other = Token.from(other) + case other when RCToken rev <=> other.rev @@ -172,6 +210,8 @@ class Version PATTERN = /p[0-9]*/i.freeze def <=>(other) + return unless other = Token.from(other) + case other when PatchToken rev <=> other.rev @@ -465,17 +505,7 @@ class Version end def tokenize - version.scan(SCAN_PATTERN).map! do |token| - case token - when /\A#{AlphaToken::PATTERN}\z/o then AlphaToken - when /\A#{BetaToken::PATTERN}\z/o then BetaToken - when /\A#{RCToken::PATTERN}\z/o then RCToken - when /\A#{PreToken::PATTERN}\z/o then PreToken - when /\A#{PatchToken::PATTERN}\z/o then PatchToken - when /\A#{NumericToken::PATTERN}\z/o then NumericToken - when /\A#{StringToken::PATTERN}\z/o then StringToken - end.new(token) - end + version.scan(SCAN_PATTERN).map { |token| Token.create(token) } end end