Skip to content

Commit

Permalink
Merge pull request #831 from kellysutton/ks-nested-module-cop
Browse files Browse the repository at this point in the history
Implement RSpec/DescribedClassModuleWrapping cop
  • Loading branch information
bquorning committed Oct 29, 2019
2 parents 6049c9a + 0e1687c commit 0036374
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,7 @@

## Master (Unreleased)

* Implement `RSpec/DescribedClassModuleWrapping` to disallow RSpec statements within a module. ([@kellysutton][])
* Fix documentation rake task to support Rubocop 0.75. ([@nickcampbell18][])
* Fix `RSpec/SubjectStub` to detect implicit subjects stubbed. ([@QQism][])

Expand Down Expand Up @@ -457,3 +458,4 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
[@onumis]: https://github.com/onumis
[@nickcampbell18]: https://github.com/nickcampbell18
[@QQism]: https://github.com/QQism
[@kellysutton]: https://github.com/kellysutton
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -88,6 +88,11 @@ RSpec/DescribedClass:
- explicit
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass

RSpec/DescribedClassModuleWrapping:
Description: Avoid opening modules and defining specs within them.
Enabled: false
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping

RSpec/Dialect:
Description: This cop enforces custom RSpec dialects.
Enabled: false
Expand Down
36 changes: 36 additions & 0 deletions lib/rubocop/cop/rspec/described_class_module_wrapping.rb
@@ -0,0 +1,36 @@
# frozen_string_literal: true

module RuboCop
module Cop
module RSpec
# Avoid opening modules and defining specs within them.
#
# @example
# # bad
# module MyModule
# RSpec.describe MyClass do
# # ...
# end
# end
#
# # good
# RSpec.describe MyModule::MyClass do
# # ...
# end
#
# @see https://github.com/rubocop-hq/rubocop-rspec/issues/735
class DescribedClassModuleWrapping < Cop
MSG = 'Avoid opening modules and defining specs within them.'

def_node_search :find_rspec_blocks,
ExampleGroups::ALL.block_pattern

def on_module(node)
find_rspec_blocks(node) do
add_offense(node)
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rspec_cops.rb
Expand Up @@ -25,6 +25,7 @@
require_relative 'rspec/describe_method'
require_relative 'rspec/describe_symbol'
require_relative 'rspec/described_class'
require_relative 'rspec/described_class_module_wrapping'
require_relative 'rspec/dialect'
require_relative 'rspec/empty_example_group'
require_relative 'rspec/empty_line_after_example'
Expand Down
1 change: 1 addition & 0 deletions manual/cops.md
Expand Up @@ -24,6 +24,7 @@
* [RSpec/DescribeMethod](cops_rspec.md#rspecdescribemethod)
* [RSpec/DescribeSymbol](cops_rspec.md#rspecdescribesymbol)
* [RSpec/DescribedClass](cops_rspec.md#rspecdescribedclass)
* [RSpec/DescribedClassModuleWrapping](cops_rspec.md#rspecdescribedclassmodulewrapping)
* [RSpec/Dialect](cops_rspec.md#rspecdialect)
* [RSpec/EmptyExampleGroup](cops_rspec.md#rspecemptyexamplegroup)
* [RSpec/EmptyLineAfterExample](cops_rspec.md#rspecemptylineafterexample)
Expand Down
28 changes: 28 additions & 0 deletions manual/cops_rspec.md
Expand Up @@ -469,6 +469,34 @@ EnforcedStyle | `described_class` | `described_class`, `explicit`

* [https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass](https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass)

## RSpec/DescribedClassModuleWrapping

Enabled by default | Supports autocorrection
--- | ---
Disabled | No

Avoid opening modules and defining specs within them.

### Examples

```ruby
# bad
module MyModule
RSpec.describe MyClass do
# ...
end
end

# good
RSpec.describe MyModule::MyClass do
# ...
end
```

### References

* [https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping](https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping)

## RSpec/Dialect

Enabled by default | Supports autocorrection
Expand Down
49 changes: 49 additions & 0 deletions spec/rubocop/cop/rspec/described_class_module_wrapping_spec.rb
@@ -0,0 +1,49 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::RSpec::DescribedClassModuleWrapping do
subject(:cop) { described_class.new }

it 'allows a describe block in the outermost scope' do
expect_no_offenses(<<-RUBY)
RSpec.describe MyClass do
subject { "MyClass" }
end
RUBY
end

it 'registers an offense when RSpec.describe is nested within a module' do
expect_offense(<<-RUBY)
module MyModule
^^^^^^^^^^^^^^^ Avoid opening modules and defining specs within them.
RSpec.describe MyClass do
subject { "MyClass" }
end
end
RUBY
end

it 'registers an offense when RSpec.describe is nested within two modules' do
expect_offense(<<-RUBY)
module MyFirstModule
^^^^^^^^^^^^^^^^^^^^ Avoid opening modules and defining specs within them.
module MySecondModule
^^^^^^^^^^^^^^^^^^^^^ Avoid opening modules and defining specs within them.
RSpec.describe MyClass do
subject { "MyClass" }
end
end
end
RUBY
end

it 'allows a module that does not contain RSpec.describe' do
expect_no_offenses(<<-RUBY)
module MyModule
def some_method
end
end
RUBY
end
end

0 comments on commit 0036374

Please sign in to comment.