The implementation of #eql? and #hash should ensure that if a.eql?(b),
then a.hash == b.hash, but #eql? itself should not *depend* on #hash.
For example, given
class Thingy
def eql?
instance_of?(other.class) && hash == other.hash
end
def hash
[name, *tags].hash
end
end
if #hash produces a collision for different values of [name, *tags], two
Thingy objects will appear to be eql?, even though this is not the case.
Instead, #eql? should depend on the equality of name and tags directly.
This hack was necessary since requirements were not checked again
in the forked build process, but now they are, and calling it again
after the build environment has been set up can produce incorrect
results. In fact, if it happens to return false the second time,
the env modification will be skipped altogether.
By always passing around a single, unnested array rather than splatting
and then defensively flattening and compacting things, we can avoid
allocating a bunch of unnecessary arrays. This gives a performance boost
of roughly 4% when enumerating 2500 formulae, and has the side effect of
cleaning up the dependency API.
The name attribute of requirements is used when generating options for
the :optional and :recommended dependency tags.
Unless otherwise specified, the name attribute of a Requirement will be
populated by stripping any module prefixes from the beginning and
"Dependency" or "Requirement" from end of the class name and downcasing
the result.
ClosesHomebrew/homebrew#17759.
When a requirement is specified like:
satisfy { which "foo" }
There is no reason that we should inject all of ENV.userpaths! into the
build environment. Instead, infer the directory to be added to PATH from
the Pathname that is returned.
This is another step towards condensing the "which program" requirements
down into a one-liner DSL element.
Instead of overriding #satisfied?, Requirement subclasses can specify
the condition in a block:
satisfy do
some_condition?
end
The contents of the block are evaluated in the context of the instance,
and so have access to instance variables and instance methods as before.
Additionally, it is wrapped in an ENV.with_build_environment block. This
can be disabled by passing :build_env => false to satisfy:
satisfy :build_env => false do
some_condition?
end
The DependencyCollector tests are really integration tests, while the
rest are closer to real unit tests. Split them up so that the tests can
be run in isolation on a per-class basis.