diff --git a/changelog/new_add_new_gemspec_add_runtime_dependency_cop.md b/changelog/new_add_new_gemspec_add_runtime_dependency_cop.md new file mode 100644 index 0000000000000..568ed4d12b701 --- /dev/null +++ b/changelog/new_add_new_gemspec_add_runtime_dependency_cop.md @@ -0,0 +1 @@ +* [#13030](https://github.com/rubocop/rubocop/pull/13030): Add new `Gemspec/AddRuntimeDependency` cop. ([@koic][]) diff --git a/config/default.yml b/config/default.yml index 5a2a8d45bc586..52a915dddc637 100644 --- a/config/default.yml +++ b/config/default.yml @@ -262,6 +262,14 @@ Bundler/OrderedGems: #################### Gemspec ############################### +Gemspec/AddRuntimeDependency: + Description: 'Prefer `add_dependency` over `add_runtime_dependency`.' + Reference: https://github.com/rubygems/rubygems/issues/7799#issuecomment-2192720316 + Enabled: pending + VersionAdded: '<>' + Include: + - '**/*.gemspec' + Gemspec/DependencyVersion: Description: 'Requires or forbids specifying gem dependency versions.' Enabled: false diff --git a/lib/rubocop.rb b/lib/rubocop.rb index 4a14cfc5e9eb9..4566f4c2873f8 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -169,6 +169,7 @@ require_relative 'rubocop/cop/bundler/insecure_protocol_source' require_relative 'rubocop/cop/bundler/ordered_gems' +require_relative 'rubocop/cop/gemspec/add_runtime_dependency' require_relative 'rubocop/cop/gemspec/dependency_version' require_relative 'rubocop/cop/gemspec/deprecated_attribute_assignment' require_relative 'rubocop/cop/gemspec/development_dependencies' diff --git a/lib/rubocop/cop/gemspec/add_runtime_dependency.rb b/lib/rubocop/cop/gemspec/add_runtime_dependency.rb new file mode 100644 index 0000000000000..73afe2cc6ce6f --- /dev/null +++ b/lib/rubocop/cop/gemspec/add_runtime_dependency.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Gemspec + # Prefer `add_dependency` over `add_runtime_dependency` because + # `add_dependency` is considered soft-deprecated. + # + # @example + # + # # bad + # Gem::Specification.new do |spec| + # spec.add_runtime_dependency('rubocop') + # end + # + # # good + # Gem::Specification.new do |spec| + # spec.add_dependency('rubocop') + # end + # + class AddRuntimeDependency < Base + extend AutoCorrector + + MSG = 'Use `add_dependency` instead of `add_runtime_dependency`.' + + RESTRICT_ON_SEND = %i[add_runtime_dependency].freeze + + def on_send(node) + return if !node.receiver || node.arguments.empty? + + add_offense(node.loc.selector) do |corrector| + corrector.replace(node.loc.selector, 'add_dependency') + end + end + end + end + end +end diff --git a/rubocop.gemspec b/rubocop.gemspec index ab96da0933447..0966bcf29dce3 100644 --- a/rubocop.gemspec +++ b/rubocop.gemspec @@ -31,14 +31,14 @@ Gem::Specification.new do |s| 'rubygems_mfa_required' => 'true' } - s.add_runtime_dependency('json', '~> 2.3') - s.add_runtime_dependency('language_server-protocol', '>= 3.17.0') - s.add_runtime_dependency('parallel', '~> 1.10') - s.add_runtime_dependency('parser', '>= 3.3.0.2') - s.add_runtime_dependency('rainbow', '>= 2.2.2', '< 4.0') - s.add_runtime_dependency('regexp_parser', '>= 2.4', '< 3.0') - s.add_runtime_dependency('rexml', '>= 3.2.5', '< 4.0') - s.add_runtime_dependency('rubocop-ast', '>= 1.31.1', '< 2.0') - s.add_runtime_dependency('ruby-progressbar', '~> 1.7') - s.add_runtime_dependency('unicode-display_width', '>= 2.4.0', '< 3.0') + s.add_dependency('json', '~> 2.3') + s.add_dependency('language_server-protocol', '>= 3.17.0') + s.add_dependency('parallel', '~> 1.10') + s.add_dependency('parser', '>= 3.3.0.2') + s.add_dependency('rainbow', '>= 2.2.2', '< 4.0') + s.add_dependency('regexp_parser', '>= 2.4', '< 3.0') + s.add_dependency('rexml', '>= 3.2.5', '< 4.0') + s.add_dependency('rubocop-ast', '>= 1.31.1', '< 2.0') + s.add_dependency('ruby-progressbar', '~> 1.7') + s.add_dependency('unicode-display_width', '>= 2.4.0', '< 3.0') end diff --git a/spec/rubocop/cop/gemspec/add_runtime_dependency_spec.rb b/spec/rubocop/cop/gemspec/add_runtime_dependency_spec.rb new file mode 100644 index 0000000000000..abb045a9cf71b --- /dev/null +++ b/spec/rubocop/cop/gemspec/add_runtime_dependency_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Gemspec::AddRuntimeDependency, :config do + it 'registers an offense when using `add_runtime_dependency`' do + expect_offense(<<~RUBY) + Gem::Specification.new do |spec| + spec.add_runtime_dependency('rubocop') + ^^^^^^^^^^^^^^^^^^^^^^ Use `add_dependency` instead of `add_runtime_dependency`. + end + RUBY + + expect_correction(<<~RUBY) + Gem::Specification.new do |spec| + spec.add_dependency('rubocop') + end + RUBY + end + + it 'does not register an offense when using `add_dependency`' do + expect_no_offenses(<<~RUBY) + Gem::Specification.new do |spec| + spec.add_dependency('rubocop') + end + RUBY + end + + it 'does not register an offense when using `add_development_dependency`' do + expect_no_offenses(<<~RUBY) + Gem::Specification.new do |spec| + spec.add_development_dependency('rubocop') + end + RUBY + end + + it 'does not register an offense when using `add_runtime_dependency` without receiver' do + expect_no_offenses(<<~RUBY) + add_runtime_dependency('rubocop') + RUBY + end + + it 'does not register an offense when using `add_runtime_dependency` without arguments' do + expect_no_offenses(<<~RUBY) + spec.add_runtime_dependency + RUBY + end +end