rubocop-rails 2.32.0 → 2.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/default.yml +47 -3
- data/lib/rubocop/cop/mixin/active_record_helper.rb +1 -1
- data/lib/rubocop/cop/mixin/index_method.rb +4 -0
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +4 -2
- data/lib/rubocop/cop/rails/delegate.rb +4 -4
- data/lib/rubocop/cop/rails/duplicate_association.rb +1 -1
- data/lib/rubocop/cop/rails/duplicate_scope.rb +2 -2
- data/lib/rubocop/cop/rails/env.rb +57 -0
- data/lib/rubocop/cop/rails/env_local.rb +50 -26
- data/lib/rubocop/cop/rails/environment_comparison.rb +56 -48
- data/lib/rubocop/cop/rails/exit.rb +7 -4
- data/lib/rubocop/cop/rails/file_path.rb +2 -2
- data/lib/rubocop/cop/rails/find_by.rb +1 -1
- data/lib/rubocop/cop/rails/find_by_or_assignment_memoization.rb +124 -0
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +16 -17
- data/lib/rubocop/cop/rails/http_status_name_consistency.rb +80 -0
- data/lib/rubocop/cop/rails/index_with.rb +5 -0
- data/lib/rubocop/cop/rails/inverse_of.rb +7 -0
- data/lib/rubocop/cop/rails/order_arguments.rb +84 -0
- data/lib/rubocop/cop/rails/output.rb +3 -0
- data/lib/rubocop/cop/rails/output_safety.rb +3 -1
- data/lib/rubocop/cop/rails/pluck.rb +6 -3
- data/lib/rubocop/cop/rails/presence.rb +52 -18
- data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
- data/lib/rubocop/cop/rails/redirect_back_or_to.rb +89 -0
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -1
- data/lib/rubocop/cop/rails/save_bang.rb +2 -2
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +4 -1
- data/lib/rubocop/cop/rails/where_exists.rb +5 -5
- data/lib/rubocop/cop/rails_cops.rb +5 -0
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +9 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ffddf417706a66433be596f397b807c824a2593bea0a5175907be9d9be318970
|
|
4
|
+
data.tar.gz: 40672bac8ab7a1961102c3f5306526fa98a360987c7095128313dd5bae7c5641
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 16ba2fc1926397b8b5c413c207a9f45e80a30b53e1e73b215e18abf38218e3aea3ecd2090cc4858adfe4a9d32ebb527b83db57acb38cff48510d4eaf18dcdd9c
|
|
7
|
+
data.tar.gz: 6541216ccafd3cd5287517989ea8a49dcb4b547ca98d0c363f58ac5a11ebbe6452329ea0964357e7f9777a5224d05d271b6bd21ee31f0d0bffcb37dfaa26dbd0
|
data/config/default.yml
CHANGED
|
@@ -91,6 +91,12 @@ Lint/UselessAccessModifier:
|
|
|
91
91
|
- concern
|
|
92
92
|
- concerning
|
|
93
93
|
|
|
94
|
+
Lint/UselessMethodDefinition:
|
|
95
|
+
# Avoids conflict with `Rails/LexicallyScopedActionFilter` cop.
|
|
96
|
+
Exclude:
|
|
97
|
+
- '**/app/controllers/**/*.rb'
|
|
98
|
+
- '**/app/mailers/**/*.rb'
|
|
99
|
+
|
|
94
100
|
Rails:
|
|
95
101
|
Enabled: true
|
|
96
102
|
DocumentationBaseURL: https://docs.rubocop.org/rubocop-rails
|
|
@@ -402,7 +408,7 @@ Rails/DuplicateAssociation:
|
|
|
402
408
|
VersionChanged: '2.18'
|
|
403
409
|
|
|
404
410
|
Rails/DuplicateScope:
|
|
405
|
-
Description: 'Multiple scopes share this same
|
|
411
|
+
Description: 'Multiple scopes share this same expression.'
|
|
406
412
|
Enabled: pending
|
|
407
413
|
Severity: warning
|
|
408
414
|
VersionAdded: '2.14'
|
|
@@ -453,6 +459,7 @@ Rails/EnumSyntax:
|
|
|
453
459
|
VersionAdded: '2.26'
|
|
454
460
|
Include:
|
|
455
461
|
- '**/app/models/**/*.rb'
|
|
462
|
+
- '**/lib/**/*.rb'
|
|
456
463
|
|
|
457
464
|
Rails/EnumUniqueness:
|
|
458
465
|
Description: 'Avoid duplicate integers in hash-syntax `enum` declaration.'
|
|
@@ -461,6 +468,11 @@ Rails/EnumUniqueness:
|
|
|
461
468
|
Include:
|
|
462
469
|
- '**/app/models/**/*.rb'
|
|
463
470
|
|
|
471
|
+
Rails/Env:
|
|
472
|
+
Description: 'Use Feature Flags or config instead of `Rails.env`.'
|
|
473
|
+
Enabled: false
|
|
474
|
+
VersionAdded: '2.34'
|
|
475
|
+
|
|
464
476
|
Rails/EnvLocal:
|
|
465
477
|
Description: 'Use `Rails.env.local?` instead of `Rails.env.development? || Rails.env.test?`.'
|
|
466
478
|
Enabled: pending
|
|
@@ -532,6 +544,13 @@ Rails/FindById:
|
|
|
532
544
|
Enabled: 'pending'
|
|
533
545
|
VersionAdded: '2.7'
|
|
534
546
|
|
|
547
|
+
Rails/FindByOrAssignmentMemoization:
|
|
548
|
+
Description: 'Avoid memoizing `find_by` results with `||=`.'
|
|
549
|
+
StyleGuide: 'https://rails.rubystyle.guide/#find-by-memoization'
|
|
550
|
+
Enabled: pending
|
|
551
|
+
Safe: false
|
|
552
|
+
VersionAdded: '2.33'
|
|
553
|
+
|
|
535
554
|
Rails/FindEach:
|
|
536
555
|
Description: 'Prefer all.find_each over all.each.'
|
|
537
556
|
StyleGuide: 'https://rails.rubystyle.guide#find-each'
|
|
@@ -595,6 +614,14 @@ Rails/HttpStatus:
|
|
|
595
614
|
- numeric
|
|
596
615
|
- symbolic
|
|
597
616
|
|
|
617
|
+
Rails/HttpStatusNameConsistency:
|
|
618
|
+
Description: 'Enforces consistency by using the current HTTP status names.'
|
|
619
|
+
Enabled: pending
|
|
620
|
+
Severity: warning
|
|
621
|
+
VersionAdded: '2.34'
|
|
622
|
+
Include:
|
|
623
|
+
- '**/app/controllers/**/*.rb'
|
|
624
|
+
|
|
598
625
|
Rails/I18nLazyLookup:
|
|
599
626
|
Description: 'Checks for places where I18n "lazy" lookup can be used.'
|
|
600
627
|
StyleGuide: 'https://rails.rubystyle.guide/#lazy-lookup'
|
|
@@ -647,8 +674,9 @@ Rails/IndexBy:
|
|
|
647
674
|
Rails/IndexWith:
|
|
648
675
|
Description: 'Prefer `index_with` over `each_with_object`, `to_h`, or `map`.'
|
|
649
676
|
Enabled: true
|
|
677
|
+
SafeAutoCorrect: false
|
|
650
678
|
VersionAdded: '2.5'
|
|
651
|
-
VersionChanged: '2.
|
|
679
|
+
VersionChanged: '2.33'
|
|
652
680
|
|
|
653
681
|
Rails/Inquiry:
|
|
654
682
|
Description: "Prefer Ruby's comparison operators over Active Support's `Array#inquiry` and `String#inquiry`."
|
|
@@ -742,6 +770,13 @@ Rails/NotNullColumn:
|
|
|
742
770
|
Include:
|
|
743
771
|
- db/**/*.rb
|
|
744
772
|
|
|
773
|
+
Rails/OrderArguments:
|
|
774
|
+
Description: 'Prefer symbol arguments over strings in `order` method.'
|
|
775
|
+
StyleGuide: 'https://rails.rubystyle.guide/#order-arguments'
|
|
776
|
+
Enabled: pending
|
|
777
|
+
VersionAdded: '2.33'
|
|
778
|
+
Safe: false
|
|
779
|
+
|
|
745
780
|
Rails/OrderById:
|
|
746
781
|
Description: >-
|
|
747
782
|
Do not use the `id` column for ordering.
|
|
@@ -809,6 +844,7 @@ Rails/Presence:
|
|
|
809
844
|
Description: 'Checks code that can be written more easily using `Object#presence` defined by Active Support.'
|
|
810
845
|
Enabled: true
|
|
811
846
|
VersionAdded: '0.52'
|
|
847
|
+
VersionChanged: '2.34'
|
|
812
848
|
|
|
813
849
|
Rails/Present:
|
|
814
850
|
Description: 'Enforces use of `present?`.'
|
|
@@ -845,6 +881,14 @@ Rails/ReadWriteAttribute:
|
|
|
845
881
|
Include:
|
|
846
882
|
- '**/app/models/**/*.rb'
|
|
847
883
|
|
|
884
|
+
Rails/RedirectBackOrTo:
|
|
885
|
+
Description: >-
|
|
886
|
+
Use `redirect_back_or_to` instead of `redirect_back` with
|
|
887
|
+
`fallback_location` option.
|
|
888
|
+
Enabled: pending
|
|
889
|
+
Severity: warning
|
|
890
|
+
VersionAdded: '2.34'
|
|
891
|
+
|
|
848
892
|
Rails/RedundantActiveRecordAllMethod:
|
|
849
893
|
Description: Detect redundant `all` used as a receiver for Active Record query methods.
|
|
850
894
|
StyleGuide: 'https://rails.rubystyle.guide/#redundant-all'
|
|
@@ -1126,7 +1170,7 @@ Rails/ThreeStateBooleanColumn:
|
|
|
1126
1170
|
Rails/TimeZone:
|
|
1127
1171
|
Description: 'Checks the correct usage of time zone aware methods.'
|
|
1128
1172
|
StyleGuide: 'https://rails.rubystyle.guide#time'
|
|
1129
|
-
Reference: '
|
|
1173
|
+
Reference: 'https://danilenko.org/2012/7/6/rails_timezones'
|
|
1130
1174
|
Enabled: true
|
|
1131
1175
|
SafeAutoCorrect: false
|
|
1132
1176
|
VersionAdded: '0.30'
|
|
@@ -106,7 +106,7 @@ module RuboCop
|
|
|
106
106
|
send_node = node.each_ancestor(:call).first
|
|
107
107
|
return false unless send_node
|
|
108
108
|
|
|
109
|
-
return true if WHERE_METHODS.include?(send_node.method_name)
|
|
109
|
+
return true if WHERE_METHODS.include?(send_node.method_name) && send_node.receiver != node
|
|
110
110
|
|
|
111
111
|
receiver = send_node.receiver
|
|
112
112
|
return false unless receiver&.send_type?
|
|
@@ -132,9 +132,13 @@ module RuboCop
|
|
|
132
132
|
add_offense(
|
|
133
133
|
node, message: "Prefer `#{new_method_name}` over `#{match_desc}`."
|
|
134
134
|
) do |corrector|
|
|
135
|
+
next if part_of_ignored_node?(node)
|
|
136
|
+
|
|
135
137
|
correction = prepare_correction(node)
|
|
136
138
|
execute_correction(corrector, node, correction)
|
|
137
139
|
end
|
|
140
|
+
|
|
141
|
+
ignore_node(node)
|
|
138
142
|
end
|
|
139
143
|
|
|
140
144
|
def extract_captures(match)
|
|
@@ -73,7 +73,7 @@ module RuboCop
|
|
|
73
73
|
return false if use_redirect_to?(context)
|
|
74
74
|
|
|
75
75
|
context = node
|
|
76
|
-
elsif context.right_siblings.empty?
|
|
76
|
+
elsif context.right_siblings.empty? && !use_redirect_to?(context.parent)
|
|
77
77
|
return true
|
|
78
78
|
end
|
|
79
79
|
context = context.right_siblings
|
|
@@ -98,7 +98,9 @@ module RuboCop
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def use_redirect_to?(context)
|
|
101
|
-
context.right_siblings.
|
|
101
|
+
context.right_siblings.any? do |sibling|
|
|
102
|
+
next unless sibling.is_a?(AST::Node)
|
|
103
|
+
|
|
102
104
|
# Unwrap `return redirect_to :index`
|
|
103
105
|
sibling = sibling.children.first if sibling.return_type? && sibling.children.one?
|
|
104
106
|
sibling.send_type? && sibling.method?(:redirect_to)
|
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
|
76
76
|
|
|
77
77
|
def on_def(node)
|
|
78
78
|
return unless trivial_delegate?(node)
|
|
79
|
-
return if private_or_protected_delegation(node)
|
|
79
|
+
return if private_or_protected_delegation?(node)
|
|
80
80
|
return if module_function_declared?(node)
|
|
81
81
|
|
|
82
82
|
register_offense(node)
|
|
@@ -163,8 +163,8 @@ module RuboCop
|
|
|
163
163
|
end
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
-
def private_or_protected_delegation(node)
|
|
167
|
-
private_or_protected_inline(node) || node_visibility(node) != :public
|
|
166
|
+
def private_or_protected_delegation?(node)
|
|
167
|
+
private_or_protected_inline?(node) || node_visibility(node) != :public
|
|
168
168
|
end
|
|
169
169
|
|
|
170
170
|
def module_function_declared?(node)
|
|
@@ -173,7 +173,7 @@ module RuboCop
|
|
|
173
173
|
end
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
-
def private_or_protected_inline(node)
|
|
176
|
+
def private_or_protected_inline?(node)
|
|
177
177
|
processed_source[node.first_line - 1].strip.match?(/\A(private )|(protected )/)
|
|
178
178
|
end
|
|
179
179
|
end
|
|
@@ -94,7 +94,7 @@ module RuboCop
|
|
|
94
94
|
filtered_nodes = association_nodes.reject { |node| node.method?(:belongs_to) }
|
|
95
95
|
grouped_associations = filtered_nodes.group_by do |node|
|
|
96
96
|
arguments = association(node).last
|
|
97
|
-
next unless arguments.
|
|
97
|
+
next unless arguments.one?
|
|
98
98
|
|
|
99
99
|
if (class_name = class_name(arguments.first))
|
|
100
100
|
class_name.source
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Rails
|
|
6
|
-
# Checks for multiple scopes in a model that have the same
|
|
6
|
+
# Checks for multiple scopes in a model that have the same expression. This
|
|
7
7
|
# often means you copy/pasted a scope, updated the name, and forgot to change the condition.
|
|
8
8
|
#
|
|
9
9
|
# @example
|
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
|
19
19
|
class DuplicateScope < Base
|
|
20
20
|
include ClassSendNodeHelper
|
|
21
21
|
|
|
22
|
-
MSG = 'Multiple scopes share this same
|
|
22
|
+
MSG = 'Multiple scopes share this same expression.'
|
|
23
23
|
|
|
24
24
|
def_node_matcher :scope, <<~PATTERN
|
|
25
25
|
(send nil? :scope _ $...)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Rails
|
|
6
|
+
# Checks for usage of `Rails.env` which can be replaced with Feature Flags
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
#
|
|
10
|
+
# # bad
|
|
11
|
+
# Rails.env.production? || Rails.env.local?
|
|
12
|
+
#
|
|
13
|
+
# # good
|
|
14
|
+
# if FeatureFlag.enabled?(:new_feature)
|
|
15
|
+
# # new feature code
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
class Env < Base
|
|
19
|
+
MSG = 'Use Feature Flags or config instead of `Rails.env`.'
|
|
20
|
+
RESTRICT_ON_SEND = %i[env].freeze
|
|
21
|
+
# This allow list is derived from:
|
|
22
|
+
# (Rails.env.methods - Object.instance_methods).select { |m| m.to_s.end_with?('?') }
|
|
23
|
+
# and then removing the environment specific methods like development?, test?, production?, local?
|
|
24
|
+
ALLOWED_LIST = Set.new(
|
|
25
|
+
%i[
|
|
26
|
+
unicode_normalized?
|
|
27
|
+
exclude?
|
|
28
|
+
empty?
|
|
29
|
+
acts_like_string?
|
|
30
|
+
include?
|
|
31
|
+
is_utf8?
|
|
32
|
+
casecmp?
|
|
33
|
+
match?
|
|
34
|
+
starts_with?
|
|
35
|
+
ends_with?
|
|
36
|
+
start_with?
|
|
37
|
+
end_with?
|
|
38
|
+
valid_encoding?
|
|
39
|
+
ascii_only?
|
|
40
|
+
between?
|
|
41
|
+
]
|
|
42
|
+
).freeze
|
|
43
|
+
|
|
44
|
+
def on_send(node)
|
|
45
|
+
return unless node.receiver&.const_name == 'Rails'
|
|
46
|
+
|
|
47
|
+
parent = node.parent
|
|
48
|
+
return unless parent&.predicate_method?
|
|
49
|
+
|
|
50
|
+
return if ALLOWED_LIST.include?(parent.method_name)
|
|
51
|
+
|
|
52
|
+
add_offense(parent)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -24,45 +24,69 @@ module RuboCop
|
|
|
24
24
|
|
|
25
25
|
minimum_target_rails_version 7.1
|
|
26
26
|
|
|
27
|
-
# @!method
|
|
28
|
-
def_node_matcher :
|
|
29
|
-
(
|
|
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)
|
|
33
30
|
PATTERN
|
|
34
31
|
|
|
35
|
-
# @!method
|
|
36
|
-
def_node_matcher :
|
|
37
|
-
(
|
|
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? :!)
|
|
45
35
|
PATTERN
|
|
46
36
|
|
|
47
37
|
def on_or(node)
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
lhs, rhs = *node.children
|
|
39
|
+
return unless rails_env_local?(rhs)
|
|
50
40
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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?')
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def on_and(node)
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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?')
|
|
64
74
|
end
|
|
65
75
|
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
|
|
66
90
|
end
|
|
67
91
|
end
|
|
68
92
|
end
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Rails
|
|
6
|
-
# Checks that Rails.env is compared using `.production?`-like
|
|
6
|
+
# Checks that `Rails.env` is compared using `.production?`-like
|
|
7
7
|
# methods instead of equality against a string or symbol.
|
|
8
8
|
#
|
|
9
9
|
# @example
|
|
10
10
|
# # bad
|
|
11
11
|
# Rails.env == 'production'
|
|
12
|
+
# Rails.env.to_sym == :production
|
|
12
13
|
#
|
|
13
14
|
# # bad, always returns false
|
|
14
15
|
# Rails.env == :test
|
|
@@ -18,26 +19,40 @@ module RuboCop
|
|
|
18
19
|
class EnvironmentComparison < Base
|
|
19
20
|
extend AutoCorrector
|
|
20
21
|
|
|
21
|
-
MSG = 'Favor `%<
|
|
22
|
+
MSG = 'Favor `%<prefer>s` over `%<source>s`.'
|
|
22
23
|
|
|
23
24
|
SYM_MSG = 'Do not compare `Rails.env` with a symbol, it will always evaluate to `false`.'
|
|
24
25
|
|
|
25
26
|
RESTRICT_ON_SEND = %i[== !=].freeze
|
|
26
27
|
|
|
27
|
-
def_node_matcher :
|
|
28
|
-
|
|
29
|
-
(send
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
def_node_matcher :comparing_env_with_rails_env_on_lhs?, <<~PATTERN
|
|
29
|
+
{
|
|
30
|
+
(send
|
|
31
|
+
(send (const {nil? cbase} :Rails) :env)
|
|
32
|
+
{:== :!=}
|
|
33
|
+
$str
|
|
34
|
+
)
|
|
35
|
+
(send
|
|
36
|
+
(send (send (const {nil? cbase} :Rails) :env) :to_sym)
|
|
37
|
+
{:== :!=}
|
|
38
|
+
$sym
|
|
39
|
+
)
|
|
40
|
+
}
|
|
33
41
|
PATTERN
|
|
34
42
|
|
|
35
|
-
def_node_matcher :
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
def_node_matcher :comparing_env_with_rails_env_on_rhs?, <<~PATTERN
|
|
44
|
+
{
|
|
45
|
+
(send
|
|
46
|
+
$str
|
|
47
|
+
{:== :!=}
|
|
48
|
+
(send (const {nil? cbase} :Rails) :env)
|
|
49
|
+
)
|
|
50
|
+
(send
|
|
51
|
+
$sym
|
|
52
|
+
{:== :!=}
|
|
53
|
+
(send (send (const {nil? cbase} :Rails) :env) :to_sym)
|
|
54
|
+
)
|
|
55
|
+
}
|
|
41
56
|
PATTERN
|
|
42
57
|
|
|
43
58
|
def_node_matcher :comparing_sym_env_with_rails_env_on_lhs?, <<~PATTERN
|
|
@@ -56,59 +71,52 @@ module RuboCop
|
|
|
56
71
|
)
|
|
57
72
|
PATTERN
|
|
58
73
|
|
|
59
|
-
def_node_matcher :content, <<~PATTERN
|
|
60
|
-
({str sym} $_)
|
|
61
|
-
PATTERN
|
|
62
|
-
|
|
63
74
|
def on_send(node)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
check_env_comparison_with_rails_env(node)
|
|
76
|
+
check_sym_env_comparison_with_rails_env(node)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def check_env_comparison_with_rails_env(node)
|
|
82
|
+
return unless comparing_env_with_rails_env_on_lhs?(node) || comparing_env_with_rails_env_on_rhs?(node)
|
|
83
|
+
|
|
84
|
+
replacement = build_predicate_method(node)
|
|
85
|
+
message = format(MSG, prefer: replacement, source: node.source)
|
|
86
|
+
|
|
87
|
+
add_offense(node, message: message) do |corrector|
|
|
88
|
+
corrector.replace(node, replacement)
|
|
73
89
|
end
|
|
90
|
+
end
|
|
74
91
|
|
|
92
|
+
def check_sym_env_comparison_with_rails_env(node)
|
|
75
93
|
return unless comparing_sym_env_with_rails_env_on_lhs?(node) || comparing_sym_env_with_rails_env_on_rhs?(node)
|
|
76
94
|
|
|
77
95
|
add_offense(node, message: SYM_MSG) do |corrector|
|
|
78
|
-
|
|
96
|
+
replacement = build_predicate_method(node)
|
|
97
|
+
corrector.replace(node, replacement)
|
|
79
98
|
end
|
|
80
99
|
end
|
|
81
100
|
|
|
82
|
-
|
|
101
|
+
def build_predicate_method(node)
|
|
102
|
+
bang = node.method?(:!=) ? '!' : ''
|
|
83
103
|
|
|
84
|
-
|
|
85
|
-
|
|
104
|
+
receiver, argument = extract_receiver_and_argument(node)
|
|
105
|
+
receiver = receiver.receiver if receiver.method?(:to_sym)
|
|
86
106
|
|
|
87
|
-
|
|
107
|
+
"#{bang}#{receiver.source}.#{argument.value}?"
|
|
88
108
|
end
|
|
89
109
|
|
|
90
|
-
def
|
|
110
|
+
def extract_receiver_and_argument(node)
|
|
91
111
|
if rails_env_on_lhs?(node)
|
|
92
|
-
|
|
112
|
+
[node.receiver, node.first_argument]
|
|
93
113
|
else
|
|
94
|
-
|
|
114
|
+
[node.first_argument, node.receiver]
|
|
95
115
|
end
|
|
96
116
|
end
|
|
97
117
|
|
|
98
118
|
def rails_env_on_lhs?(node)
|
|
99
|
-
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def build_predicate_method_for_rails_env_on_lhs(node)
|
|
103
|
-
bang = node.method?(:!=) ? '!' : ''
|
|
104
|
-
|
|
105
|
-
"#{bang}#{node.receiver.source}.#{content(node.first_argument)}?"
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def build_predicate_method_for_rails_env_on_rhs(node)
|
|
109
|
-
bang = node.method?(:!=) ? '!' : ''
|
|
110
|
-
|
|
111
|
-
"#{bang}#{node.first_argument.source}.#{content(node.receiver)}?"
|
|
119
|
+
comparing_env_with_rails_env_on_lhs?(node) || comparing_sym_env_with_rails_env_on_lhs?(node)
|
|
112
120
|
end
|
|
113
121
|
end
|
|
114
122
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Rails
|
|
6
|
-
# Enforces that `exit` calls are not used within a rails app.
|
|
6
|
+
# Enforces that `exit` and `abort` calls are not used within a rails app.
|
|
7
7
|
# Valid options are instead to raise an error, break, return, or some
|
|
8
8
|
# other form of stopping execution of current request.
|
|
9
9
|
#
|
|
@@ -26,12 +26,15 @@ module RuboCop
|
|
|
26
26
|
class Exit < Base
|
|
27
27
|
include ConfigurableEnforcedStyle
|
|
28
28
|
|
|
29
|
-
MSG = 'Do not use `
|
|
30
|
-
RESTRICT_ON_SEND = %i[exit exit!].freeze
|
|
29
|
+
MSG = 'Do not use `%<current>s` in Rails applications.'
|
|
30
|
+
RESTRICT_ON_SEND = %i[exit exit! abort].freeze
|
|
31
31
|
EXPLICIT_RECEIVERS = %i[Kernel Process].freeze
|
|
32
32
|
|
|
33
33
|
def on_send(node)
|
|
34
|
-
|
|
34
|
+
return unless offending_node?(node)
|
|
35
|
+
|
|
36
|
+
message = format(MSG, current: node.method_name)
|
|
37
|
+
add_offense(node.loc.selector, message: message)
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
private
|
|
@@ -190,7 +190,7 @@ module RuboCop
|
|
|
190
190
|
else
|
|
191
191
|
replace_with_rails_root_join(corrector, rails_root_node, argument_source)
|
|
192
192
|
end
|
|
193
|
-
node.children[rails_root_index + 1..].each { |child| corrector.remove(child) }
|
|
193
|
+
node.children[(rails_root_index + 1)..].each { |child| corrector.remove(child) }
|
|
194
194
|
end
|
|
195
195
|
|
|
196
196
|
def autocorrect_extension_after_rails_root_join_in_dstr(corrector, node, rails_root_index, extension_node)
|
|
@@ -281,7 +281,7 @@ module RuboCop
|
|
|
281
281
|
end
|
|
282
282
|
|
|
283
283
|
def extract_rails_root_join_argument_source(node, rails_root_index)
|
|
284
|
-
node.children[rails_root_index + 1..].map(&:source).join.delete_prefix(File::SEPARATOR)
|
|
284
|
+
node.children[(rails_root_index + 1)..].map(&:source).join.delete_prefix(File::SEPARATOR)
|
|
285
285
|
end
|
|
286
286
|
|
|
287
287
|
def extension_node?(node)
|