class RuboCop::Cop::RSpec::DescribedClass


end
end
include MyConcern
controller(ApplicationController) do
describe MyConcern do
# acceptable
# SkipBlocks: true
# RSpec/DescribedClass:
# spec/controllers/.rubocop.yml
@example ‘SkipBlocks: true`
directory.
possible to use an overriding configuration file local to that
To narrow down this setting to only a specific directory, it is
non-RSpec related blocks.
available to it. `SkipBlocks` option excludes detection in all
runs its block in a different context, and `described_class` is not
There’s a known caveat with rspec-rails’s ‘controller` helper that
end
subject { MyClass.do_something }
describe MyClass do
# good
end
subject { described_class.do_something }
describe MyClass do
# bad
@example `EnforcedStyle: explicit`
end
subject { described_class.do_something }
describe MyClass do
# good
end
subject { MyClass.do_something }
describe MyClass do
# bad
@example `EnforcedStyle: described_class` (default)
options.
This cop can be configured using the `EnforcedStyle` and `SkipBlocks`
each example via described_class.
If the first argument of describe is a class, the class is exposed to
Checks that tests use `described_class`.

def autocorrect(corrector, match)

def autocorrect(corrector, match)
  replacement = if style == :described_class
                  DESCRIBED_CLASS
                else
                  @described_class.const_name
                end
  corrector.replace(match, replacement)
end

def collapse_namespace(namespace, const)

Returns:
  • (Array) -

Parameters:
  • const (Array) --
  • namespace (Array) --
def collapse_namespace(namespace, const)
  return const if namespace.empty? || const.first.nil?
  start = [0, (namespace.length - const.length)].max
  max = namespace.length
  intersection = (start..max).find do |shift|
    namespace[shift, max - shift] == const[0, max - shift]
  end
  [*namespace[0, intersection], *const]
end

def const_name(node)

Returns:
  • (Array) -

Parameters:
  • node (RuboCop::AST::Node) --
def const_name(node)
  namespace, name = *node # rubocop:disable InternalAffairs/NodeDestructuring
  if !namespace
    [name]
  elsif namespace.const_type?
    [*const_name(namespace), name]
  elsif %i[lvar cbase send].include?(namespace.type)
    [nil, name]
  end
end

def find_usage(node, &block)

def find_usage(node, &block)
  yield(node) if offensive?(node)
  return if scope_change?(node) || node.const_type?
  node.each_child_node do |child|
    find_usage(child, &block)
  end
end

def full_const_name(node)

def full_const_name(node)
  symbolized_namespace = namespace(node).map(&:to_sym)
  collapse_namespace(symbolized_namespace, const_name(node))
end

def message(offense)

def message(offense)
  if style == :described_class
    format(MSG, replacement: DESCRIBED_CLASS, src: offense)
  else
    format(MSG, replacement: @described_class.const_name,
                src: DESCRIBED_CLASS)
  end
end

def offensive?(node)

def offensive?(node)
  if style == :described_class
    offensive_described_class?(node)
  else
    node.send_type? && node.method?(:described_class)
  end
end

def offensive_described_class?(node)

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)
  full_const_name(nearest_described_class) == full_const_name(node)
end

def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler

rubocop:disable InternalAffairs/NumblockHandler
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
  # In case the explicit style is used, we need to remember what's
  # being described.
  @described_class, body = described_constant(node)
  return unless body
  find_usage(body) do |match|
    msg = message(match.const_name)
    add_offense(match, message: msg) do |corrector|
      autocorrect(corrector, match)
    end
  end
end

def scope_change?(node)

def scope_change?(node)
  scope_changing_syntax?(node) ||
    common_instance_exec_closure?(node) ||
    skippable_block?(node)
end

def skippable_block?(node)

def skippable_block?(node)
  node.block_type? && !rspec_block?(node) && cop_config['SkipBlocks']
end