Manage Requirements using ComparableSet
ComparableSet only allows a single object of a given class, choosing the object with the greatest value. This was mainly created for Requirements, so that, e.g., two X11Dependencies of differing strictness don't both end up in the same requirement set. Fixes Homebrew/homebrew#15240.
This commit is contained in:
parent
3fb5dfbd7b
commit
bbfb6400c7
@ -21,7 +21,7 @@ class DependencyCollector
|
||||
|
||||
def initialize
|
||||
@deps = Dependencies.new
|
||||
@requirements = Set.new
|
||||
@requirements = ComparableSet.new
|
||||
end
|
||||
|
||||
def add spec
|
||||
@ -196,6 +196,9 @@ end
|
||||
# This requirement is used to require an X11 implementation,
|
||||
# optionally with a minimum version number.
|
||||
class X11Dependency < Requirement
|
||||
include Comparable
|
||||
attr_reader :min_version
|
||||
|
||||
def initialize min_version=nil
|
||||
@min_version = min_version
|
||||
end
|
||||
@ -217,9 +220,20 @@ class X11Dependency < Requirement
|
||||
ENV.x11
|
||||
end
|
||||
|
||||
def hash
|
||||
"X11".hash
|
||||
def <=> other
|
||||
unless other.is_a? X11Dependency
|
||||
raise TypeError, "expected X11Dependency"
|
||||
end
|
||||
|
||||
if other.min_version.nil?
|
||||
1
|
||||
elsif @min_version.nil?
|
||||
-1
|
||||
else
|
||||
@min_version <=> other.min_version
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
24
Library/Homebrew/extend/set.rb
Normal file
24
Library/Homebrew/extend/set.rb
Normal file
@ -0,0 +1,24 @@
|
||||
require 'set'
|
||||
|
||||
class ComparableSet < Set
|
||||
def add new
|
||||
# smileys only
|
||||
return super new unless new.respond_to? :>
|
||||
|
||||
objs = find_all { |o| o.class == new.class }
|
||||
objs.each do |o|
|
||||
return self if o > new
|
||||
delete o
|
||||
end
|
||||
super new
|
||||
end
|
||||
|
||||
alias_method :<<, :add
|
||||
|
||||
# Set#merge bypasses enumerating the set's contents,
|
||||
# so the subclassed #add would never be called
|
||||
def merge enum
|
||||
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
|
||||
enum.each { |o| add(o) }
|
||||
end
|
||||
end
|
||||
@ -6,6 +6,7 @@ require 'bottles'
|
||||
require 'patches'
|
||||
require 'compilers'
|
||||
require 'build_environment'
|
||||
require 'extend/set'
|
||||
|
||||
|
||||
class Formula
|
||||
@ -455,9 +456,9 @@ class Formula
|
||||
end
|
||||
|
||||
def recursive_requirements
|
||||
reqs = recursive_deps.map { |dep| dep.requirements }.to_set
|
||||
reqs << requirements
|
||||
reqs.flatten
|
||||
reqs = ComparableSet.new
|
||||
recursive_deps.each { |dep| reqs.merge dep.requirements }
|
||||
reqs.merge requirements
|
||||
end
|
||||
|
||||
def to_hash
|
||||
|
||||
40
Library/Homebrew/test/test_comparableset.rb
Normal file
40
Library/Homebrew/test/test_comparableset.rb
Normal file
@ -0,0 +1,40 @@
|
||||
require 'testing_env'
|
||||
require 'extend/set'
|
||||
|
||||
class ComparableSetTests < Test::Unit::TestCase
|
||||
def setup
|
||||
@set = ComparableSet.new
|
||||
end
|
||||
|
||||
def test_merging_multiple_dependencies
|
||||
@set << X11Dependency.new
|
||||
@set << X11Dependency.new
|
||||
assert_equal @set.count, 1
|
||||
@set << Requirement.new
|
||||
assert_equal @set.count, 2
|
||||
end
|
||||
|
||||
def test_comparison_prefers_larger
|
||||
@set << X11Dependency.new
|
||||
@set << X11Dependency.new('2.6')
|
||||
assert_equal @set.count, 1
|
||||
assert_equal @set.to_a, [X11Dependency.new('2.6')]
|
||||
end
|
||||
|
||||
def test_comparison_does_not_merge_smaller
|
||||
@set << X11Dependency.new('2.6')
|
||||
@set << X11Dependency.new
|
||||
assert_equal @set.count, 1
|
||||
assert_equal @set.to_a, [X11Dependency.new('2.6')]
|
||||
end
|
||||
|
||||
def test_merging_sets
|
||||
@set << X11Dependency.new
|
||||
@set << Requirement.new
|
||||
reqs = Set.new [X11Dependency.new('2.6'), Requirement.new]
|
||||
@set.merge reqs
|
||||
|
||||
assert_equal @set.count, 2
|
||||
assert_equal @set.find {|r| r.is_a? X11Dependency}, X11Dependency.new('2.6')
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user