Skip to content

Commit 51f9e38

Browse files
committed
LeakyConstantDeclaration - allow definitions on example group
Constant, classes, and modules that are defined on the example group do not leak into the global namespace. While doing this may not be a particularly good practice, it should ideally not result in an offense. The practice is described here: https://makandracards.com/makandra/47189-rspec-how-to-define-classes-for-specs#section-1-defining-the-constant-on-the-example-class
1 parent 31c6344 commit 51f9e38

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

lib/rubocop/cop/rspec/leaky_constant_declaration.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,18 +100,21 @@ class LeakyConstantDeclaration < Base
100100

101101
def on_casgn(node)
102102
return unless inside_describe_block?(node)
103+
return if defined_on_example_group?(node)
103104

104105
add_offense(node, message: MSG_CONST)
105106
end
106107

107108
def on_class(node)
108109
return unless inside_describe_block?(node)
110+
return if defined_on_example_group?(node)
109111

110112
add_offense(node, message: MSG_CLASS)
111113
end
112114

113115
def on_module(node)
114116
return unless inside_describe_block?(node)
117+
return if defined_on_example_group?(node)
115118

116119
add_offense(node, message: MSG_MODULE)
117120
end
@@ -121,6 +124,16 @@ def on_module(node)
121124
def inside_describe_block?(node)
122125
node.each_ancestor(:block).any?(&method(:spec_group?))
123126
end
127+
128+
def defined_on_example_group?(node)
129+
if node.is_a?(RuboCop::AST::ClassNode) || node.is_a?(RuboCop::AST::ModuleNode)
130+
node.loc.name.source.start_with?('self::')
131+
elsif node.is_a?(RuboCop::AST::CasgnNode)
132+
node.namespace&.self_type?
133+
else
134+
false
135+
end
136+
end
124137
end
125138
end
126139
end

spec/rubocop/cop/rspec/leaky_constant_declaration_spec.rb

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@
3131
RUBY
3232
end
3333

34+
it 'ignores constant defined on the example group' do
35+
expect_no_offenses(<<~RUBY)
36+
describe SomeClass do
37+
self::CONSTANT = "Accessible as self.class::CONSTANT".freeze
38+
end
39+
RUBY
40+
end
41+
3442
it 'ignores outside of example/shared group' do
3543
expect_no_offenses(<<~RUBY)
3644
factory :some_class do
@@ -60,7 +68,16 @@ def method
6068
end
6169
end
6270
end
63-
end
71+
end
72+
RUBY
73+
end
74+
75+
it 'ignores classes defined on the example group' do
76+
expect_no_offenses(<<~RUBY)
77+
describe SomeClass do
78+
class self::DummyClass
79+
end
80+
end
6481
RUBY
6582
end
6683

@@ -85,5 +102,14 @@ module DummyModule
85102
end
86103
RUBY
87104
end
105+
106+
it 'ignores modules defined on the example group' do
107+
expect_no_offenses(<<~RUBY)
108+
describe SomeClass do
109+
module self::DummyModule
110+
end
111+
end
112+
RUBY
113+
end
88114
end
89115
end

0 commit comments

Comments
 (0)