It's not clear how to avoid these problems. They arise when combining
gems that set reasonable dependencies. In this case, thin and
passenger both are certifying that they work with rack >= 1.0, but
Rails is only certifying that it works with rack ~> 1.0. Both of these
are perfectly valid assertions. In combination, however, requiring
thin first activates a dependency that Rails cannot handle. The only
solution is to examine all of the dependencies *at once* and discover
that a version (1.0.x) of the Rack satisfies all dependencies. This is
what bundler does.
> As for Rack breakage, wouldn't that be easily solved with some version
> numbering discipline? If Rack decides to break an interface then it
> should bump its major version to 2.
That's essentially what happens now. At present, Rack hasn't broken
things in teeny versions but it has in tiny. As a result, Rails 2.3 is
limiting itself to 1.0.x, while Rails 3.0 is limiting itself to 1.1.x.
Passenger and thin, on the other hand, are willing to handle 1.x. If
Rack bumped its version to 2.0 instead, the same problem could arise
(Rails 2.3 could depend on 1.x, but Rails 3.0 could depend on 2.x,
while Passenger and Thin wanted to support 1.x-2.x).
In essence, this is a fundamental problem when combining dependencies
with overlapping ranges. The only proper way to solve this is to
examine all dependencies at once and resolve them to find working
ranges. Requiring them linearly (the way without bundler) results in
these sorts of problems.