Refactor and document Version.

This commit is contained in:
Markus Reiter 2020-08-09 02:59:18 +02:00
parent b14bc2857b
commit c53f362476
7 changed files with 59 additions and 38 deletions

View File

@ -1019,7 +1019,7 @@ module Homebrew
problem "missing version"
elsif !version.detected_from_url?
version_text = version
version_url = Version.detect(url, specs)
version_url = Version.detect(url, **specs)
if version_url.to_s == version_text.to_s && version.instance_of?(Version)
problem "version #{version_text} is redundant with version scanned from URL"
end

View File

@ -468,7 +468,7 @@ module Homebrew
unless version
specs = {}
specs[:tag] = tag if tag
version = Version.detect(url, specs)
version = Version.detect(url, **specs)
end
# if we haven't already found open requests, try for an exact match across closed requests
GitHub.check_for_duplicate_pull_requests("#{formula.name} #{version}", tap_full_name, state: "closed", args: args)

View File

@ -34,7 +34,7 @@ module Homebrew
@version = if @version
Version.create(@version)
else
Version.detect(url, {})
Version.detect(url)
end
end

View File

@ -203,7 +203,7 @@ class Resource
return Version::NULL if val.nil? && url.nil?
case val
when nil then Version.detect(url, specs)
when nil then Version.detect(url, **specs)
when String then Version.create(val)
when Version then val
else

View File

@ -63,17 +63,19 @@ describe Version::NULL do
end
end
describe Version::NullToken do
describe Version do
describe "::NULL_TOKEN" do
subject { described_class::NULL_TOKEN }
specify "#inspect" do
expect(subject.inspect).to eq("#<Version::NullToken>")
end
it "is equal to itself" do
expect(subject).to be == described_class.new
expect(subject).to be == described_class::NULL_TOKEN
end
end
end
describe Version do
specify "comparison" do
expect(described_class.create("0.1")).to be == described_class.create("0.1.0")
expect(described_class.create("0.1")).to be < described_class.create("0.2")
@ -259,9 +261,17 @@ describe Version do
end
end
specify "#detected_from_url?" do
expect(described_class.create("1.0")).not_to be_detected_from_url
expect(Version::FromURL.new("1.0")).to be_detected_from_url
describe "#detected_from_url?" do
it "is false if created explicitly" do
expect(described_class.new("1.0.0")).not_to be_detected_from_url
end
it "is true if the version was detected from a URL" do
version = described_class.detect("https://example.org/archive-1.0.0.tar.gz")
expect(version).to eq "1.0.0"
expect(version).to be_detected_from_url
end
end
specify "#head?" do
@ -363,9 +373,9 @@ describe Version do
end
describe "::detect" do
matcher :be_detected_from do |url, specs = {}|
matcher :be_detected_from do |url, **specs|
match do |expected|
@detected = described_class.detect(url, specs)
@detected = described_class.detect(url, **specs)
@detected == expected
end

View File

@ -2,6 +2,9 @@
require "version/null"
# A formula's version.
#
# @api private
class Version
include Comparable
@ -9,6 +12,7 @@ class Version
/#{"^" if full}#{Regexp.escape(name)}(@\d[\d.]*)?#{"$" if full}/
end
# A part of a `Version`.
class Token
include Comparable
@ -67,9 +71,10 @@ class Version
end
end
# A pseudo-token representing the absence of a token.
class NullToken < Token
def initialize(value = nil)
super
def initialize
super(nil)
end
def <=>(other)
@ -95,9 +100,12 @@ class Version
"#<#{self.class.name}>"
end
end
private_constant :NullToken
# Represents the absence of a token.
NULL_TOKEN = NullToken.new.freeze
# A token string.
class StringToken < Token
PATTERN = /[a-z]+/i.freeze
@ -119,6 +127,7 @@ class Version
end
end
# A token consisting of only numbers.
class NumericToken < Token
PATTERN = /[0-9]+/i.freeze
@ -146,12 +155,14 @@ class Version
end
end
# A token consisting of an alphabetic and a numeric part.
class CompositeToken < StringToken
def rev
value[/[0-9]+/].to_i
end
end
# A token representing the part of a version designating it is an alpha release.
class AlphaToken < CompositeToken
PATTERN = /alpha[0-9]*|a[0-9]+/i.freeze
@ -169,6 +180,7 @@ class Version
end
end
# A token representing the part of a version designating it is a beta release.
class BetaToken < CompositeToken
PATTERN = /beta[0-9]*|b[0-9]+/i.freeze
@ -188,6 +200,7 @@ class Version
end
end
# A token representing the part of a version designating it is a pre-release.
class PreToken < CompositeToken
PATTERN = /pre[0-9]*/i.freeze
@ -207,6 +220,7 @@ class Version
end
end
# A token representing the part of a version designating it is a release-candidate.
class RCToken < CompositeToken
PATTERN = /rc[0-9]*/i.freeze
@ -226,6 +240,7 @@ class Version
end
end
# A token representing the part of a version designating it is a patch release.
class PatchToken < CompositeToken
PATTERN = /p[0-9]*/i.freeze
@ -252,19 +267,10 @@ class Version
NumericToken::PATTERN,
StringToken::PATTERN,
).freeze
private_constant :SCAN_PATTERN
class FromURL < Version
def detected_from_url?
true
end
end
def self.detect(url, specs)
if specs.key?(:tag)
FromURL.parse(specs[:tag])
else
FromURL.parse(url)
end
def self.detect(url, **specs)
parse(specs.fetch(:tag, url), detected_from_url: true)
end
def self.create(val)
@ -277,9 +283,9 @@ class Version
end
end
def self.parse(spec)
def self.parse(spec, detected_from_url: false)
version = _parse(spec)
version.nil? ? NULL : new(version)
version.nil? ? NULL : new(version, detected_from_url: detected_from_url)
end
def self._parse(spec)
@ -424,14 +430,15 @@ class Version
private_class_method :_parse
def initialize(val)
def initialize(val, detected_from_url: false)
raise TypeError, "Version value must be a string; got a #{val.class} (#{val})" unless val.respond_to?(:to_str)
@version = val.to_str
@detected_from_url = detected_from_url
end
def detected_from_url?
false
@detected_from_url
end
def head?
@ -550,10 +557,13 @@ class Version
end
end
# A formula's [HEAD version](https://docs.brew.sh/Formula-Cookbook#unstable-versions-head).
#
# @api private
class HeadVersion < Version
attr_reader :commit
def initialize(val)
def initialize(*)
super
@commit = @version[/^HEAD-(.+)$/, 1]
end

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
class Version
# Represents the absence of a version.
NULL = Class.new do
include Comparable