Skip to content

Commit 40a1512

Browse files
authored
Merge pull request #1499 from fatkodima/fix-false-negative-for-env_local
Fix a false negative for `Rails/EnvLocal` when having preceding conditions
2 parents f57c3ba + 8fcb712 commit 40a1512

3 files changed

Lines changed: 99 additions & 26 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1478](https://github.com/rubocop/rubocop-rails/issues/1478): Fix a false negative for `Rails/EnvLocal` when having preceding conditions. ([@fatkodima][])

lib/rubocop/cop/rails/env_local.rb

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,45 +24,69 @@ class EnvLocal < Base
2424

2525
minimum_target_rails_version 7.1
2626

27-
# @!method rails_env_local_or?(node)
28-
def_node_matcher :rails_env_local_or?, <<~PATTERN
29-
(or
30-
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
31-
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
32-
)
27+
# @!method rails_env_local?(node)
28+
def_node_matcher :rails_env_local?, <<~PATTERN
29+
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
3330
PATTERN
3431

35-
# @!method rails_env_local_and?(node)
36-
def_node_matcher :rails_env_local_and?, <<~PATTERN
37-
(and
38-
(send
39-
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
40-
:!)
41-
(send
42-
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
43-
:!)
44-
)
32+
# @!method not_rails_env_local?(node)
33+
def_node_matcher :not_rails_env_local?, <<~PATTERN
34+
(send #rails_env_local? :!)
4535
PATTERN
4636

4737
def on_or(node)
48-
rails_env_local_or?(node) do |*environments|
49-
next unless environments.to_set == LOCAL_ENVIRONMENTS
38+
lhs, rhs = *node.children
39+
return unless rails_env_local?(rhs)
5040

51-
add_offense(node) do |corrector|
52-
corrector.replace(node, 'Rails.env.local?')
53-
end
41+
nodes = [rhs]
42+
43+
if rails_env_local?(lhs)
44+
nodes << lhs
45+
elsif lhs.or_type? && rails_env_local?(lhs.rhs)
46+
nodes << lhs.rhs
47+
end
48+
49+
return unless environments(nodes).to_set == LOCAL_ENVIRONMENTS
50+
51+
range = offense_range(nodes)
52+
add_offense(range) do |corrector|
53+
corrector.replace(range, 'Rails.env.local?')
5454
end
5555
end
5656

5757
def on_and(node)
58-
rails_env_local_and?(node) do |*environments|
59-
next unless environments.to_set == LOCAL_ENVIRONMENTS
58+
lhs, rhs = *node.children
59+
return unless not_rails_env_local?(rhs)
60+
61+
nodes = [rhs]
62+
63+
if not_rails_env_local?(lhs)
64+
nodes << lhs
65+
elsif lhs.operator_keyword? && not_rails_env_local?(lhs.rhs)
66+
nodes << lhs.rhs
67+
end
6068

61-
add_offense(node, message: MSG_NEGATED) do |corrector|
62-
corrector.replace(node, '!Rails.env.local?')
63-
end
69+
return unless environments(nodes).to_set == LOCAL_ENVIRONMENTS
70+
71+
range = offense_range(nodes)
72+
add_offense(range, message: MSG_NEGATED) do |corrector|
73+
corrector.replace(range, '!Rails.env.local?')
6474
end
6575
end
76+
77+
private
78+
79+
def environments(nodes)
80+
if nodes[0].method?(:!)
81+
nodes.map { |node| node.receiver.method_name }
82+
else
83+
nodes.map(&:method_name)
84+
end
85+
end
86+
87+
def offense_range(nodes)
88+
nodes[1].source_range.begin.join(nodes[0].source_range.end)
89+
end
6690
end
6791
end
6892
end

spec/rubocop/cop/rails/env_local_spec.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@
4343
RUBY
4444
end
4545

46+
it 'registers an offense for `Rails.env.development? || Rails.env.test?` || foo?' do
47+
expect_offense(<<~RUBY)
48+
Rails.env.development? || Rails.env.test? || foo?
49+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `Rails.env.local?` instead.
50+
foo? || Rails.env.test? || Rails.env.development?
51+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `Rails.env.local?` instead.
52+
RUBY
53+
54+
expect_correction(<<~RUBY)
55+
Rails.env.local? || foo?
56+
foo? || Rails.env.local?
57+
RUBY
58+
end
59+
4660
it 'registers an offense for `!Rails.env.development? && !Rails.env.test?`' do
4761
expect_offense(<<~RUBY)
4862
!Rails.env.development? && !Rails.env.test?
@@ -57,12 +71,46 @@
5771
RUBY
5872
end
5973

74+
it 'registers an offense for `!Rails.env.development? && !Rails.env.test?` || foo?' do
75+
expect_offense(<<~RUBY)
76+
!Rails.env.development? && !Rails.env.test? || foo?
77+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `!Rails.env.local?` instead.
78+
foo? || !Rails.env.test? && !Rails.env.development?
79+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `!Rails.env.local?` instead.
80+
RUBY
81+
82+
expect_correction(<<~RUBY)
83+
!Rails.env.local? || foo?
84+
foo? || !Rails.env.local?
85+
RUBY
86+
end
87+
88+
it 'registers an offense for `!Rails.env.development? && !Rails.env.test?` && foo?' do
89+
expect_offense(<<~RUBY)
90+
!Rails.env.development? && !Rails.env.test? && foo?
91+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `!Rails.env.local?` instead.
92+
foo? && !Rails.env.test? && !Rails.env.development?
93+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `!Rails.env.local?` instead.
94+
RUBY
95+
96+
expect_correction(<<~RUBY)
97+
!Rails.env.local? && foo?
98+
foo? && !Rails.env.local?
99+
RUBY
100+
end
101+
60102
it 'registers no offenses for `Rails.env.local?`' do
61103
expect_no_offenses(<<~RUBY)
62104
Rails.env.local?
63105
RUBY
64106
end
65107

108+
it 'registers no offenses for `Rails.env.development? || Rails.env.test? && foo?`' do
109+
expect_no_offenses(<<~RUBY)
110+
Rails.env.development? || Rails.env.test? && foo?
111+
RUBY
112+
end
113+
66114
include_examples 'non-local candidates'
67115
end
68116

0 commit comments

Comments
 (0)