diff options
| -rw-r--r-- | lib/rubygems/specification_policy.rb | 28 | ||||
| -rw-r--r-- | test/rubygems/test_gem_specification.rb | 55 |
2 files changed, 83 insertions, 0 deletions
diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb index 0fcb635394..8ab82ee4a9 100644 --- a/lib/rubygems/specification_policy.rb +++ b/lib/rubygems/specification_policy.rb @@ -476,6 +476,7 @@ or set it to nil if you don't want to specify a license. validate_rake_extensions(builder) validate_rust_extensions(builder) + validate_extension_require_relative end def validate_rust_extensions(builder) # :nodoc: @@ -496,6 +497,33 @@ You have specified rake based extension, but rake is not added as runtime depend WARNING end + def validate_extension_require_relative # :nodoc: + return unless @specification.extensions.any? + + require_paths = @specification.require_paths + + @specification.files.each do |rb_file| + next unless rb_file.end_with?(".rb") + next unless require_paths.any? {|rp| rb_file.start_with?("#{rp}/") } + next unless File.file?(rb_file) + + File.foreach(rb_file).with_index(1) do |line, lineno| + next unless line =~ /^\s*require_relative\s+["']([^"']+)["']/ + + required_path = Regexp.last_match(1) + resolved = File.join(File.dirname(rb_file), required_path) + + next if @specification.files.any? {|f| f == "#{resolved}.rb" || f == resolved } + + warning <<~WARNING + #{rb_file}:#{lineno} uses `require_relative "#{required_path}"` to load a compiled extension. + This will break in RubyGems 4.2, which will stop copying compiled extensions into the gem's lib directory. + Use `require` instead of `require_relative` to load compiled extensions. + WARNING + end + end + end + def validate_unique_links links = @specification.metadata.slice(*METADATA_LINK_KEYS) grouped = links.group_by {|_key, uri| uri } diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 7675ade415..cf01a40b8c 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -2887,6 +2887,61 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: end end + def test_validate_extension_require_relative_warning + util_setup_validate + + Dir.chdir @tempdir do + @a1.extensions = ["ext/a/extconf.rb"] + @a1.files = %w[lib/code.rb lib/a.rb ext/a/extconf.rb] + + File.write File.join("lib", "a.rb"), 'require_relative "a/a"' + + use_ui @ui do + @a1.validate + end + + assert_match(%r{require_relative "a/a"}, @ui.error) + assert_match(/will break in RubyGems 4\.2/, @ui.error) + assert_match(/Use `require` instead of `require_relative`/, @ui.error) + end + end + + def test_validate_extension_require_relative_no_warning_when_rb_exists + util_setup_validate + + Dir.chdir @tempdir do + @a1.extensions = ["ext/a/extconf.rb"] + @a1.files = %w[lib/code.rb lib/a.rb lib/a/a.rb ext/a/extconf.rb] + + FileUtils.mkdir_p File.join("lib", "a") + File.write File.join("lib", "a.rb"), 'require_relative "a/a"' + File.write File.join("lib", "a", "a.rb"), "" + + use_ui @ui do + @a1.validate + end + + refute_match(/require_relative/, @ui.error) + end + end + + def test_validate_extension_require_relative_no_warning_without_extensions + util_setup_validate + + Dir.chdir @tempdir do + @a1.extensions = [] + @a1.files = %w[lib/code.rb lib/a.rb] + + File.write File.join("lib", "a.rb"), 'require_relative "a/a"' + + use_ui @ui do + @a1.validate + end + + refute_match(/require_relative/, @ui.error) + end + end + def test_validate_description util_setup_validate |
