Skip to content

Commit d1ff3df

Browse files
authored
Merge pull request #9246 from Shopify/ec-require-fix
Fix RubyGems not able to require the right gem:
2 parents 7d09b5d + f298e2c commit d1ff3df

4 files changed

Lines changed: 42 additions & 3 deletions

File tree

lib/rubygems.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,12 @@ def self.try_activate(path)
193193
begin
194194
spec.activate
195195
rescue Gem::LoadError => e # this could fail due to gem dep collisions, go lax
196-
spec_by_name = Gem::Specification.find_by_name(spec.name)
197-
if spec_by_name.nil?
196+
spec = Gem::Specification.find_unloaded_by_path(path)
197+
spec ||= Gem::Specification.find_by_name(spec.name)
198+
if spec.nil?
198199
raise e
199200
else
200-
spec_by_name.activate
201+
spec.activate
201202
end
202203
end
203204

lib/rubygems/specification.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,15 @@ def self.find_by_path(path)
958958
specification_record.find_by_path(path)
959959
end
960960

961+
##
962+
# Return the best specification that contains the file matching +path+
963+
# amongst the specs that are not loaded. This method is different than
964+
# +find_inactive_by_path+ as it will filter out loaded specs by their name.
965+
966+
def self.find_unloaded_by_path(path)
967+
specification_record.find_unloaded_by_path(path)
968+
end
969+
961970
##
962971
# Return the best specification that contains the file matching +path+
963972
# amongst the specs that are not activated.

lib/rubygems/specification_record.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,19 @@ def find_by_path(path)
154154
spec.to_spec
155155
end
156156

157+
##
158+
# Return the best specification that contains the file matching +path+
159+
# amongst the specs that are not loaded. This method is different than
160+
# +find_inactive_by_path+ as it will filter out loaded specs by their name.
161+
162+
def find_unloaded_by_path(path)
163+
stub = stubs.find do |s|
164+
next if Gem.loaded_specs[s.name]
165+
s.contains_requirable_file? path
166+
end
167+
stub&.to_spec
168+
end
169+
157170
##
158171
# Return the best specification in the record that contains the file
159172
# matching +path+ amongst the specs that are not activated.

test/rubygems/test_require.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,22 @@ def test_default_gem_only
431431
assert_equal %w[default-2.0.0.0], loaded_spec_names
432432
end
433433

434+
def test_multiple_gems_with_the_same_path_the_non_activated_spec_is_chosen
435+
a1 = util_spec "a", "1", nil, "lib/ib.rb"
436+
a2 = util_spec "a", "2", nil, "lib/foo.rb"
437+
b1 = util_spec "b", "1", nil, "lib/ib.rb"
438+
439+
install_specs a1, a2, b1
440+
441+
a2.activate
442+
443+
assert_equal %w[a-2], loaded_spec_names
444+
assert_empty unresolved_names
445+
446+
assert_require "ib"
447+
assert_equal %w[a-2 b-1], loaded_spec_names
448+
end
449+
434450
def test_default_gem_require_activates_just_once
435451
default_gem_spec = new_default_spec("default", "2.0.0.0",
436452
nil, "default/gem.rb")

0 commit comments

Comments
 (0)