rubocop-rails 2.30.2 → 2.33.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/README.md +2 -1
- data/config/default.yml +87 -49
- data/lib/rubocop/cop/mixin/active_record_helper.rb +2 -2
- data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +2 -2
- data/lib/rubocop/cop/mixin/database_type_resolvable.rb +2 -2
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +6 -1
- data/lib/rubocop/cop/mixin/index_method.rb +6 -1
- data/lib/rubocop/cop/rails/arel_star.rb +5 -5
- data/lib/rubocop/cop/rails/delegate.rb +7 -4
- data/lib/rubocop/cop/rails/duplicate_association.rb +1 -1
- data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +1 -3
- data/lib/rubocop/cop/rails/env_local.rb +50 -26
- data/lib/rubocop/cop/rails/file_path.rb +2 -2
- data/lib/rubocop/cop/rails/find_by_or_assignment_memoization.rb +65 -0
- data/lib/rubocop/cop/rails/index_by.rb +9 -0
- data/lib/rubocop/cop/rails/index_with.rb +14 -0
- data/lib/rubocop/cop/rails/order_arguments.rb +79 -0
- data/lib/rubocop/cop/rails/output.rb +4 -2
- data/lib/rubocop/cop/rails/pluck.rb +13 -4
- 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 +7 -2
- data/lib/rubocop/cop/rails/reflection_class_name.rb +2 -2
- data/lib/rubocop/cop/rails/relative_date_constant.rb +1 -1
- data/lib/rubocop/cop/rails/reversible_migration.rb +2 -1
- data/lib/rubocop/cop/rails/save_bang.rb +4 -4
- data/lib/rubocop/cop/rails/schema_comment.rb +1 -1
- data/lib/rubocop/cop/rails/three_state_boolean_column.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +3 -1
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +5 -3
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +1 -1
- data/lib/rubocop/cop/rails/where_exists.rb +2 -2
- data/lib/rubocop/cop/rails_cops.rb +2 -0
- data/lib/rubocop/rails/version.rb +1 -1
- data/lib/rubocop-rails.rb +0 -1
- metadata +10 -8
|
@@ -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
|
|
@@ -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)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Rails
|
|
6
|
+
# Avoid memoizing `find_by` results with `||=`.
|
|
7
|
+
#
|
|
8
|
+
# It is common to see code that attempts to memoize `find_by` result by `||=`,
|
|
9
|
+
# but `find_by` may return `nil`, in which case it is not memoized as intended.
|
|
10
|
+
#
|
|
11
|
+
# @safety
|
|
12
|
+
# This cop is unsafe because detected `find_by` may not be Active Record's method,
|
|
13
|
+
# or the code may have a different purpose than memoization.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# # bad
|
|
17
|
+
# def current_user
|
|
18
|
+
# @current_user ||= User.find_by(id: session[:user_id])
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# # good
|
|
22
|
+
# def current_user
|
|
23
|
+
# if instance_variable_defined?(:@current_user)
|
|
24
|
+
# @current_user
|
|
25
|
+
# else
|
|
26
|
+
# @current_user = User.find_by(id: session[:user_id])
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
class FindByOrAssignmentMemoization < Base
|
|
30
|
+
extend AutoCorrector
|
|
31
|
+
|
|
32
|
+
MSG = 'Avoid memoizing `find_by` results with `||=`.'
|
|
33
|
+
|
|
34
|
+
RESTRICT_ON_SEND = %i[find_by].freeze
|
|
35
|
+
|
|
36
|
+
def_node_matcher :find_by_or_assignment_memoization, <<~PATTERN
|
|
37
|
+
(or_asgn
|
|
38
|
+
(ivasgn $_)
|
|
39
|
+
$(send _ :find_by ...)
|
|
40
|
+
)
|
|
41
|
+
PATTERN
|
|
42
|
+
|
|
43
|
+
def on_send(node)
|
|
44
|
+
assignment_node = node.parent
|
|
45
|
+
find_by_or_assignment_memoization(assignment_node) do |varible_name, find_by|
|
|
46
|
+
next if assignment_node.each_ancestor(:if).any?
|
|
47
|
+
|
|
48
|
+
add_offense(assignment_node) do |corrector|
|
|
49
|
+
corrector.replace(
|
|
50
|
+
assignment_node,
|
|
51
|
+
<<~RUBY.rstrip
|
|
52
|
+
if instance_variable_defined?(:#{varible_name})
|
|
53
|
+
#{varible_name}
|
|
54
|
+
else
|
|
55
|
+
#{varible_name} = #{find_by.source}
|
|
56
|
+
end
|
|
57
|
+
RUBY
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -37,6 +37,9 @@ module RuboCop
|
|
|
37
37
|
(numblock
|
|
38
38
|
(call _ :to_h) $1
|
|
39
39
|
(array $_ (lvar :_1)))
|
|
40
|
+
(itblock
|
|
41
|
+
(call _ :to_h) $:it
|
|
42
|
+
(array $_ (lvar :it)))
|
|
40
43
|
}
|
|
41
44
|
PATTERN
|
|
42
45
|
|
|
@@ -50,6 +53,9 @@ module RuboCop
|
|
|
50
53
|
(numblock
|
|
51
54
|
(call _ {:map :collect}) $1
|
|
52
55
|
(array $_ (lvar :_1)))
|
|
56
|
+
(itblock
|
|
57
|
+
(call _ {:map :collect}) $:it
|
|
58
|
+
(array $_ (lvar :it)))
|
|
53
59
|
}
|
|
54
60
|
:to_h)
|
|
55
61
|
PATTERN
|
|
@@ -66,6 +72,9 @@ module RuboCop
|
|
|
66
72
|
(numblock
|
|
67
73
|
(call _ {:map :collect}) $1
|
|
68
74
|
(array $_ (lvar :_1)))
|
|
75
|
+
(itblock
|
|
76
|
+
(call _ {:map :collect}) $:it
|
|
77
|
+
(array $_ (lvar :it)))
|
|
69
78
|
}
|
|
70
79
|
)
|
|
71
80
|
PATTERN
|
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
|
8
8
|
# an enumerable into a hash where the keys are the original elements.
|
|
9
9
|
# Rails provides the `index_with` method for this purpose.
|
|
10
10
|
#
|
|
11
|
+
# @safety
|
|
12
|
+
# This cop is marked as unsafe autocorrection, because `nil.to_h` returns {}
|
|
13
|
+
# but `nil.with_index` throws `NoMethodError`. Therefore, autocorrection is not
|
|
14
|
+
# compatible if the receiver is nil.
|
|
15
|
+
#
|
|
11
16
|
# @example
|
|
12
17
|
# # bad
|
|
13
18
|
# [1, 2, 3].each_with_object({}) { |el, h| h[el] = foo(el) }
|
|
@@ -40,6 +45,9 @@ module RuboCop
|
|
|
40
45
|
(numblock
|
|
41
46
|
(call _ :to_h) $1
|
|
42
47
|
(array (lvar :_1) $_))
|
|
48
|
+
(itblock
|
|
49
|
+
(call _ :to_h) $:it
|
|
50
|
+
(array (lvar :it) $_))
|
|
43
51
|
}
|
|
44
52
|
PATTERN
|
|
45
53
|
|
|
@@ -53,6 +61,9 @@ module RuboCop
|
|
|
53
61
|
(numblock
|
|
54
62
|
(call _ {:map :collect}) $1
|
|
55
63
|
(array (lvar :_1) $_))
|
|
64
|
+
(itblock
|
|
65
|
+
(call _ {:map :collect}) $:it
|
|
66
|
+
(array (lvar :it) $_))
|
|
56
67
|
}
|
|
57
68
|
:to_h)
|
|
58
69
|
PATTERN
|
|
@@ -69,6 +80,9 @@ module RuboCop
|
|
|
69
80
|
(numblock
|
|
70
81
|
(call _ {:map :collect}) $1
|
|
71
82
|
(array (lvar :_1) $_))
|
|
83
|
+
(itblock
|
|
84
|
+
(call _ {:map :collect}) $:it
|
|
85
|
+
(array (lvar :it) $_))
|
|
72
86
|
}
|
|
73
87
|
)
|
|
74
88
|
PATTERN
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Rails
|
|
6
|
+
# Prefer symbol arguments over strings in `order` method.
|
|
7
|
+
#
|
|
8
|
+
# @safety
|
|
9
|
+
# Cop is unsafe because the receiver might not be an Active Record query.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# # bad
|
|
13
|
+
# User.order('name')
|
|
14
|
+
# User.order('name DESC')
|
|
15
|
+
#
|
|
16
|
+
# # good
|
|
17
|
+
# User.order(:name)
|
|
18
|
+
# User.order(name: :desc)
|
|
19
|
+
#
|
|
20
|
+
class OrderArguments < Base
|
|
21
|
+
extend AutoCorrector
|
|
22
|
+
|
|
23
|
+
MSG = 'Prefer `%<prefer>s` instead.'
|
|
24
|
+
|
|
25
|
+
RESTRICT_ON_SEND = %i[order].freeze
|
|
26
|
+
|
|
27
|
+
def_node_matcher :string_order, <<~PATTERN
|
|
28
|
+
(call _ :order (str $_value)+)
|
|
29
|
+
PATTERN
|
|
30
|
+
|
|
31
|
+
ORDER_EXPRESSION_REGEX = /\A(\w+) ?(asc|desc)?\z/i.freeze
|
|
32
|
+
|
|
33
|
+
def on_send(node)
|
|
34
|
+
return unless (current_expressions = string_order(node))
|
|
35
|
+
return unless (preferred_expressions = replacement(current_expressions))
|
|
36
|
+
|
|
37
|
+
offense_range = find_offense_range(node)
|
|
38
|
+
add_offense(offense_range, message: format(MSG, prefer: preferred_expressions)) do |corrector|
|
|
39
|
+
corrector.replace(offense_range, preferred_expressions)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
alias on_csend on_send
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def find_offense_range(node)
|
|
47
|
+
node.first_argument.source_range.join(node.last_argument.source_range)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def replacement(order_expressions)
|
|
51
|
+
order_arguments = order_expressions.flat_map { |expr| expr.split(',') }
|
|
52
|
+
order_arguments.map! { |arg| extract_column_and_direction(arg.strip) }
|
|
53
|
+
|
|
54
|
+
return if order_arguments.any?(&:nil?)
|
|
55
|
+
|
|
56
|
+
convert_to_preferred_arguments(order_arguments).join(', ')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def convert_to_preferred_arguments(order_expressions)
|
|
60
|
+
use_hash = false
|
|
61
|
+
order_expressions.map do |column, direction|
|
|
62
|
+
if direction == :asc && !use_hash
|
|
63
|
+
":#{column}"
|
|
64
|
+
else
|
|
65
|
+
use_hash = true
|
|
66
|
+
"#{column}: :#{direction}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def extract_column_and_direction(order_expression)
|
|
72
|
+
return unless (column, direction = ORDER_EXPRESSION_REGEX.match(order_expression)&.captures)
|
|
73
|
+
|
|
74
|
+
[column.downcase, direction&.downcase&.to_sym || :asc]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -23,7 +23,6 @@ module RuboCop
|
|
|
23
23
|
|
|
24
24
|
MSG = "Do not write to stdout. Use Rails's logger if you want to log."
|
|
25
25
|
RESTRICT_ON_SEND = %i[ap p pp pretty_print print puts binwrite syswrite write write_nonblock].freeze
|
|
26
|
-
ALLOWED_TYPES = %i[send csend block numblock].freeze
|
|
27
26
|
|
|
28
27
|
def_node_matcher :output?, <<~PATTERN
|
|
29
28
|
(send nil? {:ap :p :pp :pretty_print :print :puts} ...)
|
|
@@ -39,9 +38,11 @@ module RuboCop
|
|
|
39
38
|
...)
|
|
40
39
|
PATTERN
|
|
41
40
|
|
|
41
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
42
42
|
def on_send(node)
|
|
43
|
-
return if
|
|
43
|
+
return if node.parent&.call_type? || node.block_node
|
|
44
44
|
return if !output?(node) && !io_output?(node)
|
|
45
|
+
return if node.arguments.any? { |arg| arg.type?(:hash, :block_pass) }
|
|
45
46
|
|
|
46
47
|
range = offense_range(node)
|
|
47
48
|
|
|
@@ -49,6 +50,7 @@ module RuboCop
|
|
|
49
50
|
corrector.replace(range, 'Rails.logger.debug')
|
|
50
51
|
end
|
|
51
52
|
end
|
|
53
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
52
54
|
|
|
53
55
|
private
|
|
54
56
|
|
|
@@ -27,6 +27,9 @@ module RuboCop
|
|
|
27
27
|
# end
|
|
28
28
|
# ----
|
|
29
29
|
#
|
|
30
|
+
# If a method call has no receiver, like `do_something { users.map { |user| user[:foo] }`,
|
|
31
|
+
# it is not considered part of an iteration and will be detected.
|
|
32
|
+
#
|
|
30
33
|
# @safety
|
|
31
34
|
# This cop is unsafe because model can use column aliases.
|
|
32
35
|
#
|
|
@@ -59,8 +62,9 @@ module RuboCop
|
|
|
59
62
|
(any_block (call _ {:map :collect}) $_argument (send lvar :[] $_key))
|
|
60
63
|
PATTERN
|
|
61
64
|
|
|
65
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
62
66
|
def on_block(node)
|
|
63
|
-
return if node.each_ancestor(:
|
|
67
|
+
return if node.each_ancestor(:any_block).first&.receiver
|
|
64
68
|
|
|
65
69
|
pluck_candidate?(node) do |argument, key|
|
|
66
70
|
next if key.regexp_type? || !use_one_block_argument?(argument)
|
|
@@ -68,20 +72,25 @@ module RuboCop
|
|
|
68
72
|
match = if node.block_type?
|
|
69
73
|
block_argument = argument.children.first.source
|
|
70
74
|
use_block_argument_in_key?(block_argument, key)
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
elsif node.numblock_type?
|
|
76
|
+
use_block_argument_in_key?('_1', key)
|
|
77
|
+
else # itblock
|
|
78
|
+
use_block_argument_in_key?('it', key)
|
|
73
79
|
end
|
|
74
80
|
next unless match
|
|
75
81
|
|
|
76
82
|
register_offense(node, key)
|
|
77
83
|
end
|
|
78
84
|
end
|
|
85
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
79
86
|
alias on_numblock on_block
|
|
87
|
+
alias on_itblock on_block
|
|
80
88
|
|
|
81
89
|
private
|
|
82
90
|
|
|
83
91
|
def use_one_block_argument?(argument)
|
|
84
|
-
|
|
92
|
+
# Checks for numbered argument `_1` or `it block parameter.
|
|
93
|
+
return true if [1, :it].include?(argument)
|
|
85
94
|
|
|
86
95
|
argument.respond_to?(:one?) && argument.one?
|
|
87
96
|
end
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
|
74
74
|
$[
|
|
75
75
|
(hash <$(pair (sym :presence) true) ...>) # presence: true
|
|
76
76
|
!(hash <$(pair (sym :strict) {true const}) ...>) # strict: true
|
|
77
|
-
!(hash <$(pair (sym {:if
|
|
77
|
+
!(hash <$(pair (sym {:if}) _) ...>) # if: some_condition or unless: some_condition
|
|
78
78
|
]
|
|
79
79
|
)
|
|
80
80
|
PATTERN
|
|
@@ -211,12 +211,12 @@ module RuboCop
|
|
|
211
211
|
|
|
212
212
|
def non_optional_belongs_to(node, keys)
|
|
213
213
|
keys.select do |key|
|
|
214
|
-
belongs_to = belongs_to_for(node, key)
|
|
214
|
+
belongs_to = belongs_to_for?(node, key)
|
|
215
215
|
belongs_to && !optional?(belongs_to)
|
|
216
216
|
end
|
|
217
217
|
end
|
|
218
218
|
|
|
219
|
-
def belongs_to_for(model_class_node, key)
|
|
219
|
+
def belongs_to_for?(model_class_node, key)
|
|
220
220
|
if key.to_s.end_with?('_id')
|
|
221
221
|
normalized_key = key.to_s.delete_suffix('_id').to_sym
|
|
222
222
|
belongs_to?(model_class_node, key: normalized_key, fk: key)
|
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
|
71
71
|
def on_block(node)
|
|
72
72
|
return unless node.method?(:with_options)
|
|
73
73
|
return unless (body = node.body)
|
|
74
|
-
return unless all_block_nodes_in(body).
|
|
74
|
+
return unless all_block_nodes_in(body).none?
|
|
75
75
|
|
|
76
76
|
send_nodes = all_send_nodes_in(body)
|
|
77
77
|
return unless redundant_receiver?(send_nodes, node)
|
|
@@ -85,18 +85,22 @@ module RuboCop
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
alias on_numblock on_block
|
|
88
|
+
alias on_itblock on_block
|
|
88
89
|
|
|
89
90
|
private
|
|
90
91
|
|
|
91
92
|
def autocorrect(corrector, send_node, node)
|
|
92
93
|
corrector.remove(send_node.receiver)
|
|
93
94
|
corrector.remove(send_node.loc.dot)
|
|
94
|
-
corrector.remove(block_argument_range(send_node))
|
|
95
|
+
corrector.remove(block_argument_range(send_node)) if node.block_type?
|
|
95
96
|
end
|
|
96
97
|
|
|
98
|
+
# rubocop:disable Metrics/AbcSize
|
|
97
99
|
def redundant_receiver?(send_nodes, node)
|
|
98
100
|
proc = if node.numblock_type?
|
|
99
101
|
->(n) { n.receiver.lvar_type? && n.receiver.source == '_1' }
|
|
102
|
+
elsif node.itblock_type?
|
|
103
|
+
->(n) { n.receiver.lvar_type? && n.receiver.source == 'it' }
|
|
100
104
|
else
|
|
101
105
|
return false if node.arguments.empty?
|
|
102
106
|
|
|
@@ -106,6 +110,7 @@ module RuboCop
|
|
|
106
110
|
|
|
107
111
|
send_nodes.all?(&proc)
|
|
108
112
|
end
|
|
113
|
+
# rubocop:enable Metrics/AbcSize
|
|
109
114
|
|
|
110
115
|
def block_argument_range(node)
|
|
111
116
|
block_node = node.each_ancestor(:block).first
|
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
|
40
40
|
|
|
41
41
|
def on_send(node)
|
|
42
42
|
association_with_reflection(node) do |reflection_class_name|
|
|
43
|
-
return if reflection_class_name.value.send_type? && reflection_class_name.value.receiver
|
|
43
|
+
return if reflection_class_name.value.send_type? && !reflection_class_name.value.receiver&.const_type?
|
|
44
44
|
return if reflection_class_name.value.lvar_type? && str_assigned?(reflection_class_name)
|
|
45
45
|
|
|
46
46
|
add_offense(reflection_class_name) do |corrector|
|
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
|
76
76
|
def autocorrect(corrector, class_config)
|
|
77
77
|
class_value = class_config.value
|
|
78
78
|
replacement = const_or_string(class_value)
|
|
79
|
-
return unless replacement
|
|
79
|
+
return unless replacement
|
|
80
80
|
|
|
81
81
|
corrector.replace(class_value, replacement.source.inspect)
|
|
82
82
|
end
|
|
@@ -205,6 +205,7 @@ module RuboCop
|
|
|
205
205
|
end
|
|
206
206
|
|
|
207
207
|
alias on_numblock on_block
|
|
208
|
+
alias on_itblock on_block
|
|
208
209
|
|
|
209
210
|
private
|
|
210
211
|
|
|
@@ -218,7 +219,7 @@ module RuboCop
|
|
|
218
219
|
return unless (last_argument = node.last_argument)
|
|
219
220
|
|
|
220
221
|
drop_table_call(node) do
|
|
221
|
-
unless node.parent.
|
|
222
|
+
unless node.parent.any_block_type? || last_argument.block_pass_type?
|
|
222
223
|
add_offense(node, message: format(MSG, action: 'drop_table(without block)'))
|
|
223
224
|
end
|
|
224
225
|
end
|
|
@@ -156,7 +156,7 @@ module RuboCop
|
|
|
156
156
|
return unless persist_method?(node)
|
|
157
157
|
return if return_value_assigned?(node)
|
|
158
158
|
return if implicit_return?(node)
|
|
159
|
-
return if check_used_in_condition_or_compound_boolean(node)
|
|
159
|
+
return if check_used_in_condition_or_compound_boolean?(node)
|
|
160
160
|
return if argument?(node)
|
|
161
161
|
return if explicit_return?(node)
|
|
162
162
|
return if checked_immediately?(node)
|
|
@@ -182,7 +182,7 @@ module RuboCop
|
|
|
182
182
|
def right_assignment_node(assignment)
|
|
183
183
|
node = assignment.node.child_nodes.first
|
|
184
184
|
|
|
185
|
-
return node unless node&.
|
|
185
|
+
return node unless node&.any_block_type?
|
|
186
186
|
|
|
187
187
|
node.send_node
|
|
188
188
|
end
|
|
@@ -227,7 +227,7 @@ module RuboCop
|
|
|
227
227
|
array
|
|
228
228
|
end
|
|
229
229
|
|
|
230
|
-
def check_used_in_condition_or_compound_boolean(node)
|
|
230
|
+
def check_used_in_condition_or_compound_boolean?(node)
|
|
231
231
|
return false unless in_condition_or_compound_boolean?(node)
|
|
232
232
|
|
|
233
233
|
register_offense(node, CREATE_CONDITIONAL_MSG) unless MODIFY_PERSIST_METHODS.include?(node.method_name)
|
|
@@ -305,7 +305,7 @@ module RuboCop
|
|
|
305
305
|
|
|
306
306
|
node = assignable_node(node)
|
|
307
307
|
method, sibling_index = find_method_with_sibling_index(node.parent)
|
|
308
|
-
return false unless method&.type?(:def, :
|
|
308
|
+
return false unless method&.type?(:def, :any_block)
|
|
309
309
|
|
|
310
310
|
method.children.size == node.sibling_index + sibling_index
|
|
311
311
|
end
|
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
|
39
39
|
|
|
40
40
|
# @!method comment_present?(node)
|
|
41
41
|
def_node_matcher :comment_present?, <<~PATTERN
|
|
42
|
-
(hash <(pair {(sym :comment) (str "comment")} (
|
|
42
|
+
(hash <(pair {(sym :comment) (str "comment")} !{nil (str blank?)}) ...>)
|
|
43
43
|
PATTERN
|
|
44
44
|
|
|
45
45
|
# @!method add_column?(node)
|
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
|
45
45
|
|
|
46
46
|
return if required_options?(options_node)
|
|
47
47
|
|
|
48
|
-
def_node = node.each_ancestor(:
|
|
48
|
+
def_node = node.each_ancestor(:any_def).first
|
|
49
49
|
table_node = table_node(node)
|
|
50
50
|
return if def_node && (table_node.nil? || change_column_null?(def_node, table_node, column_node))
|
|
51
51
|
|
|
@@ -135,7 +135,9 @@ module RuboCop
|
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
def attach_timezone_specifier?(date)
|
|
138
|
-
date.respond_to?(:value)
|
|
138
|
+
return false unless date.respond_to?(:value)
|
|
139
|
+
|
|
140
|
+
!date.value.to_s.valid_encoding? || TIMEZONE_SPECIFIER.match?(date.value.to_s)
|
|
139
141
|
end
|
|
140
142
|
|
|
141
143
|
def build_message(klass, method_name, node)
|
|
@@ -97,9 +97,11 @@ module RuboCop
|
|
|
97
97
|
|
|
98
98
|
def in_transaction_block?(node)
|
|
99
99
|
return false unless transaction_method_name?(node.method_name)
|
|
100
|
-
return false unless
|
|
100
|
+
return false unless node.parent&.body
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
node.right_siblings.none? do |sibling|
|
|
103
|
+
sibling.respond_to?(:loop_keyword?) && sibling.loop_keyword?
|
|
104
|
+
end
|
|
103
105
|
end
|
|
104
106
|
|
|
105
107
|
def statement(statement_node)
|
|
@@ -113,7 +115,7 @@ module RuboCop
|
|
|
113
115
|
end
|
|
114
116
|
|
|
115
117
|
def nested_block?(statement_node)
|
|
116
|
-
name = statement_node.ancestors.find(&:
|
|
118
|
+
name = statement_node.ancestors.find(&:any_block_type?).children.first.method_name
|
|
117
119
|
!transaction_method_name?(name)
|
|
118
120
|
end
|
|
119
121
|
|
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
|
52
52
|
MSG = 'Use `distinct` before `pluck`.'
|
|
53
53
|
RESTRICT_ON_SEND = %i[uniq].freeze
|
|
54
54
|
|
|
55
|
-
def_node_matcher :uniq_before_pluck, '[!^
|
|
55
|
+
def_node_matcher :uniq_before_pluck, '[!^any_block $(send $(send _ :pluck ...) :uniq ...)]'
|
|
56
56
|
|
|
57
57
|
def on_send(node)
|
|
58
58
|
uniq_before_pluck(node) do |uniq_node, pluck_node|
|
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
|
63
63
|
PATTERN
|
|
64
64
|
|
|
65
65
|
def on_send(node)
|
|
66
|
-
find_offenses(node) do |args|
|
|
66
|
+
find_offenses?(node) do |args|
|
|
67
67
|
return unless convertable_args?(args)
|
|
68
68
|
|
|
69
69
|
range = correction_range(node)
|
|
@@ -87,7 +87,7 @@ module RuboCop
|
|
|
87
87
|
style == :exists
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
def find_offenses(node, &block)
|
|
90
|
+
def find_offenses?(node, &block)
|
|
91
91
|
if exists_style?
|
|
92
92
|
where_exists_call?(node, &block)
|
|
93
93
|
elsif where_style?
|
|
@@ -58,6 +58,7 @@ require_relative 'rails/expanded_date_range'
|
|
|
58
58
|
require_relative 'rails/file_path'
|
|
59
59
|
require_relative 'rails/find_by'
|
|
60
60
|
require_relative 'rails/find_by_id'
|
|
61
|
+
require_relative 'rails/find_by_or_assignment_memoization'
|
|
61
62
|
require_relative 'rails/find_each'
|
|
62
63
|
require_relative 'rails/freeze_time'
|
|
63
64
|
require_relative 'rails/has_and_belongs_to_many'
|
|
@@ -82,6 +83,7 @@ require_relative 'rails/migration_class_name'
|
|
|
82
83
|
require_relative 'rails/multiple_route_paths'
|
|
83
84
|
require_relative 'rails/negate_include'
|
|
84
85
|
require_relative 'rails/not_null_column'
|
|
86
|
+
require_relative 'rails/order_arguments'
|
|
85
87
|
require_relative 'rails/order_by_id'
|
|
86
88
|
require_relative 'rails/output'
|
|
87
89
|
require_relative 'rails/output_safety'
|