lib/rubocop/cop/rspec/described_class.rb in rubocop-rspec-1.35.0 vs lib/rubocop/cop/rspec/described_class.rb in rubocop-rspec-1.36.0
- old
+ new
@@ -6,11 +6,12 @@
# Checks that tests use `described_class`.
#
# If the first argument of describe is a class, the class is exposed to
# each example via described_class.
#
- # This cop can be configured using the `EnforcedStyle` option
+ # This cop can be configured using the `EnforcedStyle` and `SkipBlocks`
+ # options.
#
# @example `EnforcedStyle: described_class`
# # bad
# describe MyClass do
# subject { MyClass.do_something }
@@ -30,10 +31,31 @@
# # good
# describe MyClass do
# subject { MyClass.do_something }
# end
#
+ # There's a known caveat with rspec-rails's `controller` helper that
+ # runs its block in a different context, and `described_class` is not
+ # available to it. `SkipBlocks` option excludes detection in all
+ # non-RSpec related blocks.
+ #
+ # To narrow down this setting to only a specific directory, it is
+ # possible to use an overriding configuration file local to that
+ # directory.
+ #
+ # @example `SkipBlocks: true`
+ # # spec/controllers/.rubocop.yml
+ # # RSpec/DescribedClass:
+ # # SkipBlocks: true
+ #
+ # # acceptable
+ # describe MyConcern do
+ # controller(ApplicationController) do
+ # include MyConcern
+ # end
+ # end
+ #
class DescribedClass < Cop
include ConfigurableEnforcedStyle
DESCRIBED_CLASS = 'described_class'
MSG = 'Use `%<replacement>s` instead of `%<src>s`.'
@@ -49,10 +71,14 @@
def_node_matcher :described_constant, <<-PATTERN
(block (send _ :describe $(const ...) ...) (args) $_)
PATTERN
+ def_node_search :contains_described_class?, <<-PATTERN
+ (send nil? :described_class)
+ PATTERN
+
def on_block(node)
# In case the explicit style is used, we need to remember what's
# being described.
@described_class, body = described_constant(node)
@@ -117,9 +143,11 @@
end
end
def offensive_described_class?(node)
return unless node.const_type?
+ # E.g. `described_class::CONSTANT`
+ return if contains_described_class?(node)
nearest_described_class, = node.each_ancestor(:block)
.map { |ancestor| described_constant(ancestor) }.find(&:itself)
return if nearest_described_class.equal?(node)