rubocop-rails 2.20.2 → 2.24.1
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 +9 -7
- data/config/default.yml +72 -10
- data/lib/rubocop/cop/mixin/active_record_helper.rb +15 -3
- data/lib/rubocop/cop/mixin/database_type_resolvable.rb +66 -0
- data/lib/rubocop/cop/mixin/index_method.rb +2 -2
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +3 -1
- data/lib/rubocop/cop/rails/action_controller_test_case.rb +2 -2
- data/lib/rubocop/cop/rails/action_filter.rb +3 -0
- data/lib/rubocop/cop/rails/active_record_aliases.rb +2 -2
- data/lib/rubocop/cop/rails/active_support_aliases.rb +6 -5
- data/lib/rubocop/cop/rails/active_support_on_load.rb +21 -1
- data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
- data/lib/rubocop/cop/rails/bulk_change_table.rb +8 -41
- data/lib/rubocop/cop/rails/content_tag.rb +1 -1
- data/lib/rubocop/cop/rails/dangerous_column_names.rb +446 -0
- data/lib/rubocop/cop/rails/date.rb +1 -1
- data/lib/rubocop/cop/rails/duplicate_association.rb +69 -12
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +3 -3
- data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +2 -2
- data/lib/rubocop/cop/rails/env_local.rb +46 -0
- data/lib/rubocop/cop/rails/expanded_date_range.rb +1 -1
- data/lib/rubocop/cop/rails/file_path.rb +9 -6
- data/lib/rubocop/cop/rails/find_by.rb +3 -3
- data/lib/rubocop/cop/rails/find_by_id.rb +9 -23
- data/lib/rubocop/cop/rails/freeze_time.rb +1 -1
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -1
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +1 -1
- data/lib/rubocop/cop/rails/http_status.rb +4 -3
- data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +63 -13
- data/lib/rubocop/cop/rails/inquiry.rb +1 -0
- data/lib/rubocop/cop/rails/inverse_of.rb +1 -1
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +7 -8
- data/lib/rubocop/cop/rails/not_null_column.rb +13 -3
- data/lib/rubocop/cop/rails/output.rb +3 -2
- data/lib/rubocop/cop/rails/pick.rb +6 -5
- data/lib/rubocop/cop/rails/pluck.rb +1 -1
- data/lib/rubocop/cop/rails/pluck_id.rb +2 -1
- data/lib/rubocop/cop/rails/pluck_in_where.rb +18 -5
- data/lib/rubocop/cop/rails/rake_environment.rb +22 -6
- data/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +219 -0
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +7 -0
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -1
- data/lib/rubocop/cop/rails/response_parsed_body.rb +52 -10
- data/lib/rubocop/cop/rails/reversible_migration.rb +4 -4
- data/lib/rubocop/cop/rails/root_pathname_methods.rb +38 -4
- data/lib/rubocop/cop/rails/save_bang.rb +15 -8
- data/lib/rubocop/cop/rails/schema_comment.rb +16 -10
- data/lib/rubocop/cop/rails/select_map.rb +78 -0
- data/lib/rubocop/cop/rails/time_zone.rb +13 -5
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +29 -10
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +12 -4
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +2 -2
- data/lib/rubocop/cop/rails/unknown_env.rb +5 -1
- data/lib/rubocop/cop/rails/unused_render_content.rb +67 -0
- data/lib/rubocop/cop/rails/validation.rb +2 -2
- data/lib/rubocop/cop/rails/where_equals.rb +3 -2
- data/lib/rubocop/cop/rails/where_exists.rb +9 -9
- data/lib/rubocop/cop/rails/where_missing.rb +6 -2
- data/lib/rubocop/cop/rails/where_not.rb +8 -6
- data/lib/rubocop/cop/rails_cops.rb +6 -0
- data/lib/rubocop/rails/schema_loader/schema.rb +3 -2
- data/lib/rubocop/rails/schema_loader.rb +5 -15
- data/lib/rubocop/rails/version.rb +1 -1
- data/lib/rubocop-rails.rb +8 -0
- metadata +30 -4
@@ -163,9 +163,9 @@ module RuboCop
|
|
163
163
|
|
164
164
|
def autocorrect_extension_after_rails_root_join_in_dstr(corrector, node, rails_root_index, extension_node)
|
165
165
|
rails_root_node = node.children[rails_root_index].children.first
|
166
|
-
return unless rails_root_node.
|
166
|
+
return unless rails_root_node.last_argument.str_type?
|
167
167
|
|
168
|
-
corrector.insert_before(rails_root_node.
|
168
|
+
corrector.insert_before(rails_root_node.last_argument.location.end, extension_node.source)
|
169
169
|
corrector.remove(extension_node)
|
170
170
|
end
|
171
171
|
|
@@ -174,17 +174,20 @@ module RuboCop
|
|
174
174
|
corrector.remove(
|
175
175
|
range_with_surrounding_space(
|
176
176
|
range_with_surrounding_comma(
|
177
|
-
node.
|
177
|
+
node.first_argument.source_range,
|
178
178
|
:right
|
179
179
|
),
|
180
180
|
side: :right
|
181
181
|
)
|
182
182
|
)
|
183
|
+
node.arguments.filter(&:str_type?).each do |argument|
|
184
|
+
corrector.replace(argument, argument.value.delete_prefix('/').inspect)
|
185
|
+
end
|
183
186
|
corrector.insert_after(node, '.to_s')
|
184
187
|
end
|
185
188
|
|
186
189
|
def autocorrect_rails_root_join_with_string_arguments(corrector, node)
|
187
|
-
corrector.replace(node.
|
190
|
+
corrector.replace(node.first_argument, %("#{node.arguments.map(&:value).join('/')}"))
|
188
191
|
node.arguments[1..].each do |argument|
|
189
192
|
corrector.remove(
|
190
193
|
range_with_surrounding_comma(
|
@@ -218,7 +221,7 @@ module RuboCop
|
|
218
221
|
end
|
219
222
|
|
220
223
|
def append_argument(corrector, node, argument_source)
|
221
|
-
corrector.insert_after(node.
|
224
|
+
corrector.insert_after(node.last_argument, %(, "#{argument_source}"))
|
222
225
|
end
|
223
226
|
|
224
227
|
def replace_with_rails_root_join(corrector, node, argument_source)
|
@@ -230,7 +233,7 @@ module RuboCop
|
|
230
233
|
end
|
231
234
|
|
232
235
|
def extension_node?(node)
|
233
|
-
node&.str_type? && node.source.
|
236
|
+
node&.str_type? && node.source.match?(/\A\.[A-Za-z]+/)
|
234
237
|
end
|
235
238
|
end
|
236
239
|
end
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
include RangeHelp
|
29
29
|
extend AutoCorrector
|
30
30
|
|
31
|
-
MSG = 'Use `find_by` instead of `where
|
31
|
+
MSG = 'Use `find_by` instead of `where%<dot>s%<method>s`.'
|
32
32
|
RESTRICT_ON_SEND = %i[first take].freeze
|
33
33
|
|
34
34
|
def on_send(node)
|
@@ -37,7 +37,7 @@ module RuboCop
|
|
37
37
|
|
38
38
|
range = offense_range(node)
|
39
39
|
|
40
|
-
add_offense(range, message: format(MSG, method: node.method_name)) do |corrector|
|
40
|
+
add_offense(range, message: format(MSG, dot: node.loc.dot.source, method: node.method_name)) do |corrector|
|
41
41
|
autocorrect(corrector, node)
|
42
42
|
end
|
43
43
|
end
|
@@ -59,7 +59,7 @@ module RuboCop
|
|
59
59
|
return if node.method?(:first)
|
60
60
|
|
61
61
|
where_loc = node.receiver.loc.selector
|
62
|
-
first_loc = range_between(node.
|
62
|
+
first_loc = range_between(node.receiver.source_range.end_pos, node.loc.selector.end_pos)
|
63
63
|
|
64
64
|
corrector.replace(where_loc, 'find_by')
|
65
65
|
corrector.replace(first_loc, '')
|
@@ -24,40 +24,39 @@ module RuboCop
|
|
24
24
|
RESTRICT_ON_SEND = %i[take! find_by_id! find_by!].freeze
|
25
25
|
|
26
26
|
def_node_matcher :where_take?, <<~PATTERN
|
27
|
-
(
|
28
|
-
$(
|
27
|
+
(call
|
28
|
+
$(call _ :where
|
29
29
|
(hash
|
30
30
|
(pair (sym :id) $_))) :take!)
|
31
31
|
PATTERN
|
32
32
|
|
33
33
|
def_node_matcher :find_by?, <<~PATTERN
|
34
34
|
{
|
35
|
-
(
|
36
|
-
(
|
35
|
+
(call _ :find_by_id! $_)
|
36
|
+
(call _ :find_by! (hash (pair (sym :id) $_)))
|
37
37
|
}
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
def on_send(node)
|
41
41
|
where_take?(node) do |where, id_value|
|
42
42
|
range = where_take_offense_range(node, where)
|
43
|
-
bad_method = build_where_take_bad_method(id_value)
|
44
43
|
|
45
|
-
register_offense(range, id_value
|
44
|
+
register_offense(range, id_value)
|
46
45
|
end
|
47
46
|
|
48
47
|
find_by?(node) do |id_value|
|
49
48
|
range = find_by_offense_range(node)
|
50
|
-
bad_method = build_find_by_bad_method(node, id_value)
|
51
49
|
|
52
|
-
register_offense(range, id_value
|
50
|
+
register_offense(range, id_value)
|
53
51
|
end
|
54
52
|
end
|
53
|
+
alias on_csend on_send
|
55
54
|
|
56
55
|
private
|
57
56
|
|
58
|
-
def register_offense(range, id_value
|
57
|
+
def register_offense(range, id_value)
|
59
58
|
good_method = build_good_method(id_value)
|
60
|
-
message = format(MSG, good_method: good_method, bad_method:
|
59
|
+
message = format(MSG, good_method: good_method, bad_method: range.source)
|
61
60
|
|
62
61
|
add_offense(range, message: message) do |corrector|
|
63
62
|
corrector.replace(range, good_method)
|
@@ -75,19 +74,6 @@ module RuboCop
|
|
75
74
|
def build_good_method(id_value)
|
76
75
|
"find(#{id_value.source})"
|
77
76
|
end
|
78
|
-
|
79
|
-
def build_where_take_bad_method(id_value)
|
80
|
-
"where(id: #{id_value.source}).take!"
|
81
|
-
end
|
82
|
-
|
83
|
-
def build_find_by_bad_method(node, id_value)
|
84
|
-
case node.method_name
|
85
|
-
when :find_by_id!
|
86
|
-
"find_by_id!(#{id_value.source})"
|
87
|
-
when :find_by!
|
88
|
-
"find_by!(id: #{id_value.source})"
|
89
|
-
end
|
90
|
-
end
|
91
77
|
end
|
92
78
|
end
|
93
79
|
end
|
@@ -69,7 +69,7 @@ module RuboCop
|
|
69
69
|
return false unless CONVERT_METHODS.include?(method_name)
|
70
70
|
|
71
71
|
child_node, child_method_name, time_argument = *node.children
|
72
|
-
return if time_argument
|
72
|
+
return false if time_argument
|
73
73
|
|
74
74
|
current_time?(child_node, child_method_name)
|
75
75
|
end
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks for use of the helper methods which reference
|
7
7
|
# instance variables.
|
8
8
|
#
|
9
|
-
# Relying on instance variables makes it difficult to
|
9
|
+
# Relying on instance variables makes it difficult to reuse helper
|
10
10
|
# methods.
|
11
11
|
#
|
12
12
|
# If it seems awkward to explicitly pass in each dependent
|
@@ -8,6 +8,7 @@ module RuboCop
|
|
8
8
|
# @example EnforcedStyle: symbolic (default)
|
9
9
|
# # bad
|
10
10
|
# render :foo, status: 200
|
11
|
+
# render :foo, status: '200'
|
11
12
|
# render json: { foo: 'bar' }, status: 200
|
12
13
|
# render plain: 'foo/bar', status: 304
|
13
14
|
# redirect_to root_url, status: 301
|
@@ -50,7 +51,7 @@ module RuboCop
|
|
50
51
|
PATTERN
|
51
52
|
|
52
53
|
def_node_matcher :status_code, <<~PATTERN
|
53
|
-
(hash <(pair (sym :status) ${int sym}) ...>)
|
54
|
+
(hash <(pair (sym :status) ${int sym str}) ...>)
|
54
55
|
PATTERN
|
55
56
|
|
56
57
|
def on_send(node)
|
@@ -108,7 +109,7 @@ module RuboCop
|
|
108
109
|
private
|
109
110
|
|
110
111
|
def symbol
|
111
|
-
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
|
112
|
+
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number.to_i)
|
112
113
|
end
|
113
114
|
|
114
115
|
def number
|
@@ -133,7 +134,7 @@ module RuboCop
|
|
133
134
|
end
|
134
135
|
|
135
136
|
def offensive?
|
136
|
-
!node.int_type? && !permitted_symbol?
|
137
|
+
!node.int_type? && !permitted_symbol? && number
|
137
138
|
end
|
138
139
|
|
139
140
|
def message
|
@@ -5,7 +5,13 @@ module RuboCop
|
|
5
5
|
module Rails
|
6
6
|
# Checks for places where I18n "lazy" lookup can be used.
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# This cop has two different enforcement modes. When the EnforcedStyle
|
9
|
+
# is `lazy` (the default), explicit lookups are added as offenses.
|
10
|
+
#
|
11
|
+
# When the EnforcedStyle is `explicit` then lazy lookups are added as
|
12
|
+
# offenses.
|
13
|
+
#
|
14
|
+
# @example EnforcedStyle: lazy (default)
|
9
15
|
# # en.yml
|
10
16
|
# # en:
|
11
17
|
# # books:
|
@@ -28,11 +34,29 @@ module RuboCop
|
|
28
34
|
# end
|
29
35
|
# end
|
30
36
|
#
|
37
|
+
# @example EnforcedStyle: explicit
|
38
|
+
# # bad
|
39
|
+
# class BooksController < ApplicationController
|
40
|
+
# def create
|
41
|
+
# # ...
|
42
|
+
# redirect_to books_url, notice: t('.success')
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# class BooksController < ApplicationController
|
48
|
+
# def create
|
49
|
+
# # ...
|
50
|
+
# redirect_to books_url, notice: t('books.create.success')
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
31
54
|
class I18nLazyLookup < Base
|
55
|
+
include ConfigurableEnforcedStyle
|
32
56
|
include VisibilityHelp
|
33
57
|
extend AutoCorrector
|
34
58
|
|
35
|
-
MSG = 'Use
|
59
|
+
MSG = 'Use %<style>s lookup for the text used in controllers.'
|
36
60
|
|
37
61
|
RESTRICT_ON_SEND = %i[translate t].freeze
|
38
62
|
|
@@ -42,23 +66,45 @@ module RuboCop
|
|
42
66
|
|
43
67
|
def on_send(node)
|
44
68
|
translate_call?(node) do |key_node|
|
45
|
-
|
46
|
-
|
69
|
+
case style
|
70
|
+
when :lazy
|
71
|
+
handle_lazy_style(node, key_node)
|
72
|
+
when :explicit
|
73
|
+
handle_explicit_style(node, key_node)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
47
79
|
|
48
|
-
|
49
|
-
|
80
|
+
def handle_lazy_style(node, key_node)
|
81
|
+
key = key_node.value
|
82
|
+
return if key.to_s.start_with?('.')
|
50
83
|
|
51
|
-
|
52
|
-
|
84
|
+
controller, action = controller_and_action(node)
|
85
|
+
return unless controller && action
|
53
86
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
87
|
+
scoped_key = get_scoped_key(key_node, controller, action)
|
88
|
+
return unless key == scoped_key
|
89
|
+
|
90
|
+
add_offense(key_node) do |corrector|
|
91
|
+
unscoped_key = key_node.value.to_s.split('.').last
|
92
|
+
corrector.replace(key_node, "'.#{unscoped_key}'")
|
58
93
|
end
|
59
94
|
end
|
60
95
|
|
61
|
-
|
96
|
+
def handle_explicit_style(node, key_node)
|
97
|
+
key = key_node.value
|
98
|
+
return unless key.to_s.start_with?('.')
|
99
|
+
|
100
|
+
controller, action = controller_and_action(node)
|
101
|
+
return unless controller && action
|
102
|
+
|
103
|
+
scoped_key = get_scoped_key(key_node, controller, action)
|
104
|
+
add_offense(key_node) do |corrector|
|
105
|
+
corrector.replace(key_node, "'#{scoped_key}'")
|
106
|
+
end
|
107
|
+
end
|
62
108
|
|
63
109
|
def controller_and_action(node)
|
64
110
|
action_node = node.each_ancestor(:def).first
|
@@ -90,6 +136,10 @@ module RuboCop
|
|
90
136
|
|
91
137
|
path.delete_suffix('Controller').underscore
|
92
138
|
end
|
139
|
+
|
140
|
+
def message(_range)
|
141
|
+
format(MSG, style: style)
|
142
|
+
end
|
93
143
|
end
|
94
144
|
end
|
95
145
|
end
|
@@ -222,7 +222,7 @@ module RuboCop
|
|
222
222
|
|
223
223
|
def with_options_arguments(recv, node)
|
224
224
|
blocks = node.each_ancestor(:block).select do |block|
|
225
|
-
block.send_node.command?(:with_options) && same_context_in_with_options?(block.
|
225
|
+
block.send_node.command?(:with_options) && same_context_in_with_options?(block.first_argument, recv)
|
226
226
|
end
|
227
227
|
blocks.flat_map { |n| n.send_node.arguments }
|
228
228
|
end
|
@@ -122,24 +122,23 @@ module RuboCop
|
|
122
122
|
parent = node.each_ancestor(:class, :module).first
|
123
123
|
return unless parent
|
124
124
|
|
125
|
+
# NOTE: a `:begin` node may not exist if the class/module consists of a single statement
|
125
126
|
block = parent.each_child_node(:begin).first
|
126
|
-
return unless block
|
127
|
-
|
128
127
|
defined_action_methods = defined_action_methods(block)
|
129
128
|
|
130
|
-
|
131
|
-
|
132
|
-
end
|
129
|
+
unmatched_methods = array_values(methods_node) - defined_action_methods
|
130
|
+
return if unmatched_methods.empty?
|
133
131
|
|
134
|
-
message = message(
|
135
|
-
add_offense(node, message: message)
|
132
|
+
message = message(unmatched_methods, parent)
|
133
|
+
add_offense(node, message: message)
|
136
134
|
end
|
137
135
|
|
138
136
|
private
|
139
137
|
|
140
138
|
def defined_action_methods(block)
|
141
|
-
|
139
|
+
return [] unless block
|
142
140
|
|
141
|
+
defined_methods = block.each_child_node(:def).map(&:method_name)
|
143
142
|
defined_methods + aliased_action_methods(block, defined_methods)
|
144
143
|
end
|
145
144
|
|
@@ -3,8 +3,13 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
# Checks for add_column call with NOT NULL constraint
|
7
|
-
#
|
6
|
+
# Checks for add_column call with NOT NULL constraint in migration file.
|
7
|
+
#
|
8
|
+
# `TEXT` can have default values in PostgreSQL, but not in MySQL.
|
9
|
+
# It will automatically detect an adapter from `development` environment
|
10
|
+
# in `config/database.yml` or the environment variable `DATABASE_URL`
|
11
|
+
# when the `Database` option is not set. If the database is MySQL,
|
12
|
+
# this cop ignores offenses for the `TEXT`.
|
8
13
|
#
|
9
14
|
# @example
|
10
15
|
# # bad
|
@@ -17,6 +22,8 @@ module RuboCop
|
|
17
22
|
# add_reference :products, :category
|
18
23
|
# add_reference :products, :category, null: false, default: 1
|
19
24
|
class NotNullColumn < Base
|
25
|
+
include DatabaseTypeResolvable
|
26
|
+
|
20
27
|
MSG = 'Do not add a NOT NULL column without a default value.'
|
21
28
|
RESTRICT_ON_SEND = %i[add_column add_reference].freeze
|
22
29
|
|
@@ -45,7 +52,10 @@ module RuboCop
|
|
45
52
|
|
46
53
|
def check_add_column(node)
|
47
54
|
add_not_null_column?(node) do |type, pairs|
|
48
|
-
|
55
|
+
if type.respond_to?(:value)
|
56
|
+
return if type.value == :virtual || type.value == 'virtual'
|
57
|
+
return if (type.value == :text || type.value == 'text') && database == MYSQL
|
58
|
+
end
|
49
59
|
|
50
60
|
check_pairs(pairs)
|
51
61
|
end
|
@@ -23,6 +23,7 @@ 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
|
26
27
|
|
27
28
|
def_node_matcher :output?, <<~PATTERN
|
28
29
|
(send nil? {:ap :p :pp :pretty_print :print :puts} ...)
|
@@ -39,8 +40,8 @@ module RuboCop
|
|
39
40
|
PATTERN
|
40
41
|
|
41
42
|
def on_send(node)
|
42
|
-
return if node.parent&.
|
43
|
-
return
|
43
|
+
return if ALLOWED_TYPES.include?(node.parent&.type)
|
44
|
+
return if !output?(node) && !io_output?(node)
|
44
45
|
|
45
46
|
range = offense_range(node)
|
46
47
|
|
@@ -28,13 +28,13 @@ module RuboCop
|
|
28
28
|
extend AutoCorrector
|
29
29
|
extend TargetRailsVersion
|
30
30
|
|
31
|
-
MSG = 'Prefer `pick(%<args>s)` over
|
31
|
+
MSG = 'Prefer `pick(%<args>s)` over `%<current>s`.'
|
32
32
|
RESTRICT_ON_SEND = %i[first].freeze
|
33
33
|
|
34
34
|
minimum_target_rails_version 6.0
|
35
35
|
|
36
36
|
def_node_matcher :pick_candidate?, <<~PATTERN
|
37
|
-
(
|
37
|
+
(call (call _ :pluck ...) :first)
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
def on_send(node)
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
node_selector = node.loc.selector
|
45
45
|
range = receiver_selector.join(node_selector)
|
46
46
|
|
47
|
-
add_offense(range, message: message(receiver)) do |corrector|
|
47
|
+
add_offense(range, message: message(receiver, range)) do |corrector|
|
48
48
|
first_range = receiver.source_range.end.join(node_selector)
|
49
49
|
|
50
50
|
corrector.remove(first_range)
|
@@ -52,11 +52,12 @@ module RuboCop
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
|
+
alias on_csend on_send
|
55
56
|
|
56
57
|
private
|
57
58
|
|
58
|
-
def message(receiver)
|
59
|
-
format(MSG, args: receiver.arguments.map(&:source).join(', '))
|
59
|
+
def message(receiver, current)
|
60
|
+
format(MSG, args: receiver.arguments.map(&:source).join(', '), current: current.source)
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
@@ -38,7 +38,7 @@ module RuboCop
|
|
38
38
|
minimum_target_rails_version 5.0
|
39
39
|
|
40
40
|
def_node_matcher :pluck_candidate?, <<~PATTERN
|
41
|
-
({block numblock} (
|
41
|
+
({block numblock} (call _ {:map :collect}) $_argument (send lvar :[] $_key))
|
42
42
|
PATTERN
|
43
43
|
|
44
44
|
def on_block(node)
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
RESTRICT_ON_SEND = %i[pluck].freeze
|
35
35
|
|
36
36
|
def_node_matcher :pluck_id_call?, <<~PATTERN
|
37
|
-
(
|
37
|
+
(call _ :pluck {(sym :id) (send nil? :primary_key)})
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
def on_send(node)
|
@@ -47,6 +47,7 @@ module RuboCop
|
|
47
47
|
corrector.replace(offense_range(node), 'ids')
|
48
48
|
end
|
49
49
|
end
|
50
|
+
alias on_csend on_send
|
50
51
|
|
51
52
|
private
|
52
53
|
|
@@ -22,10 +22,13 @@ module RuboCop
|
|
22
22
|
# @example
|
23
23
|
# # bad
|
24
24
|
# Post.where(user_id: User.active.pluck(:id))
|
25
|
+
# Post.where(user_id: User.active.ids)
|
26
|
+
# Post.where.not(user_id: User.active.pluck(:id))
|
25
27
|
#
|
26
28
|
# # good
|
27
29
|
# Post.where(user_id: User.active.select(:id))
|
28
30
|
# Post.where(user_id: active_users.select(:id))
|
31
|
+
# Post.where.not(user_id: active_users.select(:id))
|
29
32
|
#
|
30
33
|
# @example EnforcedStyle: conservative (default)
|
31
34
|
# # good
|
@@ -40,8 +43,9 @@ module RuboCop
|
|
40
43
|
include ConfigurableEnforcedStyle
|
41
44
|
extend AutoCorrector
|
42
45
|
|
43
|
-
|
44
|
-
|
46
|
+
MSG_SELECT = 'Use `select` instead of `pluck` within `where` query method.'
|
47
|
+
MSG_IDS = 'Use `select(:id)` instead of `ids` within `where` query method.'
|
48
|
+
RESTRICT_ON_SEND = %i[pluck ids].freeze
|
45
49
|
|
46
50
|
def on_send(node)
|
47
51
|
return unless in_where?(node)
|
@@ -49,17 +53,26 @@ module RuboCop
|
|
49
53
|
|
50
54
|
range = node.loc.selector
|
51
55
|
|
52
|
-
|
53
|
-
|
56
|
+
if node.method?(:ids)
|
57
|
+
replacement = 'select(:id)'
|
58
|
+
message = MSG_IDS
|
59
|
+
else
|
60
|
+
replacement = 'select'
|
61
|
+
message = MSG_SELECT
|
62
|
+
end
|
63
|
+
|
64
|
+
add_offense(range, message: message) do |corrector|
|
65
|
+
corrector.replace(range, replacement)
|
54
66
|
end
|
55
67
|
end
|
68
|
+
alias on_csend on_send
|
56
69
|
|
57
70
|
private
|
58
71
|
|
59
72
|
def root_receiver(node)
|
60
73
|
receiver = node.receiver
|
61
74
|
|
62
|
-
if receiver&.
|
75
|
+
if receiver&.call_type?
|
63
76
|
root_receiver(receiver)
|
64
77
|
else
|
65
78
|
receiver
|
@@ -45,16 +45,24 @@ module RuboCop
|
|
45
45
|
return if with_dependencies?(task_method)
|
46
46
|
|
47
47
|
add_offense(task_method) do |corrector|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
if with_arguments?(task_method)
|
49
|
+
new_task_dependency = correct_task_arguments_dependency(task_method)
|
50
|
+
corrector.replace(task_arguments(task_method), new_task_dependency)
|
51
|
+
else
|
52
|
+
task_name = task_method.first_argument
|
53
|
+
new_task_dependency = correct_task_dependency(task_name)
|
54
|
+
corrector.replace(task_name, new_task_dependency)
|
55
|
+
end
|
52
56
|
end
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
60
|
private
|
57
61
|
|
62
|
+
def correct_task_arguments_dependency(task_method)
|
63
|
+
"#{task_arguments(task_method).source} => :environment"
|
64
|
+
end
|
65
|
+
|
58
66
|
def correct_task_dependency(task_name)
|
59
67
|
if task_name.sym_type?
|
60
68
|
"#{task_name.source.delete(':|\'|"')}: :environment"
|
@@ -64,7 +72,7 @@ module RuboCop
|
|
64
72
|
end
|
65
73
|
|
66
74
|
def task_name(node)
|
67
|
-
first_arg = node.
|
75
|
+
first_arg = node.first_argument
|
68
76
|
case first_arg&.type
|
69
77
|
when :sym, :str
|
70
78
|
first_arg.value.to_sym
|
@@ -80,8 +88,16 @@ module RuboCop
|
|
80
88
|
end
|
81
89
|
end
|
82
90
|
|
91
|
+
def task_arguments(node)
|
92
|
+
node.arguments[1]
|
93
|
+
end
|
94
|
+
|
95
|
+
def with_arguments?(node)
|
96
|
+
node.arguments.size > 1 && node.arguments[1].array_type?
|
97
|
+
end
|
98
|
+
|
83
99
|
def with_dependencies?(node)
|
84
|
-
first_arg = node.
|
100
|
+
first_arg = node.first_argument
|
85
101
|
return false unless first_arg
|
86
102
|
|
87
103
|
if first_arg.hash_type?
|