Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Master (Unreleased)

- Mark `RSpec/IncludeExamples` as `SafeAutoCorrect: false`. ([@yujideveloper])
- Fix a false positive for `RSpec/LeakyConstantDeclaration` when defining constants in explicit namespaces. ([@naveg])

## 3.6.0 (2025-04-18)

Expand Down
7 changes: 7 additions & 0 deletions lib/rubocop/cop/rspec/leaky_constant_declaration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,21 @@ class LeakyConstantDeclaration < Base

def on_casgn(node)
return unless inside_describe_block?(node)
return if explicit_namespace?(node.namespace)

add_offense(node, message: MSG_CONST)
end

def on_class(node)
return unless inside_describe_block?(node)
return if explicit_namespace?(node.identifier.namespace)

add_offense(node, message: MSG_CLASS)
end

def on_module(node)
return unless inside_describe_block?(node)
return if explicit_namespace?(node.identifier.namespace)

add_offense(node, message: MSG_MODULE)
end
Expand All @@ -121,6 +124,10 @@ def on_module(node)
def inside_describe_block?(node)
node.each_ancestor(:block).any? { |ancestor| spec_group?(ancestor) }
end

def explicit_namespace?(namespace)
!namespace.nil?
end
end
end
end
Expand Down
78 changes: 73 additions & 5 deletions spec/rubocop/cop/rspec/leaky_constant_declaration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,30 @@
RUBY
end

it 'ignores constant defined on the example group' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
self::CONSTANT = "Accessible as self.class::CONSTANT".freeze
end
RUBY
end

it 'ignores constant defined in an explicit namespace' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
Foo::CONSTANT = "Accessible as Foo::CONSTANT".freeze
end
RUBY
end

it 'ignores classes defined explicitly in the global namespace' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
::CONSTANT = "Accessible as ::CONSTANT".freeze
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also accessible as CONSTANT aka “I know what I am doing”.

end
RUBY
end

it 'ignores outside of example/shared group' do
expect_no_offenses(<<~RUBY)
factory :some_class do
Expand Down Expand Up @@ -60,15 +84,32 @@ def method
end
end
end
end
end
RUBY
end

it 'flags namespaced class' do
expect_offense(<<~RUBY)
it 'ignores classes defined on the example group' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
class self::DummyClass
end
end
RUBY
end

it 'ignores classes defined in an explicit namespace' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
class SomeModule::AnotherModule::DummyClass
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Stub class constant instead of declaring explicitly.
class Foo::DummyClass
end
end
RUBY
end

it 'ignores classes defined explicitly in the global namespace' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
class ::DummyClass
end
end
RUBY
Expand All @@ -93,6 +134,33 @@ module DummyModule
RUBY
end

it 'ignores modules defined on the example group' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
module self::DummyModule
end
end
RUBY
end

it 'ignores modules defined in an explicit namespace' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
module Foo::DummyModule
end
end
RUBY
end

it 'ignores modules defined explicitly in the global namespace' do
expect_no_offenses(<<~RUBY)
describe SomeClass do
module ::DummyModule
end
end
RUBY
end

it 'ignores outside of example/shared group' do
expect_no_offenses(<<~RUBY)
module Dummymodule
Expand Down