rubocop-rails 2.7.1 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/default.yml +45 -3
- data/lib/rubocop/cop/mixin/index_method.rb +17 -0
- data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +2 -4
- data/lib/rubocop/cop/rails/after_commit_override.rb +84 -0
- data/lib/rubocop/cop/rails/content_tag.rb +2 -2
- data/lib/rubocop/cop/rails/file_path.rb +1 -1
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -5
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +2 -0
- data/lib/rubocop/cop/rails/index_by.rb +8 -0
- data/lib/rubocop/cop/rails/index_with.rb +8 -0
- data/lib/rubocop/cop/rails/inquiry.rb +5 -1
- data/lib/rubocop/cop/rails/order_by_id.rb +53 -0
- data/lib/rubocop/cop/rails/pluck_in_where.rb +35 -1
- data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
- data/lib/rubocop/cop/rails/relative_date_constant.rb +5 -2
- data/lib/rubocop/cop/rails/reversible_migration.rb +79 -0
- data/lib/rubocop/cop/rails/save_bang.rb +2 -2
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +83 -0
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +2 -0
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +15 -7
- data/lib/rubocop/cop/rails/where_exists.rb +68 -5
- data/lib/rubocop/cop/rails/where_not.rb +106 -0
- data/lib/rubocop/cop/rails_cops.rb +4 -0
- data/lib/rubocop/rails/schema_loader/schema.rb +2 -4
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e89f00783e4dce6642e43ba4a4bf8ee29d078131f71404230db8fd2a1f87248
|
4
|
+
data.tar.gz: bfbca38eb400e89e260b572babc327afec01b25bad89178179e8276ef7ce651c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 241d43809d5cbfa4684fa83c1b92c9069447bae05ca0235d137e6934a2a9ad35ff3e00fba46928e793045ee1cf35dc3a520cca9f177e8c3280530282eb52ac06
|
7
|
+
data.tar.gz: 7019b400331651ad86a94e9562f93e31c32025ae5ed9c8c5da0f62c65974b21052438908a535da9314a6b903ea3ff6815dc7a0a6350ce3db9d6ab1d0ac18d015
|
data/config/default.yml
CHANGED
@@ -62,6 +62,14 @@ Rails/ActiveSupportAliases:
|
|
62
62
|
Enabled: true
|
63
63
|
VersionAdded: '0.48'
|
64
64
|
|
65
|
+
Rails/AfterCommitOverride:
|
66
|
+
Description: >-
|
67
|
+
This cop enforces that there is only one call to `after_commit`
|
68
|
+
(and its aliases - `after_create_commit`, `after_update_commit`,
|
69
|
+
and `after_destroy_commit`) with the same callback name per model.
|
70
|
+
Enabled: 'pending'
|
71
|
+
VersionAdded: '2.8'
|
72
|
+
|
65
73
|
Rails/ApplicationController:
|
66
74
|
Description: 'Check that controllers subclass ApplicationController.'
|
67
75
|
Enabled: true
|
@@ -313,14 +321,16 @@ Rails/IgnoredSkipActionFilterOption:
|
|
313
321
|
- app/controllers/**/*.rb
|
314
322
|
|
315
323
|
Rails/IndexBy:
|
316
|
-
Description: 'Prefer `index_by` over `each_with_object` or `map`.'
|
324
|
+
Description: 'Prefer `index_by` over `each_with_object`, `to_h`, or `map`.'
|
317
325
|
Enabled: true
|
318
326
|
VersionAdded: '2.5'
|
327
|
+
VersionChanged: '2.8'
|
319
328
|
|
320
329
|
Rails/IndexWith:
|
321
|
-
Description: 'Prefer `index_with` over `each_with_object` or `map`.'
|
330
|
+
Description: 'Prefer `index_with` over `each_with_object`, `to_h`, or `map`.'
|
322
331
|
Enabled: true
|
323
332
|
VersionAdded: '2.5'
|
333
|
+
VersionChanged: '2.8'
|
324
334
|
|
325
335
|
Rails/Inquiry:
|
326
336
|
Description: "Prefer Ruby's comparison operators over Active Support's `Array#inquiry` and `String#inquiry`."
|
@@ -357,6 +367,7 @@ Rails/MailerName:
|
|
357
367
|
Description: 'Mailer should end with `Mailer` suffix.'
|
358
368
|
StyleGuide: 'https://rails.rubystyle.guide/#mailer-name'
|
359
369
|
Enabled: 'pending'
|
370
|
+
SafeAutoCorrect: false
|
360
371
|
VersionAdded: '2.7'
|
361
372
|
Include:
|
362
373
|
- app/mailers/**/*.rb
|
@@ -385,6 +396,14 @@ Rails/NotNullColumn:
|
|
385
396
|
Include:
|
386
397
|
- db/migrate/*.rb
|
387
398
|
|
399
|
+
Rails/OrderById:
|
400
|
+
Description: >-
|
401
|
+
Do not use the `id` column for ordering.
|
402
|
+
Use a timestamp column to order chronologically.
|
403
|
+
StyleGuide: 'https://rails.rubystyle.guide/#order-by-id'
|
404
|
+
Enabled: false
|
405
|
+
VersionAdded: '2.8'
|
406
|
+
|
388
407
|
Rails/Output:
|
389
408
|
Description: 'Checks for calls to puts, print, etc.'
|
390
409
|
Enabled: true
|
@@ -426,6 +445,11 @@ Rails/PluckInWhere:
|
|
426
445
|
Enabled: 'pending'
|
427
446
|
Safe: false
|
428
447
|
VersionAdded: '2.7'
|
448
|
+
VersionChanged: '2.8'
|
449
|
+
EnforcedStyle: conservative
|
450
|
+
SupportedStyles:
|
451
|
+
- conservative
|
452
|
+
- aggressive
|
429
453
|
|
430
454
|
Rails/PluralizationGrammar:
|
431
455
|
Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.'
|
@@ -624,6 +648,12 @@ Rails/SkipsModelValidations:
|
|
624
648
|
- upsert_all
|
625
649
|
AllowedMethods: []
|
626
650
|
|
651
|
+
Rails/SquishedSQLHeredocs:
|
652
|
+
Description: 'Checks SQL heredocs to use `.squish`.'
|
653
|
+
StyleGuide: 'https://rails.rubystyle.guide/#squished-heredocs'
|
654
|
+
Enabled: 'pending'
|
655
|
+
VersionAdded: '2.8'
|
656
|
+
|
627
657
|
Rails/TimeZone:
|
628
658
|
Description: 'Checks the correct usage of time zone aware methods.'
|
629
659
|
StyleGuide: 'https://rails.rubystyle.guide#time'
|
@@ -643,11 +673,12 @@ Rails/UniqBeforePluck:
|
|
643
673
|
Description: 'Prefer the use of uniq or distinct before pluck.'
|
644
674
|
Enabled: true
|
645
675
|
VersionAdded: '0.40'
|
646
|
-
VersionChanged: '2.
|
676
|
+
VersionChanged: '2.8'
|
647
677
|
EnforcedStyle: conservative
|
648
678
|
SupportedStyles:
|
649
679
|
- conservative
|
650
680
|
- aggressive
|
681
|
+
SafeAutoCorrect: false
|
651
682
|
AutoCorrect: false
|
652
683
|
|
653
684
|
Rails/UniqueValidationWithoutIndex:
|
@@ -677,7 +708,18 @@ Rails/Validation:
|
|
677
708
|
Rails/WhereExists:
|
678
709
|
Description: 'Prefer `exists?(...)` over `where(...).exists?`.'
|
679
710
|
Enabled: 'pending'
|
711
|
+
EnforcedStyle: exists
|
712
|
+
SupportedStyles:
|
713
|
+
- exists
|
714
|
+
- where
|
680
715
|
VersionAdded: '2.7'
|
716
|
+
VersionChanged: '2.8'
|
717
|
+
|
718
|
+
Rails/WhereNot:
|
719
|
+
Description: 'Use `where.not(...)` instead of manually constructing negated SQL in `where`.'
|
720
|
+
StyleGuide: 'https://rails.rubystyle.guide/#where-not'
|
721
|
+
Enabled: 'pending'
|
722
|
+
VersionAdded: '2.8'
|
681
723
|
|
682
724
|
# Accept `redirect_to(...) and return` and similar cases.
|
683
725
|
Style/AndOr:
|
@@ -8,6 +8,12 @@ module RuboCop
|
|
8
8
|
on_bad_each_with_object(node) do |*match|
|
9
9
|
handle_possible_offense(node, match, 'each_with_object')
|
10
10
|
end
|
11
|
+
|
12
|
+
return if target_ruby_version < 2.6
|
13
|
+
|
14
|
+
on_bad_to_h(node) do |*match|
|
15
|
+
handle_possible_offense(node, match, 'to_h { ... }')
|
16
|
+
end
|
11
17
|
end
|
12
18
|
|
13
19
|
def on_send(node)
|
@@ -40,6 +46,11 @@ module RuboCop
|
|
40
46
|
raise NotImplementedError
|
41
47
|
end
|
42
48
|
|
49
|
+
# @abstract Implemented with `def_node_matcher`
|
50
|
+
def on_bad_to_h(_node)
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
|
43
54
|
# @abstract Implemented with `def_node_matcher`
|
44
55
|
def on_bad_map_to_h(_node)
|
45
56
|
raise NotImplementedError
|
@@ -73,6 +84,8 @@ module RuboCop
|
|
73
84
|
def prepare_correction(node)
|
74
85
|
if (match = on_bad_each_with_object(node))
|
75
86
|
Autocorrection.from_each_with_object(node, match)
|
87
|
+
elsif (match = on_bad_to_h(node))
|
88
|
+
Autocorrection.from_to_h(node, match)
|
76
89
|
elsif (match = on_bad_map_to_h(node))
|
77
90
|
Autocorrection.from_map_to_h(node, match)
|
78
91
|
elsif (match = on_bad_hash_brackets_map(node))
|
@@ -111,6 +124,10 @@ module RuboCop
|
|
111
124
|
new(match, node, 0, 0)
|
112
125
|
end
|
113
126
|
|
127
|
+
def self.from_to_h(node, match)
|
128
|
+
new(match, node, 0, 0)
|
129
|
+
end
|
130
|
+
|
114
131
|
def self.from_map_to_h(node, match)
|
115
132
|
strip_trailing_chars = 0
|
116
133
|
|
@@ -44,9 +44,7 @@ module RuboCop
|
|
44
44
|
after_touch
|
45
45
|
].freeze
|
46
46
|
|
47
|
-
CALLBACKS_ORDER_MAP =
|
48
|
-
CALLBACKS_IN_ORDER.map.with_index { |name, index| [name, index] }
|
49
|
-
].freeze
|
47
|
+
CALLBACKS_ORDER_MAP = CALLBACKS_IN_ORDER.each_with_index.to_h.freeze
|
50
48
|
|
51
49
|
def on_class(class_node)
|
52
50
|
previous_index = -1
|
@@ -68,7 +66,7 @@ module RuboCop
|
|
68
66
|
|
69
67
|
# Autocorrect by swapping between two nodes autocorrecting them
|
70
68
|
def autocorrect(node)
|
71
|
-
previous = left_siblings_of(node).find do |sibling|
|
69
|
+
previous = left_siblings_of(node).reverse_each.find do |sibling|
|
72
70
|
callback?(sibling)
|
73
71
|
end
|
74
72
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop enforces that there is only one call to `after_commit`
|
7
|
+
# (and its aliases - `after_create_commit`, `after_update_commit`,
|
8
|
+
# and `after_destroy_commit`) with the same callback name per model.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# # This won't be triggered.
|
13
|
+
# after_create_commit :log_action
|
14
|
+
#
|
15
|
+
# # This will override the callback added by
|
16
|
+
# # after_create_commit.
|
17
|
+
# after_update_commit :log_action
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# # This won't be triggered.
|
21
|
+
# after_commit :log_action, on: :create
|
22
|
+
# # This won't be triggered.
|
23
|
+
# after_update_commit :log_action
|
24
|
+
# # This will override both previous callbacks.
|
25
|
+
# after_commit :log_action, on: :destroy
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# after_save_commit :log_action
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# after_create_commit :log_create_action
|
32
|
+
# after_update_commit :log_update_action
|
33
|
+
#
|
34
|
+
class AfterCommitOverride < Cop
|
35
|
+
MSG = 'There can only be one `after_*_commit :%<name>s` hook defined for a model.'
|
36
|
+
|
37
|
+
AFTER_COMMIT_CALLBACKS = %i[
|
38
|
+
after_commit
|
39
|
+
after_create_commit
|
40
|
+
after_update_commit
|
41
|
+
after_save_commit
|
42
|
+
after_destroy_commit
|
43
|
+
].freeze
|
44
|
+
|
45
|
+
def on_class(class_node)
|
46
|
+
seen_callback_names = {}
|
47
|
+
|
48
|
+
each_after_commit_callback(class_node) do |node|
|
49
|
+
callback_name = node.arguments[0].value
|
50
|
+
if seen_callback_names.key?(callback_name)
|
51
|
+
add_offense(node, message: format(MSG, name: callback_name))
|
52
|
+
else
|
53
|
+
seen_callback_names[callback_name] = true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def each_after_commit_callback(class_node)
|
61
|
+
class_send_nodes(class_node).each do |node|
|
62
|
+
yield node if after_commit_callback?(node)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def class_send_nodes(class_node)
|
67
|
+
class_def = class_node.body
|
68
|
+
|
69
|
+
return [] unless class_def
|
70
|
+
|
71
|
+
if class_def.send_type?
|
72
|
+
[class_def]
|
73
|
+
else
|
74
|
+
class_def.each_child_node(:send).to_a
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def after_commit_callback?(node)
|
79
|
+
AFTER_COMMIT_CALLBACKS.include?(node.method_name)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
range = correction_range(node)
|
44
44
|
|
45
45
|
rest_args = node.arguments.drop(1)
|
46
|
-
replacement = "tag.#{node.first_argument.value}(#{rest_args.map(&:source).join(', ')})"
|
46
|
+
replacement = "tag.#{node.first_argument.value.to_s.underscore}(#{rest_args.map(&:source).join(', ')})"
|
47
47
|
|
48
48
|
corrector.replace(range, replacement)
|
49
49
|
else
|
@@ -57,7 +57,7 @@ module RuboCop
|
|
57
57
|
def method_name?(node)
|
58
58
|
return false unless node.str_type? || node.sym_type?
|
59
59
|
|
60
|
-
/^[a-zA-Z_][a-zA-
|
60
|
+
/^[a-zA-Z_][a-zA-Z_\-0-9]*$/.match?(node.value)
|
61
61
|
end
|
62
62
|
|
63
63
|
def correction_range(node)
|
@@ -52,11 +52,7 @@ module RuboCop
|
|
52
52
|
|
53
53
|
def on_send(node)
|
54
54
|
return if active_resource?(node.parent)
|
55
|
-
|
56
|
-
unless association_without_options?(node)
|
57
|
-
return if valid_options?(association_with_options?(node))
|
58
|
-
end
|
59
|
-
|
55
|
+
return if !association_without_options?(node) && valid_options?(association_with_options?(node))
|
60
56
|
return if valid_options_in_with_options_block?(node)
|
61
57
|
|
62
58
|
add_offense(node, location: :selector)
|
@@ -11,6 +11,7 @@ module RuboCop
|
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
13
|
# [1, 2, 3].each_with_object({}) { |el, h| h[foo(el)] = el }
|
14
|
+
# [1, 2, 3].to_h { |el| [foo(el), el] }
|
14
15
|
# [1, 2, 3].map { |el| [foo(el), el] }.to_h
|
15
16
|
# Hash[[1, 2, 3].collect { |el| [foo(el), el] }]
|
16
17
|
#
|
@@ -26,6 +27,13 @@ module RuboCop
|
|
26
27
|
({send csend} (lvar _memo) :[]= $_ (lvar _el)))
|
27
28
|
PATTERN
|
28
29
|
|
30
|
+
def_node_matcher :on_bad_to_h, <<~PATTERN
|
31
|
+
(block
|
32
|
+
({send csend} _ :to_h)
|
33
|
+
(args (arg $_el))
|
34
|
+
(array $_ (lvar _el)))
|
35
|
+
PATTERN
|
36
|
+
|
29
37
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
30
38
|
({send csend}
|
31
39
|
(block
|
@@ -11,6 +11,7 @@ module RuboCop
|
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
13
|
# [1, 2, 3].each_with_object({}) { |el, h| h[el] = foo(el) }
|
14
|
+
# [1, 2, 3].to_h { |el| [el, foo(el)] }
|
14
15
|
# [1, 2, 3].map { |el| [el, foo(el)] }.to_h
|
15
16
|
# Hash[[1, 2, 3].collect { |el| [el, foo(el)] }]
|
16
17
|
#
|
@@ -29,6 +30,13 @@ module RuboCop
|
|
29
30
|
({send csend} (lvar _memo) :[]= (lvar _el) $_))
|
30
31
|
PATTERN
|
31
32
|
|
33
|
+
def_node_matcher :on_bad_to_h, <<~PATTERN
|
34
|
+
(block
|
35
|
+
({send csend} _ :to_h)
|
36
|
+
(args (arg $_el))
|
37
|
+
(array (lvar _el) $_))
|
38
|
+
PATTERN
|
39
|
+
|
32
40
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
33
41
|
({send csend}
|
34
42
|
(block
|
@@ -26,7 +26,11 @@ module RuboCop
|
|
26
26
|
MSG = "Prefer Ruby's comparison operators over Active Support's `inquiry`."
|
27
27
|
|
28
28
|
def on_send(node)
|
29
|
-
|
29
|
+
return unless node.method?(:inquiry) && node.arguments.empty?
|
30
|
+
return unless (receiver = node.receiver)
|
31
|
+
return if !receiver.str_type? && !receiver.array_type?
|
32
|
+
|
33
|
+
add_offense(node, location: :selector)
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks for places where ordering by `id` column is used.
|
7
|
+
#
|
8
|
+
# Don't use the `id` column for ordering. The sequence of ids is not guaranteed
|
9
|
+
# to be in any particular order, despite often (incidentally) being chronological.
|
10
|
+
# Use a timestamp column to order chronologically. As a bonus the intent is clearer.
|
11
|
+
#
|
12
|
+
# NOTE: Make sure the changed order column does not introduce performance
|
13
|
+
# bottlenecks and appropriate database indexes are added.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# # bad
|
17
|
+
# scope :chronological, -> { order(id: :asc) }
|
18
|
+
# scope :chronological, -> { order(primary_key => :asc) }
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# scope :chronological, -> { order(created_at: :asc) }
|
22
|
+
#
|
23
|
+
class OrderById < Base
|
24
|
+
include RangeHelp
|
25
|
+
|
26
|
+
MSG = 'Do not use the `id` column for ordering. '\
|
27
|
+
'Use a timestamp column to order chronologically.'
|
28
|
+
|
29
|
+
def_node_matcher :order_by_id?, <<~PATTERN
|
30
|
+
(send _ :order
|
31
|
+
{
|
32
|
+
(sym :id)
|
33
|
+
(hash (pair (sym :id) _))
|
34
|
+
(send _ :primary_key)
|
35
|
+
(hash (pair (send _ :primary_key) _))
|
36
|
+
})
|
37
|
+
PATTERN
|
38
|
+
|
39
|
+
def on_send(node)
|
40
|
+
return unless node.method?(:order)
|
41
|
+
|
42
|
+
add_offense(offense_range(node)) if order_by_id?(node)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def offense_range(node)
|
48
|
+
range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -9,20 +9,42 @@ module RuboCop
|
|
9
9
|
# Since `pluck` is an eager method and hits the database immediately,
|
10
10
|
# using `select` helps to avoid additional database queries.
|
11
11
|
#
|
12
|
+
# This cop has two different enforcement modes. When the EnforcedStyle
|
13
|
+
# is conservative (the default) then only calls to `pluck` on a constant
|
14
|
+
# (i.e. a model class) in the `where` is used as offenses.
|
15
|
+
#
|
16
|
+
# When the EnforcedStyle is aggressive then all calls to `pluck` in the
|
17
|
+
# `where` is used as offenses. This may lead to false positives
|
18
|
+
# as the cop cannot replace to `select` between calls to `pluck` on an
|
19
|
+
# `ActiveRecord::Relation` instance vs a call to `pluck` on an `Array` instance.
|
20
|
+
#
|
12
21
|
# @example
|
13
22
|
# # bad
|
14
23
|
# Post.where(user_id: User.active.pluck(:id))
|
15
24
|
#
|
16
25
|
# # good
|
17
26
|
# Post.where(user_id: User.active.select(:id))
|
27
|
+
# Post.where(user_id: active_users.select(:id))
|
28
|
+
#
|
29
|
+
# @example EnforcedStyle: conservative (default)
|
30
|
+
# # good
|
31
|
+
# Post.where(user_id: active_users.pluck(:id))
|
32
|
+
#
|
33
|
+
# @example EnforcedStyle: aggressive
|
34
|
+
# # bad
|
35
|
+
# Post.where(user_id: active_users.pluck(:id))
|
18
36
|
#
|
19
37
|
class PluckInWhere < Cop
|
20
38
|
include ActiveRecordHelper
|
39
|
+
include ConfigurableEnforcedStyle
|
21
40
|
|
22
41
|
MSG = 'Use `select` instead of `pluck` within `where` query method.'
|
23
42
|
|
24
43
|
def on_send(node)
|
25
|
-
|
44
|
+
return unless node.method?(:pluck) && in_where?(node)
|
45
|
+
return if style == :conservative && !root_receiver(node)&.const_type?
|
46
|
+
|
47
|
+
add_offense(node, location: :selector)
|
26
48
|
end
|
27
49
|
|
28
50
|
def autocorrect(node)
|
@@ -30,6 +52,18 @@ module RuboCop
|
|
30
52
|
corrector.replace(node.loc.selector, 'select')
|
31
53
|
end
|
32
54
|
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def root_receiver(node)
|
59
|
+
receiver = node.receiver
|
60
|
+
|
61
|
+
if receiver&.send_type?
|
62
|
+
root_receiver(receiver)
|
63
|
+
else
|
64
|
+
receiver
|
65
|
+
end
|
66
|
+
end
|
33
67
|
end
|
34
68
|
end
|
35
69
|
end
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
MSG = 'Use a string value for `class_name`.'
|
18
18
|
|
19
19
|
def_node_matcher :association_with_reflection, <<~PATTERN
|
20
|
-
(send nil? {:has_many :has_one :belongs_to} _
|
20
|
+
(send nil? {:has_many :has_one :belongs_to} _ _ ?
|
21
21
|
(hash <$#reflection_class_name ...>)
|
22
22
|
)
|
23
23
|
PATTERN
|
@@ -49,8 +49,7 @@ module RuboCop
|
|
49
49
|
|
50
50
|
relative_date?(value) do |method_name|
|
51
51
|
add_offense(node,
|
52
|
-
location:
|
53
|
-
value.loc.expression.end_pos),
|
52
|
+
location: offense_range(name, value),
|
54
53
|
message: format(MSG, method_name: method_name))
|
55
54
|
end
|
56
55
|
end
|
@@ -77,6 +76,10 @@ module RuboCop
|
|
77
76
|
|
78
77
|
private
|
79
78
|
|
79
|
+
def offense_range(name, value)
|
80
|
+
range_between(name.loc.expression.begin_pos, value.loc.expression.end_pos)
|
81
|
+
end
|
82
|
+
|
80
83
|
def_node_matcher :relative_date_assignment?, <<~PATTERN
|
81
84
|
{
|
82
85
|
(casgn _ _ (send _ ${:since :from_now :after :ago :until :before}))
|
@@ -129,6 +129,51 @@ module RuboCop
|
|
129
129
|
# end
|
130
130
|
# end
|
131
131
|
#
|
132
|
+
# @example
|
133
|
+
# # remove_columns
|
134
|
+
#
|
135
|
+
# # bad
|
136
|
+
# def change
|
137
|
+
# remove_columns :users, :name, :email
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# # good
|
141
|
+
# def change
|
142
|
+
# reversible do |dir|
|
143
|
+
# dir.up do
|
144
|
+
# remove_columns :users, :name, :email
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
# dir.down do
|
148
|
+
# add_column :users, :name, :string
|
149
|
+
# add_column :users, :email, :string
|
150
|
+
# end
|
151
|
+
# end
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
# # good (Rails >= 6.1, see https://github.com/rails/rails/pull/36589)
|
155
|
+
# def change
|
156
|
+
# remove_columns :users, :name, :email, type: :string
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# @example
|
160
|
+
# # remove_index
|
161
|
+
#
|
162
|
+
# # bad
|
163
|
+
# def change
|
164
|
+
# remove_index :users, name: :index_users_on_email
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# # good
|
168
|
+
# def change
|
169
|
+
# remove_index :users, :email
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
# # good
|
173
|
+
# def change
|
174
|
+
# remove_index :users, column: :email
|
175
|
+
# end
|
176
|
+
#
|
132
177
|
# @see https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html
|
133
178
|
class ReversibleMigration < Cop
|
134
179
|
MSG = '%<action>s is not reversible.'
|
@@ -153,6 +198,14 @@ module RuboCop
|
|
153
198
|
(send nil? :change_table $_ ...)
|
154
199
|
PATTERN
|
155
200
|
|
201
|
+
def_node_matcher :remove_columns_call, <<~PATTERN
|
202
|
+
(send nil? :remove_columns ... $_)
|
203
|
+
PATTERN
|
204
|
+
|
205
|
+
def_node_matcher :remove_index_call, <<~PATTERN
|
206
|
+
(send nil? :remove_index _ $_)
|
207
|
+
PATTERN
|
208
|
+
|
156
209
|
def on_send(node)
|
157
210
|
return unless within_change_method?(node)
|
158
211
|
return if within_reversible_or_up_only_block?(node)
|
@@ -162,6 +215,8 @@ module RuboCop
|
|
162
215
|
check_reversible_hash_node(node)
|
163
216
|
check_remove_column_node(node)
|
164
217
|
check_remove_foreign_key_node(node)
|
218
|
+
check_remove_columns_node(node)
|
219
|
+
check_remove_index_node(node)
|
165
220
|
end
|
166
221
|
|
167
222
|
def on_block(node)
|
@@ -237,6 +292,30 @@ module RuboCop
|
|
237
292
|
end
|
238
293
|
end
|
239
294
|
|
295
|
+
def check_remove_columns_node(node)
|
296
|
+
remove_columns_call(node) do |args|
|
297
|
+
unless all_hash_key?(args, :type) && target_rails_version >= 6.1
|
298
|
+
action = target_rails_version >= 6.1 ? 'remove_columns(without type)' : 'remove_columns'
|
299
|
+
|
300
|
+
add_offense(
|
301
|
+
node,
|
302
|
+
message: format(MSG, action: action)
|
303
|
+
)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def check_remove_index_node(node)
|
309
|
+
remove_index_call(node) do |args|
|
310
|
+
if args.hash_type? && !all_hash_key?(args, :column)
|
311
|
+
add_offense(
|
312
|
+
node,
|
313
|
+
message: format(MSG, action: 'remove_index(without column)')
|
314
|
+
)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
240
319
|
def check_change_table_offense(receiver, node)
|
241
320
|
method_name = node.method_name
|
242
321
|
return if receiver != node.receiver &&
|
@@ -138,7 +138,7 @@ module RuboCop
|
|
138
138
|
add_offense_for_node(node, CREATE_MSG)
|
139
139
|
end
|
140
140
|
|
141
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
141
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
142
142
|
def on_send(node)
|
143
143
|
return unless persist_method?(node)
|
144
144
|
return if return_value_assigned?(node)
|
@@ -150,7 +150,7 @@ module RuboCop
|
|
150
150
|
|
151
151
|
add_offense_for_node(node)
|
152
152
|
end
|
153
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
153
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
154
154
|
alias on_csend on_send
|
155
155
|
|
156
156
|
def autocorrect(node)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
#
|
7
|
+
# Checks SQL heredocs to use `.squish`.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# <<-SQL
|
12
|
+
# SELECT * FROM posts;
|
13
|
+
# SQL
|
14
|
+
#
|
15
|
+
# <<-SQL
|
16
|
+
# SELECT * FROM posts
|
17
|
+
# WHERE id = 1
|
18
|
+
# SQL
|
19
|
+
#
|
20
|
+
# execute(<<~SQL, "Post Load")
|
21
|
+
# SELECT * FROM posts
|
22
|
+
# WHERE post_id = 1
|
23
|
+
# SQL
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# <<-SQL.squish
|
27
|
+
# SELECT * FROM posts;
|
28
|
+
# SQL
|
29
|
+
#
|
30
|
+
# <<~SQL.squish
|
31
|
+
# SELECT * FROM table
|
32
|
+
# WHERE id = 1
|
33
|
+
# SQL
|
34
|
+
#
|
35
|
+
# execute(<<~SQL.squish, "Post Load")
|
36
|
+
# SELECT * FROM posts
|
37
|
+
# WHERE post_id = 1
|
38
|
+
# SQL
|
39
|
+
#
|
40
|
+
class SquishedSQLHeredocs < Cop
|
41
|
+
include Heredoc
|
42
|
+
|
43
|
+
SQL = 'SQL'
|
44
|
+
SQUISH = '.squish'
|
45
|
+
MSG = 'Use `%<expect>s` instead of `%<current>s`.'
|
46
|
+
|
47
|
+
def on_heredoc(node)
|
48
|
+
return unless offense_detected?(node)
|
49
|
+
|
50
|
+
add_offense(node)
|
51
|
+
end
|
52
|
+
|
53
|
+
def autocorrect(node)
|
54
|
+
lambda do |corrector|
|
55
|
+
corrector.insert_after(node, SQUISH)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def offense_detected?(node)
|
62
|
+
sql_heredoc?(node) && !using_squish?(node)
|
63
|
+
end
|
64
|
+
|
65
|
+
def sql_heredoc?(node)
|
66
|
+
delimiter_string(node) == SQL
|
67
|
+
end
|
68
|
+
|
69
|
+
def using_squish?(node)
|
70
|
+
node.parent&.send_type? && node.parent&.method?(:squish)
|
71
|
+
end
|
72
|
+
|
73
|
+
def message(node)
|
74
|
+
format(
|
75
|
+
MSG,
|
76
|
+
expect: "#{node.source}#{SQUISH}",
|
77
|
+
current: node.source
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -18,6 +18,8 @@ module RuboCop
|
|
18
18
|
# ActiveRecord::Relation vs a call to pluck on an
|
19
19
|
# ActiveRecord::Associations::CollectionProxy.
|
20
20
|
#
|
21
|
+
# This cop is unsafe because the behavior may change depending on the
|
22
|
+
# database collation.
|
21
23
|
# Autocorrect is disabled by default for this cop since it may generate
|
22
24
|
# false positives.
|
23
25
|
#
|
@@ -34,23 +34,25 @@ module RuboCop
|
|
34
34
|
return unless uniqueness_part(node)
|
35
35
|
return if condition_part?(node)
|
36
36
|
return unless schema
|
37
|
-
|
37
|
+
|
38
|
+
klass, table, names = find_schema_information(node)
|
39
|
+
return unless names
|
40
|
+
return if with_index?(klass, table, names)
|
38
41
|
|
39
42
|
add_offense(node)
|
40
43
|
end
|
41
44
|
|
42
45
|
private
|
43
46
|
|
44
|
-
def
|
47
|
+
def find_schema_information(node)
|
45
48
|
klass = class_node(node)
|
46
|
-
return true unless klass # Skip analysis
|
47
|
-
|
48
49
|
table = schema.table_by(name: table_name(klass))
|
49
|
-
return true unless table # Skip analysis if it can't find the table
|
50
|
-
|
51
50
|
names = column_names(node)
|
52
|
-
return true unless names
|
53
51
|
|
52
|
+
[klass, table, names]
|
53
|
+
end
|
54
|
+
|
55
|
+
def with_index?(klass, table, names)
|
54
56
|
# Compatibility for Rails 4.2.
|
55
57
|
add_indicies = schema.add_indicies_by(table_name: table_name(klass))
|
56
58
|
|
@@ -95,6 +97,8 @@ module RuboCop
|
|
95
97
|
scope = find_scope(uniq)
|
96
98
|
return unless scope
|
97
99
|
|
100
|
+
scope = unfreeze_scope(scope)
|
101
|
+
|
98
102
|
case scope.type
|
99
103
|
when :sym, :str
|
100
104
|
[scope.value]
|
@@ -112,6 +116,10 @@ module RuboCop
|
|
112
116
|
end
|
113
117
|
end
|
114
118
|
|
119
|
+
def unfreeze_scope(scope)
|
120
|
+
scope.send_type? && scope.method?(:freeze) ? scope.children.first : scope
|
121
|
+
end
|
122
|
+
|
115
123
|
def class_node(node)
|
116
124
|
node.each_ancestor.find(&:class_type?)
|
117
125
|
end
|
@@ -3,9 +3,15 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
# This cop enforces
|
6
|
+
# This cop enforces consistent style when using `exists?`.
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# Two styles are supported for this cop. When EnforcedStyle is 'exists'
|
9
|
+
# then the cop enforces `exists?(...)` over `where(...).exists?`.
|
10
|
+
#
|
11
|
+
# When EnforcedStyle is 'where' then the cop enforces
|
12
|
+
# `where(...).exists?` over `exists?(...)`.
|
13
|
+
#
|
14
|
+
# @example EnforcedStyle: exists (default)
|
9
15
|
# # bad
|
10
16
|
# User.where(name: 'john').exists?
|
11
17
|
# User.where(['name = ?', 'john']).exists?
|
@@ -17,15 +23,34 @@ module RuboCop
|
|
17
23
|
# User.where('length(name) > 10').exists?
|
18
24
|
# user.posts.exists?(published: true)
|
19
25
|
#
|
26
|
+
# @example EnforcedStyle: where
|
27
|
+
# # bad
|
28
|
+
# User.exists?(name: 'john')
|
29
|
+
# User.exists?(['name = ?', 'john'])
|
30
|
+
# User.exists?('name = ?', 'john')
|
31
|
+
# user.posts.exists?(published: true)
|
32
|
+
#
|
33
|
+
# # good
|
34
|
+
# User.where(name: 'john').exists?
|
35
|
+
# User.where(['name = ?', 'john']).exists?
|
36
|
+
# User.where('name = ?', 'john').exists?
|
37
|
+
# user.posts.where(published: true).exists?
|
38
|
+
# User.where('length(name) > 10').exists?
|
20
39
|
class WhereExists < Cop
|
40
|
+
include ConfigurableEnforcedStyle
|
41
|
+
|
21
42
|
MSG = 'Prefer `%<good_method>s` over `%<bad_method>s`.'
|
22
43
|
|
23
44
|
def_node_matcher :where_exists_call?, <<~PATTERN
|
24
45
|
(send (send _ :where $...) :exists?)
|
25
46
|
PATTERN
|
26
47
|
|
48
|
+
def_node_matcher :exists_with_args?, <<~PATTERN
|
49
|
+
(send _ :exists? $...)
|
50
|
+
PATTERN
|
51
|
+
|
27
52
|
def on_send(node)
|
28
|
-
|
53
|
+
find_offenses(node) do |args|
|
29
54
|
return unless convertable_args?(args)
|
30
55
|
|
31
56
|
range = correction_range(node)
|
@@ -35,7 +60,7 @@ module RuboCop
|
|
35
60
|
end
|
36
61
|
|
37
62
|
def autocorrect(node)
|
38
|
-
args =
|
63
|
+
args = find_offenses(node)
|
39
64
|
|
40
65
|
lambda do |corrector|
|
41
66
|
corrector.replace(
|
@@ -47,21 +72,59 @@ module RuboCop
|
|
47
72
|
|
48
73
|
private
|
49
74
|
|
75
|
+
def where_style?
|
76
|
+
style == :where
|
77
|
+
end
|
78
|
+
|
79
|
+
def exists_style?
|
80
|
+
style == :exists
|
81
|
+
end
|
82
|
+
|
83
|
+
def find_offenses(node, &block)
|
84
|
+
if exists_style?
|
85
|
+
where_exists_call?(node, &block)
|
86
|
+
elsif where_style?
|
87
|
+
exists_with_args?(node, &block)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
50
91
|
def convertable_args?(args)
|
92
|
+
return false if args.empty?
|
93
|
+
|
51
94
|
args.size > 1 || args[0].hash_type? || args[0].array_type?
|
52
95
|
end
|
53
96
|
|
54
97
|
def correction_range(node)
|
55
|
-
|
98
|
+
if exists_style?
|
99
|
+
node.receiver.loc.selector.join(node.loc.selector)
|
100
|
+
elsif where_style?
|
101
|
+
node.loc.selector.with(end_pos: node.loc.expression.end_pos)
|
102
|
+
end
|
56
103
|
end
|
57
104
|
|
58
105
|
def build_good_method(args)
|
106
|
+
if exists_style?
|
107
|
+
build_good_method_exists(args)
|
108
|
+
elsif where_style?
|
109
|
+
build_good_method_where(args)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def build_good_method_exists(args)
|
59
114
|
if args.size > 1
|
60
115
|
"exists?([#{args.map(&:source).join(', ')}])"
|
61
116
|
else
|
62
117
|
"exists?(#{args[0].source})"
|
63
118
|
end
|
64
119
|
end
|
120
|
+
|
121
|
+
def build_good_method_where(args)
|
122
|
+
if args.size > 1
|
123
|
+
"where(#{args.map(&:source).join(', ')}).exists?"
|
124
|
+
else
|
125
|
+
"where(#{args[0].source}).exists?"
|
126
|
+
end
|
127
|
+
end
|
65
128
|
end
|
66
129
|
end
|
67
130
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop identifies places where manually constructed SQL
|
7
|
+
# in `where` can be replaced with `where.not(...)`.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# User.where('name != ?', 'Gabe')
|
12
|
+
# User.where('name != :name', name: 'Gabe')
|
13
|
+
# User.where('name IS NOT NULL')
|
14
|
+
# User.where('name NOT IN (?)', ['john', 'jane'])
|
15
|
+
# User.where('name NOT IN (:names)', names: ['john', 'jane'])
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# User.where.not(name: 'Gabe')
|
19
|
+
# User.where.not(name: nil)
|
20
|
+
# User.where.not(name: ['john', 'jane'])
|
21
|
+
#
|
22
|
+
class WhereNot < Cop
|
23
|
+
include RangeHelp
|
24
|
+
|
25
|
+
MSG = 'Use `%<good_method>s` instead of manually constructing negated SQL in `where`.'
|
26
|
+
|
27
|
+
def_node_matcher :where_method_call?, <<~PATTERN
|
28
|
+
{
|
29
|
+
(send _ :where (array $str_type? $_ ?))
|
30
|
+
(send _ :where $str_type? $_ ?)
|
31
|
+
}
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_send(node)
|
35
|
+
where_method_call?(node) do |template_node, value_node|
|
36
|
+
value_node = value_node.first
|
37
|
+
|
38
|
+
range = offense_range(node)
|
39
|
+
|
40
|
+
column_and_value = extract_column_and_value(template_node, value_node)
|
41
|
+
return unless column_and_value
|
42
|
+
|
43
|
+
good_method = build_good_method(*column_and_value)
|
44
|
+
message = format(MSG, good_method: good_method)
|
45
|
+
|
46
|
+
add_offense(node, location: range, message: message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def autocorrect(node)
|
51
|
+
where_method_call?(node) do |template_node, value_node|
|
52
|
+
value_node = value_node.first
|
53
|
+
|
54
|
+
lambda do |corrector|
|
55
|
+
range = offense_range(node)
|
56
|
+
|
57
|
+
column, value = *extract_column_and_value(template_node, value_node)
|
58
|
+
replacement = build_good_method(column, value)
|
59
|
+
|
60
|
+
corrector.replace(range, replacement)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
NOT_EQ_ANONYMOUS_RE = /\A([\w.]+)\s+!=\s+\?\z/.freeze # column != ?
|
66
|
+
NOT_IN_ANONYMOUS_RE = /\A([\w.]+)\s+NOT\s+IN\s+\(\?\)\z/i.freeze # column NOT IN (?)
|
67
|
+
NOT_EQ_NAMED_RE = /\A([\w.]+)\s+!=\s+:(\w+)\z/.freeze # column != :column
|
68
|
+
NOT_IN_NAMED_RE = /\A([\w.]+)\s+NOT\s+IN\s+\(:(\w+)\)\z/i.freeze # column NOT IN (:column)
|
69
|
+
IS_NOT_NULL_RE = /\A([\w.]+)\s+IS\s+NOT\s+NULL\z/i.freeze # column IS NOT NULL
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def offense_range(node)
|
74
|
+
range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
|
75
|
+
end
|
76
|
+
|
77
|
+
def extract_column_and_value(template_node, value_node)
|
78
|
+
value =
|
79
|
+
case template_node.value
|
80
|
+
when NOT_EQ_ANONYMOUS_RE, NOT_IN_ANONYMOUS_RE
|
81
|
+
value_node.source
|
82
|
+
when NOT_EQ_NAMED_RE, NOT_IN_NAMED_RE
|
83
|
+
return unless value_node.hash_type?
|
84
|
+
|
85
|
+
pair = value_node.pairs.find { |p| p.key.value.to_sym == Regexp.last_match(2).to_sym }
|
86
|
+
pair.value.source
|
87
|
+
when IS_NOT_NULL_RE
|
88
|
+
'nil'
|
89
|
+
else
|
90
|
+
return
|
91
|
+
end
|
92
|
+
|
93
|
+
[Regexp.last_match(1), value]
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_good_method(column, value)
|
97
|
+
if column.include?('.')
|
98
|
+
"where.not('#{column}' => #{value})"
|
99
|
+
else
|
100
|
+
"where.not(#{column}: #{value})"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -9,6 +9,7 @@ require_relative 'rails/active_record_aliases'
|
|
9
9
|
require_relative 'rails/active_record_callbacks_order'
|
10
10
|
require_relative 'rails/active_record_override'
|
11
11
|
require_relative 'rails/active_support_aliases'
|
12
|
+
require_relative 'rails/after_commit_override'
|
12
13
|
require_relative 'rails/application_controller'
|
13
14
|
require_relative 'rails/application_job'
|
14
15
|
require_relative 'rails/application_mailer'
|
@@ -48,6 +49,7 @@ require_relative 'rails/mailer_name'
|
|
48
49
|
require_relative 'rails/match_route'
|
49
50
|
require_relative 'rails/negate_include'
|
50
51
|
require_relative 'rails/not_null_column'
|
52
|
+
require_relative 'rails/order_by_id'
|
51
53
|
require_relative 'rails/output'
|
52
54
|
require_relative 'rails/output_safety'
|
53
55
|
require_relative 'rails/pick'
|
@@ -75,9 +77,11 @@ require_relative 'rails/save_bang'
|
|
75
77
|
require_relative 'rails/scope_args'
|
76
78
|
require_relative 'rails/short_i18n'
|
77
79
|
require_relative 'rails/skips_model_validations'
|
80
|
+
require_relative 'rails/squished_sql_heredocs'
|
78
81
|
require_relative 'rails/time_zone'
|
79
82
|
require_relative 'rails/uniq_before_pluck'
|
80
83
|
require_relative 'rails/unique_validation_without_index'
|
81
84
|
require_relative 'rails/unknown_env'
|
82
85
|
require_relative 'rails/validation'
|
83
86
|
require_relative 'rails/where_exists'
|
87
|
+
require_relative 'rails/where_not'
|
@@ -97,14 +97,12 @@ module RuboCop
|
|
97
97
|
end.compact
|
98
98
|
end
|
99
99
|
|
100
|
-
def each_content(node)
|
100
|
+
def each_content(node, &block)
|
101
101
|
return enum_for(__method__, node) unless block_given?
|
102
102
|
|
103
103
|
case node.body&.type
|
104
104
|
when :begin
|
105
|
-
node.body.children.each
|
106
|
-
yield(child)
|
107
|
-
end
|
105
|
+
node.body.children.each(&block)
|
108
106
|
else
|
109
107
|
yield(node.body)
|
110
108
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-
|
13
|
+
date: 2020-09-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- lib/rubocop/cop/rails/active_record_callbacks_order.rb
|
78
78
|
- lib/rubocop/cop/rails/active_record_override.rb
|
79
79
|
- lib/rubocop/cop/rails/active_support_aliases.rb
|
80
|
+
- lib/rubocop/cop/rails/after_commit_override.rb
|
80
81
|
- lib/rubocop/cop/rails/application_controller.rb
|
81
82
|
- lib/rubocop/cop/rails/application_job.rb
|
82
83
|
- lib/rubocop/cop/rails/application_mailer.rb
|
@@ -116,6 +117,7 @@ files:
|
|
116
117
|
- lib/rubocop/cop/rails/match_route.rb
|
117
118
|
- lib/rubocop/cop/rails/negate_include.rb
|
118
119
|
- lib/rubocop/cop/rails/not_null_column.rb
|
120
|
+
- lib/rubocop/cop/rails/order_by_id.rb
|
119
121
|
- lib/rubocop/cop/rails/output.rb
|
120
122
|
- lib/rubocop/cop/rails/output_safety.rb
|
121
123
|
- lib/rubocop/cop/rails/pick.rb
|
@@ -143,12 +145,14 @@ files:
|
|
143
145
|
- lib/rubocop/cop/rails/scope_args.rb
|
144
146
|
- lib/rubocop/cop/rails/short_i18n.rb
|
145
147
|
- lib/rubocop/cop/rails/skips_model_validations.rb
|
148
|
+
- lib/rubocop/cop/rails/squished_sql_heredocs.rb
|
146
149
|
- lib/rubocop/cop/rails/time_zone.rb
|
147
150
|
- lib/rubocop/cop/rails/uniq_before_pluck.rb
|
148
151
|
- lib/rubocop/cop/rails/unique_validation_without_index.rb
|
149
152
|
- lib/rubocop/cop/rails/unknown_env.rb
|
150
153
|
- lib/rubocop/cop/rails/validation.rb
|
151
154
|
- lib/rubocop/cop/rails/where_exists.rb
|
155
|
+
- lib/rubocop/cop/rails/where_not.rb
|
152
156
|
- lib/rubocop/cop/rails_cops.rb
|
153
157
|
- lib/rubocop/rails.rb
|
154
158
|
- lib/rubocop/rails/inject.rb
|