diff --git a/lib/rubygems.rb b/lib/rubygems.rb index b52dd1b9d3e9..31abb7e56987 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -193,11 +193,12 @@ def self.try_activate(path) begin spec.activate rescue Gem::LoadError => e # this could fail due to gem dep collisions, go lax - spec_by_name = Gem::Specification.find_by_name(spec.name) - if spec_by_name.nil? + spec = Gem::Specification.find_unloaded_by_path(path) + spec ||= Gem::Specification.find_by_name(spec.name) + if spec.nil? raise e else - spec_by_name.activate + spec.activate end end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 3d1f2dad9104..aa495696adce 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -958,6 +958,15 @@ def self.find_by_path(path) specification_record.find_by_path(path) end + ## + # Return the best specification that contains the file matching +path+ + # amongst the specs that are not loaded. This method is different than + # +find_inactive_by_path+ as it will filter out loaded specs by their name. + + def self.find_unloaded_by_path(path) + specification_record.find_unloaded_by_path(path) + end + ## # Return the best specification that contains the file matching +path+ # amongst the specs that are not activated. diff --git a/lib/rubygems/specification_record.rb b/lib/rubygems/specification_record.rb index d08410096fac..c7e5cbedb58c 100644 --- a/lib/rubygems/specification_record.rb +++ b/lib/rubygems/specification_record.rb @@ -154,6 +154,19 @@ def find_by_path(path) spec.to_spec end + ## + # Return the best specification that contains the file matching +path+ + # amongst the specs that are not loaded. This method is different than + # +find_inactive_by_path+ as it will filter out loaded specs by their name. + + def find_unloaded_by_path(path) + stub = stubs.find do |s| + next if Gem.loaded_specs[s.name] + s.contains_requirable_file? path + end + stub&.to_spec + end + ## # Return the best specification in the record that contains the file # matching +path+ amongst the specs that are not activated. diff --git a/test/rubygems/test_require.rb b/test/rubygems/test_require.rb index f63c23c3159d..e5f9d7bed2c9 100644 --- a/test/rubygems/test_require.rb +++ b/test/rubygems/test_require.rb @@ -431,6 +431,22 @@ def test_default_gem_only assert_equal %w[default-2.0.0.0], loaded_spec_names end + def test_multiple_gems_with_the_same_path_the_non_activated_spec_is_chosen + a1 = util_spec "a", "1", nil, "lib/ib.rb" + a2 = util_spec "a", "2", nil, "lib/foo.rb" + b1 = util_spec "b", "1", nil, "lib/ib.rb" + + install_specs a1, a2, b1 + + a2.activate + + assert_equal %w[a-2], loaded_spec_names + assert_empty unresolved_names + + assert_require "ib" + assert_equal %w[a-2 b-1], loaded_spec_names + end + def test_default_gem_require_activates_just_once default_gem_spec = new_default_spec("default", "2.0.0.0", nil, "default/gem.rb")