class RuboCop::Cop::RSpec::LeakyConstantDeclaration

end
end
stub_const(‘SomeModule::SomeClass’, foo_class)
end
end
def do_something
foo_class = Class.new(described_class) do
before do
describe SomeClass do
# good
end
end
end
end
def do_something
class SomeClass
module SomeModule
describe SomeClass do
# bad
@example
end
it { expect(FooClass.new.double_that).to eq(4) }
end
stub_const(‘FooClass’, foo_class)
end
end
def do_something
foo_class = Class.new(described_class) do
before do
describe SomeClass do
# good - constant is stubbed
end
it { expect(foo_class.new.double_that).to eq(4) }
end
end
end
some_base_method * 2
def double_that
Class.new(described_class) do
let(:foo_class) do
describe SomeClass do
# good - anonymous class, no constant needs to be defined
end
it { expect(FooClass.new.double_that).to eq(4) }
end
end
some_base_method * 2
def double_that
class FooClass < described_class
describe SomeClass do
# bad
@example
end
end
stub_const(‘CONSTANT_HERE’, ‘I only exist during this example’)
stub_const(‘OtherClass’, Struct.new)
before do
describe SomeClass do
# good
end
CONSTANT_HERE = ‘I leak into global namespace’
OtherClass = Struct.new
describe SomeClass do
# bad
@example Constants leak between examples
@see relishapp.com/rspec/rspec-mocks/docs/mutating-constants<br><br>namespace name clashes.
Anonymous classes are fine, since they don’t result in global
Even worse when a class that exists in the codebase is reopened.
unpredictable ways.
examples will be reopening it and modifying its behavior in
blank slate class as it will be in the first example, subsequent
If several examples may define a ‘DummyClass`, instead of being a
scope, are defined in global namespace, and leak between examples.
Constants, including classes and modules, when declared in a block
Checks that no class, module, or constant is declared.

def inside_describe_block?(node)

def inside_describe_block?(node)
  node.each_ancestor(:block).any?(&method(:spec_group?))
end

def on_casgn(node)

def on_casgn(node)
  return unless inside_describe_block?(node)
  add_offense(node, message: MSG_CONST)
end

def on_class(node)

def on_class(node)
  return unless inside_describe_block?(node)
  add_offense(node, message: MSG_CLASS)
end

def on_module(node)

def on_module(node)
  return unless inside_describe_block?(node)
  add_offense(node, message: MSG_MODULE)
end