diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index edfc33d7d..88f234e1c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -91,7 +91,7 @@ jobs: - uses: actions/checkout@v4 - name: Use oldest RuboCop allowed by gemspec run: | - sed -nr "s/ *spec.add_dependency 'rubocop', '~> ([0-9\.]+)'/gem 'rubocop', '= \1'/p" \ + sed -nr "s/ *spec.add_dependency 'rubocop'.*'>= ([0-9\.]+)'/gem 'rubocop', '= \1'/p" \ rubocop-rspec.gemspec > Gemfile.local cat Gemfile.local - uses: ruby/setup-ruby@v1 diff --git a/.rubocop.yml b/.rubocop.yml index eea5a6472..301fa37a9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,10 +1,10 @@ inherit_from: .rubocop_todo.yml -require: +plugins: - rubocop-performance - rubocop-rake - rubocop-rspec - - rubocop/cop/internal_affairs + - rubocop-internal_affairs AllCops: DisplayCopNames: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a42c044d..c5664ddac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Don't let `RSpec/PredicateMatcher` replace `respond_to?` with two arguments with the RSpec `respond_to` matcher. ([@bquorning]) - Fix `RSpec/PredicateMatcher` support for `eql` and `equal` matchers. ([@bquorning]) +- Pluginfy RuboCop RSpec. ([@koic]) ## 3.4.0 (2025-01-20) diff --git a/README.md b/README.md index 61b5ff355..938a8f0d7 100644 --- a/README.md +++ b/README.md @@ -48,13 +48,13 @@ ways to do this: Put this into your `.rubocop.yml`. ```yaml -require: rubocop-rspec +plugins: rubocop-rspec ``` Alternatively, use the following array notation when specifying multiple extensions. ```yaml -require: +plugins: - rubocop-other-extension - rubocop-rspec ``` @@ -62,17 +62,20 @@ require: Now you can run `rubocop` and it will automatically load the RuboCop RSpec cops together with the standard cops. +> [!NOTE] +> The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`. + ### Command line ```bash -rubocop --require rubocop-rspec +rubocop --plugin rubocop-rspec ``` ### Rake task ```ruby RuboCop::RakeTask.new do |task| - task.requires << 'rubocop-rspec' + task.plugins << 'rubocop-rspec' end ``` diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index dd381a687..d0a276420 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -8,13 +8,13 @@ There are three ways to do this: Put this into your `.rubocop.yml`: ---- -require: rubocop-rspec +plugins: rubocop-rspec ---- or, if you are using several extensions: ---- -require: +plugins: - rubocop-rspec - rubocop-performance ---- @@ -22,6 +22,8 @@ require: Now you can run `rubocop` and it will automatically load the RuboCop RSpec cops together with the standard cops. +NOTE: The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`. + === RSpec DSL configuration In case you https://github.com/rspec/rspec-core/blob/b0d0843a285693c64cdbe0c85726db155b46047e/lib/rspec/core/configuration.rb#L1122[define aliases for RSpec DSL], i.e. examples, example groups, hooks, or include example statements, you need to configure it so those elements are properly detected by RuboCop RSpec. @@ -78,7 +80,7 @@ RuboCop RSpec's https://github.com/rubocop/rubocop-rspec/blob/a43424527c09fae2e6 [source,bash] ---- -$ rubocop --require rubocop-rspec +$ rubocop --plugin rubocop-rspec ---- == Rake task @@ -86,7 +88,7 @@ $ rubocop --require rubocop-rspec [source,ruby] ---- RuboCop::RakeTask.new do |task| - task.requires << 'rubocop-rspec' + task.plugins << 'rubocop-rspec' end ---- diff --git a/lib/rubocop-rspec.rb b/lib/rubocop-rspec.rb index ac03fa7dc..3de03a7ae 100644 --- a/lib/rubocop-rspec.rb +++ b/lib/rubocop-rspec.rb @@ -6,9 +6,9 @@ require 'rubocop' require_relative 'rubocop/rspec' -require_relative 'rubocop/rspec/inject' require_relative 'rubocop/rspec/language' require_relative 'rubocop/rspec/node' +require_relative 'rubocop/rspec/plugin' require_relative 'rubocop/rspec/version' require_relative 'rubocop/rspec/wording' @@ -34,8 +34,6 @@ require_relative 'rubocop/rspec/example_group' require_relative 'rubocop/rspec/hook' -RuboCop::RSpec::Inject.defaults! - require_relative 'rubocop/cop/rspec_cops' # We have to register our autocorrect incompatibilities in RuboCop's cops diff --git a/lib/rubocop/rspec.rb b/lib/rubocop/rspec.rb index 83235f3da..e53c3ce5a 100644 --- a/lib/rubocop/rspec.rb +++ b/lib/rubocop/rspec.rb @@ -3,12 +3,5 @@ module RuboCop # RuboCop RSpec project namespace module RSpec - PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze - CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze - - private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT) - - ::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join('config', - 'obsoletion.yml') end end diff --git a/lib/rubocop/rspec/inject.rb b/lib/rubocop/rspec/inject.rb deleted file mode 100644 index d4b193e1f..000000000 --- a/lib/rubocop/rspec/inject.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module RSpec - # Because RuboCop doesn't yet support plugins, we have to monkey patch in a - # bit of our configuration. - module Inject - def self.defaults! - path = CONFIG_DEFAULT.to_s - hash = ConfigLoader.send(:load_yaml_configuration, path) - config = RuboCop::Config.new(hash, path) - puts "configuration from #{path}" if ConfigLoader.debug? - config = ConfigLoader.merge_with_default(config, path) - ConfigLoader.instance_variable_set(:@default_configuration, config) - end - end - end -end diff --git a/lib/rubocop/rspec/plugin.rb b/lib/rubocop/rspec/plugin.rb new file mode 100644 index 000000000..88d48cf0c --- /dev/null +++ b/lib/rubocop/rspec/plugin.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'lint_roller' + +module RuboCop + module RSpec + # A plugin that integrates RuboCop RSpec with RuboCop's plugin system. + class Plugin < LintRoller::Plugin + # :nocov: + def about + LintRoller::About.new( + name: 'rubocop-rspec', + version: Version::STRING, + homepage: 'https://github.com/rubocop/rubocop-rspec', + description: 'Code style checking for RSpec files.' + ) + end + # :nocov: + + def supported?(context) + context.engine == :rubocop + end + + def rules(_context) + project_root = Pathname.new(__dir__).join('../../..') + + ConfigObsoletion.files << project_root.join('config', 'obsoletion.yml') + + LintRoller::Rules.new( + type: :path, + config_format: :rubocop, + value: project_root.join('config/default.yml') + ) + end + end + end +end diff --git a/rubocop-rspec.gemspec b/rubocop-rspec.gemspec index 6b1ada365..5296dd3e2 100644 --- a/rubocop-rspec.gemspec +++ b/rubocop-rspec.gemspec @@ -34,8 +34,10 @@ Gem::Specification.new do |spec| spec.metadata = { 'changelog_uri' => 'https://github.com/rubocop/rubocop-rspec/blob/master/CHANGELOG.md', 'documentation_uri' => 'https://docs.rubocop.org/rubocop-rspec/', - 'rubygems_mfa_required' => 'true' + 'rubygems_mfa_required' => 'true', + 'default_lint_roller_plugin' => 'RuboCop::RSpec::Plugin' } - spec.add_dependency 'rubocop', '~> 1.61' + spec.add_dependency 'lint_roller', '~> 1.1' + spec.add_dependency 'rubocop', '~> 1.72', '>= 1.72.1' end diff --git a/spec/rubocop/rspec/inject_spec.rb b/spec/rubocop/rspec/inject_spec.rb deleted file mode 100644 index 44f98070f..000000000 --- a/spec/rubocop/rspec/inject_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::RSpec::Inject do - describe '.defaults!' do - let(:config_loader) { class_double(RuboCop::ConfigLoader).as_stubbed_const } - - before do - rubocop_config = instance_double(RuboCop::Config) - allow(config_loader).to receive(:send) - .with(:load_yaml_configuration, any_args) - .and_return({}) - allow(RuboCop::Config).to receive(:new).and_return(rubocop_config) - allow(config_loader).to receive(:merge_with_default) - .and_return(rubocop_config) - allow(config_loader).to receive(:instance_variable_set) - end - - context 'when ConfigLoader.debug? is true' do - before do - allow(config_loader).to receive(:debug?).and_return(true) - end - - it 'puts the configuration path' do - expect { described_class.defaults! }.to output( - %r{configuration from .*rubocop-rspec/config/default.yml} - ).to_stdout - end - end - - context 'when ConfigLoader.debug? is false' do - before do - allow(config_loader).to receive(:debug?).and_return(false) - end - - it 'does not put the configuration path' do - expect { described_class.defaults! }.not_to output.to_stdout - end - end - end -end diff --git a/tasks/cops_documentation.rake b/tasks/cops_documentation.rake index 510146bd6..b257dea1d 100644 --- a/tasks/cops_documentation.rake +++ b/tasks/cops_documentation.rake @@ -12,6 +12,8 @@ end desc 'Generate docs of all cops departments' task generate_cops_documentation: :yard_for_generate_documentation do + RuboCop::ConfigLoader.inject_defaults!("#{__dir__}/../config/default.yml") + generator = CopsDocumentationGenerator.new( departments: %w[RSpec] )