Remove Array subclassing

Inheriting from Array (and other core types) is problematic:

  - It exposes a very wide interface with many methods that are not
    really relevant to the subclass.
  - It can cause some weird side effects, as many Array operations are
    in C and have hardcoded return values; for example, combining two
    array subclasses returns a new Array instead of the subclass.

Avoid these problems using delegation and the Enumerable module where
applicable.
This commit is contained in:
Jack Nagel 2013-01-07 14:06:34 -06:00
parent 7473d2b12f
commit 429caf69a9
3 changed files with 57 additions and 14 deletions

View File

@ -1,19 +1,45 @@
class Compilers < Array
def include? cc
class Compilers
include Enumerable
def initialize(*args)
@compilers = Array.new(*args)
end
def each(*args, &block)
@compilers.each(*args, &block)
end
def include?(cc)
cc = cc.name if cc.is_a? Compiler
self.any? { |c| c.name == cc }
@compilers.any? { |c| c.name == cc }
end
def <<(o)
@compilers << o
self
end
end
class CompilerFailures < Array
def include? cc
class CompilerFailures
include Enumerable
def initialize(*args)
@failures = Array.new(*args)
end
def each(*args, &block)
@failures.each(*args, &block)
end
def include?(cc)
cc = Compiler.new(cc) unless cc.is_a? Compiler
self.any? { |failure| failure.compiler == cc.name }
@failures.any? { |failure| failure.compiler == cc.name }
end
def <<(failure)
super(failure) unless self.include? failure.compiler
def <<(o)
@failures << o unless include? o.compiler
self
end
end
@ -72,7 +98,7 @@ class CompilerSelector
# @compilers is our list of available compilers. If @f declares a
# failure with compiler foo, then we remove foo from the list if
# the failing build is >= the currently installed version of foo.
@compilers.reject! do |cc|
@compilers = @compilers.reject do |cc|
failure = @f.fails_with? cc
next unless failure
failure.build >= cc.build

View File

@ -85,11 +85,28 @@ private
end
class Dependencies
include Enumerable
def initialize(*args)
@deps = Array.new(*args)
end
def each(*args, &block)
@deps.each(*args, &block)
end
# A list of formula dependencies.
class Dependencies < Array
def <<(o)
super(o) unless include? o
@deps << o unless @deps.include? o
self
end
def empty?
@deps.empty?
end
def *(arg)
@deps * arg
end
end

View File

@ -30,7 +30,7 @@ class DependencyTests < Test::Unit::TestCase
def test_no_duplicate_dependencies
@d.add 'foo'
@d.add 'foo' => :build
assert_equal 1, @d.deps.length
assert_equal 1, @d.deps.count
assert_empty @d.find_dependency('foo').tags
end
end