diff --git a/.rubocop.yml b/.rubocop.yml index fec4631b4..8ae0a9f6e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -179,6 +179,8 @@ RSpec/RedundantAround: Enabled: true RSpec/RedundantPredicateMatcher: Enabled: true +RSpec/RemoveConst: + Enabled: true RSpec/SkipBlockInsideExample: Enabled: true RSpec/SortMetadata: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d4470237..360677133 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Add new `RSpec/RedundantPredicateMatcher` cop. ([@ydah]) - Add support for correcting "it will" (future tense) for `RSpec/ExampleWording`. ([@jdufresne]) +- Add new `RSpec/RemoveConst` cop. ([@swelther]) ## 2.25.0 (2023-10-27) @@ -913,6 +914,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. [@smcgivern]: https://github.com/smcgivern [@splattael]: https://github.com/splattael [@stephannv]: https://github.com/stephannv +[@swelther]: https://github.com/swelther [@t3h2mas]: https://github.com/t3h2mas [@tdeo]: https://github.com/tdeo [@tejasbubane]: https://github.com/tejasbubane diff --git a/config/default.yml b/config/default.yml index 0429572b1..d1dc431d7 100644 --- a/config/default.yml +++ b/config/default.yml @@ -777,6 +777,12 @@ RSpec/RedundantPredicateMatcher: VersionAdded: "<>" Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPredicateMatcher +RSpec/RemoveConst: + Description: Checks that `remove_const` is not used in specs. + Enabled: pending + VersionAdded: "<>" + Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RemoveConst + RSpec/RepeatedDescription: Description: Check for repeated description strings in example groups. Enabled: true diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index b2878c1a9..41faf557f 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -81,6 +81,7 @@ * xref:cops_rspec.adoc#rspecreceivenever[RSpec/ReceiveNever] * xref:cops_rspec.adoc#rspecredundantaround[RSpec/RedundantAround] * xref:cops_rspec.adoc#rspecredundantpredicatematcher[RSpec/RedundantPredicateMatcher] +* xref:cops_rspec.adoc#rspecremoveconst[RSpec/RemoveConst] * xref:cops_rspec.adoc#rspecrepeateddescription[RSpec/RepeatedDescription] * xref:cops_rspec.adoc#rspecrepeatedexample[RSpec/RepeatedExample] * xref:cops_rspec.adoc#rspecrepeatedexamplegroupbody[RSpec/RepeatedExampleGroupBody] diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 51960efc7..48d17cd07 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -4525,6 +4525,38 @@ expect(foo).not_to include(bar) * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPredicateMatcher +== RSpec/RemoveConst + +|=== +| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed + +| Pending +| Yes +| No +| <> +| - +|=== + +Checks that `remove_const` is not used in specs. + +=== Examples + +[source,ruby] +---- +# bad +it 'does something' do + Object.send(:remove_const, :SomeConstant) +end + +before do + SomeClass.send(:remove_const, :SomeConstant) +end +---- + +=== References + +* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RemoveConst + == RSpec/RepeatedDescription |=== diff --git a/lib/rubocop/cop/rspec/remove_const.rb b/lib/rubocop/cop/rspec/remove_const.rb new file mode 100644 index 000000000..1adbe9d9f --- /dev/null +++ b/lib/rubocop/cop/rspec/remove_const.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks that `remove_const` is not used in specs. + # + # @example + # # bad + # it 'does something' do + # Object.send(:remove_const, :SomeConstant) + # end + # + # before do + # SomeClass.send(:remove_const, :SomeConstant) + # end + # + class RemoveConst < Base + include RuboCop::RSpec::Language + extend RuboCop::RSpec::Language::NodePattern + + MSG = 'Do not use remove_const in specs. ' \ + 'Consider using e.g. `stub_const`.' + RESTRICT_ON_SEND = %i[send __send__].freeze + + # @!method remove_const(node) + def_node_matcher :remove_const, <<~PATTERN + (send _ {:send | :__send__} (sym :remove_const) _) + PATTERN + + # Check for offenses + def on_send(node) + remove_const(node) do + add_offense(node) + end + end + end + end + end +end diff --git a/lib/rubocop/cop/rspec_cops.rb b/lib/rubocop/cop/rspec_cops.rb index 70add9ab0..02f2692b4 100644 --- a/lib/rubocop/cop/rspec_cops.rb +++ b/lib/rubocop/cop/rspec_cops.rb @@ -107,6 +107,7 @@ require_relative 'rspec/receive_never' require_relative 'rspec/redundant_around' require_relative 'rspec/redundant_predicate_matcher' +require_relative 'rspec/remove_const' require_relative 'rspec/repeated_description' require_relative 'rspec/repeated_example' require_relative 'rspec/repeated_example_group_body' diff --git a/spec/rubocop/cop/rspec/remove_const_spec.rb b/spec/rubocop/cop/rspec/remove_const_spec.rb new file mode 100644 index 000000000..41bad4646 --- /dev/null +++ b/spec/rubocop/cop/rspec/remove_const_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::RSpec::RemoveConst do + it 'detects the `remove_const` usage' do + expect_offense(<<-RUBY) + it 'does something' do + Object.send(:remove_const, :SomeConstant) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use remove_const in specs. Consider using e.g. `stub_const`. + end + RUBY + + expect_offense(<<-RUBY) + before do + SomeClass.send(:remove_const, :SomeConstant) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use remove_const in specs. Consider using e.g. `stub_const`. + end + RUBY + end + + it 'detects the `remove_const` usage when using `__send__`' do + expect_offense(<<-RUBY) + it 'does something' do + NiceClass.__send__(:remove_const, :SomeConstant) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use remove_const in specs. Consider using e.g. `stub_const`. + end + RUBY + end +end