rubocop-rails 2.15.2 → 2.16.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 +80 -0
- data/config/obsoletion.yml +10 -0
- data/lib/rubocop/cop/mixin/active_record_helper.rb +1 -4
- data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
- data/lib/rubocop/cop/mixin/index_method.rb +5 -15
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +98 -0
- data/lib/rubocop/cop/rails/action_filter.rb +1 -1
- data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
- data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
- data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
- data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
- data/lib/rubocop/cop/rails/blank.rb +1 -2
- data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
- data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
- data/lib/rubocop/cop/rails/content_tag.rb +1 -3
- data/lib/rubocop/cop/rails/date.rb +4 -9
- data/lib/rubocop/cop/rails/delegate.rb +2 -5
- data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
- data/lib/rubocop/cop/rails/dot_separated_keys.rb +1 -1
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +2 -4
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
- data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
- data/lib/rubocop/cop/rails/file_path.rb +2 -4
- data/lib/rubocop/cop/rails/find_each.rb +8 -2
- data/lib/rubocop/cop/rails/freeze_time.rb +69 -0
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -3
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
- data/lib/rubocop/cop/rails/http_status.rb +5 -10
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
- data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
- data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
- data/lib/rubocop/cop/rails/output.rb +2 -5
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
- data/lib/rubocop/cop/rails/presence.rb +1 -3
- data/lib/rubocop/cop/rails/present.rb +3 -6
- data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
- data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +2 -2
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +28 -26
- data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
- data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
- data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
- data/lib/rubocop/cop/rails/request_referer.rb +1 -2
- data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
- data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
- data/lib/rubocop/cop/rails/root_pathname_methods.rb +175 -0
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
- data/lib/rubocop/cop/rails/save_bang.rb +10 -22
- data/lib/rubocop/cop/rails/short_i18n.rb +1 -4
- data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -2
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
- data/lib/rubocop/cop/rails/time_zone.rb +8 -19
- data/lib/rubocop/cop/rails/to_s_with_argument.rb +41 -0
- data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +48 -0
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
- data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
- data/lib/rubocop/cop/rails/validation.rb +4 -12
- data/lib/rubocop/cop/rails/where_missing.rb +111 -0
- data/lib/rubocop/cop/rails_cops.rb +7 -0
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +13 -8
- data/bin/console +0 -11
- data/bin/setup +0 -7
@@ -81,11 +81,7 @@ module RuboCop
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def offense_message(method_name)
|
84
|
-
format(
|
85
|
-
MSG,
|
86
|
-
bad_method: method_name,
|
87
|
-
good_method: convert_good_method(method_name)
|
88
|
-
)
|
84
|
+
format(MSG, bad_method: method_name, good_method: convert_good_method(method_name))
|
89
85
|
end
|
90
86
|
|
91
87
|
def convert_good_method(bad_method)
|
@@ -34,8 +34,7 @@ module RuboCop
|
|
34
34
|
include RangeHelp
|
35
35
|
extend AutoCorrector
|
36
36
|
|
37
|
-
MSG = 'Do not assign `%<method_name>s` to constants as it '
|
38
|
-
'will be evaluated only once.'
|
37
|
+
MSG = 'Do not assign `%<method_name>s` to constants as it will be evaluated only once.'
|
39
38
|
RELATIVE_DATE_METHODS = %i[since from_now after ago until before yesterday tomorrow].to_set.freeze
|
40
39
|
|
41
40
|
def on_casgn(node)
|
@@ -77,9 +76,7 @@ module RuboCop
|
|
77
76
|
return unless scope.nil?
|
78
77
|
|
79
78
|
indent = ' ' * node.loc.column
|
80
|
-
new_code = ["def self.#{const_name.downcase}",
|
81
|
-
"#{indent}#{value.source}",
|
82
|
-
'end'].join("\n#{indent}")
|
79
|
+
new_code = ["def self.#{const_name.downcase}", "#{indent}#{value.source}", 'end'].join("\n#{indent}")
|
83
80
|
|
84
81
|
corrector.replace(node.source_range, new_code)
|
85
82
|
end
|
@@ -23,8 +23,7 @@ module RuboCop
|
|
23
23
|
include ConfigurableEnforcedStyle
|
24
24
|
extend AutoCorrector
|
25
25
|
|
26
|
-
MSG = 'Use `request.%<prefer>s` instead of '
|
27
|
-
'`request.%<current>s`.'
|
26
|
+
MSG = 'Use `request.%<prefer>s` instead of `request.%<current>s`.'
|
28
27
|
RESTRICT_ON_SEND = %i[referer referrer].freeze
|
29
28
|
|
30
29
|
def_node_matcher :referer?, <<~PATTERN
|
@@ -229,6 +229,8 @@ module RuboCop
|
|
229
229
|
check_change_table_node(node.send_node, node.body)
|
230
230
|
end
|
231
231
|
|
232
|
+
alias on_numblock on_block
|
233
|
+
|
232
234
|
private
|
233
235
|
|
234
236
|
def check_irreversible_schema_statement_node(node)
|
@@ -240,10 +242,7 @@ module RuboCop
|
|
240
242
|
def check_drop_table_node(node)
|
241
243
|
drop_table_call(node) do
|
242
244
|
unless node.parent.block_type? || node.last_argument.block_pass_type?
|
243
|
-
add_offense(
|
244
|
-
node,
|
245
|
-
message: format(MSG, action: 'drop_table(without block)')
|
246
|
-
)
|
245
|
+
add_offense(node, message: format(MSG, action: 'drop_table(without block)'))
|
247
246
|
end
|
248
247
|
end
|
249
248
|
end
|
@@ -251,22 +250,12 @@ module RuboCop
|
|
251
250
|
def check_reversible_hash_node(node)
|
252
251
|
return if reversible_change_table_call?(node)
|
253
252
|
|
254
|
-
add_offense(
|
255
|
-
node,
|
256
|
-
message: format(
|
257
|
-
MSG, action: "#{node.method_name}(without :from and :to)"
|
258
|
-
)
|
259
|
-
)
|
253
|
+
add_offense(node, message: format(MSG, action: "#{node.method_name}(without :from and :to)"))
|
260
254
|
end
|
261
255
|
|
262
256
|
def check_remove_column_node(node)
|
263
257
|
remove_column_call(node) do |args|
|
264
|
-
if args.to_a.size < 3
|
265
|
-
add_offense(
|
266
|
-
node,
|
267
|
-
message: format(MSG, action: 'remove_column(without type)')
|
268
|
-
)
|
269
|
-
end
|
258
|
+
add_offense(node, message: format(MSG, action: 'remove_column(without type)')) if args.to_a.size < 3
|
270
259
|
end
|
271
260
|
end
|
272
261
|
|
@@ -295,10 +284,7 @@ module RuboCop
|
|
295
284
|
unless all_hash_key?(args, :type) && target_rails_version >= 6.1
|
296
285
|
action = target_rails_version >= 6.1 ? 'remove_columns(without type)' : 'remove_columns'
|
297
286
|
|
298
|
-
add_offense(
|
299
|
-
node,
|
300
|
-
message: format(MSG, action: action)
|
301
|
-
)
|
287
|
+
add_offense(node, message: format(MSG, action: action))
|
302
288
|
end
|
303
289
|
end
|
304
290
|
end
|
@@ -306,18 +292,14 @@ module RuboCop
|
|
306
292
|
def check_remove_index_node(node)
|
307
293
|
remove_index_call(node) do |args|
|
308
294
|
if args.hash_type? && !all_hash_key?(args, :column)
|
309
|
-
add_offense(
|
310
|
-
node,
|
311
|
-
message: format(MSG, action: 'remove_index(without column)')
|
312
|
-
)
|
295
|
+
add_offense(node, message: format(MSG, action: 'remove_index(without column)'))
|
313
296
|
end
|
314
297
|
end
|
315
298
|
end
|
316
299
|
|
317
300
|
def check_change_table_offense(receiver, node)
|
318
301
|
method_name = node.method_name
|
319
|
-
return if receiver != node.receiver &&
|
320
|
-
reversible_change_table_call?(node)
|
302
|
+
return if receiver != node.receiver && reversible_change_table_call?(node)
|
321
303
|
|
322
304
|
action = if method_name == :remove
|
323
305
|
target_rails_version >= 6.1 ? 't.remove (without type)' : 't.remove'
|
@@ -325,10 +307,7 @@ module RuboCop
|
|
325
307
|
"change_table(with #{method_name})"
|
326
308
|
end
|
327
309
|
|
328
|
-
add_offense(
|
329
|
-
node,
|
330
|
-
message: format(MSG, action: action)
|
331
|
-
)
|
310
|
+
add_offense(node, message: format(MSG, action: action))
|
332
311
|
end
|
333
312
|
|
334
313
|
def reversible_change_table_call?(node)
|
@@ -353,9 +332,7 @@ module RuboCop
|
|
353
332
|
|
354
333
|
def within_reversible_or_up_only_block?(node)
|
355
334
|
node.each_ancestor(:block).any? do |ancestor|
|
356
|
-
(ancestor.block_type? &&
|
357
|
-
ancestor.send_node.method?(:reversible)) ||
|
358
|
-
ancestor.send_node.method?(:up_only)
|
335
|
+
(ancestor.block_type? && ancestor.send_node.method?(:reversible)) || ancestor.send_node.method?(:up_only)
|
359
336
|
end
|
360
337
|
end
|
361
338
|
|
@@ -45,8 +45,7 @@ module RuboCop
|
|
45
45
|
class ReversibleMigrationMethodDefinition < Base
|
46
46
|
include MigrationsHelper
|
47
47
|
|
48
|
-
MSG = 'Migrations must contain either a `change` method, or '
|
49
|
-
'both an `up` and a `down` method.'
|
48
|
+
MSG = 'Migrations must contain either a `change` method, or both an `up` and a `down` method.'
|
50
49
|
|
51
50
|
def_node_matcher :change_method?, <<~PATTERN
|
52
51
|
`(def :change (args) _)
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Use `Rails.root` IO methods instead of passing it to `File`.
|
7
|
+
#
|
8
|
+
# `Rails.root` is an instance of `Pathname`
|
9
|
+
# so we can apply many IO methods directly.
|
10
|
+
#
|
11
|
+
# This cop works best when used together with
|
12
|
+
# `Style/FileRead`, `Style/FileWrite` and `Rails/RootJoinChain`.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # bad
|
16
|
+
# File.open(Rails.root.join('db', 'schema.rb'))
|
17
|
+
# File.open(Rails.root.join('db', 'schema.rb'), 'w')
|
18
|
+
# File.read(Rails.root.join('db', 'schema.rb'))
|
19
|
+
# File.binread(Rails.root.join('db', 'schema.rb'))
|
20
|
+
# File.write(Rails.root.join('db', 'schema.rb'), content)
|
21
|
+
# File.binwrite(Rails.root.join('db', 'schema.rb'), content)
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# Rails.root.join('db', 'schema.rb').open
|
25
|
+
# Rails.root.join('db', 'schema.rb').open('w')
|
26
|
+
# Rails.root.join('db', 'schema.rb').read
|
27
|
+
# Rails.root.join('db', 'schema.rb').binread
|
28
|
+
# Rails.root.join('db', 'schema.rb').write(content)
|
29
|
+
# Rails.root.join('db', 'schema.rb').binwrite(content)
|
30
|
+
#
|
31
|
+
class RootPathnameMethods < Base
|
32
|
+
extend AutoCorrector
|
33
|
+
|
34
|
+
MSG = '`%<rails_root>s` is a `Pathname` so you can just append `#%<method>s`.'
|
35
|
+
|
36
|
+
DIR_METHODS = %i[children delete each_child empty? entries exist? glob mkdir open rmdir unlink].to_set.freeze
|
37
|
+
|
38
|
+
FILE_METHODS = %i[
|
39
|
+
atime
|
40
|
+
basename
|
41
|
+
binread
|
42
|
+
binwrite
|
43
|
+
birthtime
|
44
|
+
blockdev?
|
45
|
+
chardev?
|
46
|
+
chmod
|
47
|
+
chown
|
48
|
+
ctime
|
49
|
+
delete
|
50
|
+
directory?
|
51
|
+
dirname
|
52
|
+
empty?
|
53
|
+
executable?
|
54
|
+
executable_real?
|
55
|
+
exist?
|
56
|
+
expand_path
|
57
|
+
extname
|
58
|
+
file?
|
59
|
+
fnmatch
|
60
|
+
fnmatch?
|
61
|
+
ftype
|
62
|
+
grpowned?
|
63
|
+
join
|
64
|
+
lchmod
|
65
|
+
lchown
|
66
|
+
lstat
|
67
|
+
mtime
|
68
|
+
open
|
69
|
+
owned?
|
70
|
+
pipe?
|
71
|
+
read
|
72
|
+
readable?
|
73
|
+
readable_real?
|
74
|
+
readlines
|
75
|
+
readlink
|
76
|
+
realdirpath
|
77
|
+
realpath
|
78
|
+
rename
|
79
|
+
setgid?
|
80
|
+
setuid?
|
81
|
+
size
|
82
|
+
size?
|
83
|
+
socket?
|
84
|
+
split
|
85
|
+
stat
|
86
|
+
sticky?
|
87
|
+
symlink?
|
88
|
+
sysopen
|
89
|
+
truncate
|
90
|
+
unlink
|
91
|
+
utime
|
92
|
+
world_readable?
|
93
|
+
world_writable?
|
94
|
+
writable?
|
95
|
+
writable_real?
|
96
|
+
write
|
97
|
+
zero?
|
98
|
+
].to_set.freeze
|
99
|
+
|
100
|
+
FILE_TEST_METHODS = %i[
|
101
|
+
blockdev?
|
102
|
+
chardev?
|
103
|
+
directory?
|
104
|
+
empty?
|
105
|
+
executable?
|
106
|
+
executable_real?
|
107
|
+
exist?
|
108
|
+
file?
|
109
|
+
grpowned?
|
110
|
+
owned?
|
111
|
+
pipe?
|
112
|
+
readable?
|
113
|
+
readable_real?
|
114
|
+
setgid?
|
115
|
+
setuid?
|
116
|
+
size
|
117
|
+
size?
|
118
|
+
socket?
|
119
|
+
sticky?
|
120
|
+
symlink?
|
121
|
+
world_readable?
|
122
|
+
world_writable?
|
123
|
+
writable?
|
124
|
+
writable_real?
|
125
|
+
zero?
|
126
|
+
].to_set.freeze
|
127
|
+
|
128
|
+
FILE_UTILS_METHODS = %i[chmod chown mkdir mkpath rmdir rmtree].to_set.freeze
|
129
|
+
|
130
|
+
RESTRICT_ON_SEND = (DIR_METHODS + FILE_METHODS + FILE_TEST_METHODS + FILE_UTILS_METHODS).to_set.freeze
|
131
|
+
|
132
|
+
def_node_matcher :pathname_method, <<~PATTERN
|
133
|
+
{
|
134
|
+
(send (const {nil? cbase} :Dir) $DIR_METHODS $_ $...)
|
135
|
+
(send (const {nil? cbase} {:IO :File}) $FILE_METHODS $_ $...)
|
136
|
+
(send (const {nil? cbase} :FileTest) $FILE_TEST_METHODS $_ $...)
|
137
|
+
(send (const {nil? cbase} :FileUtils) $FILE_UTILS_METHODS $_ $...)
|
138
|
+
}
|
139
|
+
PATTERN
|
140
|
+
|
141
|
+
def_node_matcher :rails_root_pathname?, <<~PATTERN
|
142
|
+
{
|
143
|
+
$#rails_root?
|
144
|
+
(send $#rails_root? :join ...)
|
145
|
+
}
|
146
|
+
PATTERN
|
147
|
+
|
148
|
+
# @!method rails_root?(node)
|
149
|
+
def_node_matcher :rails_root?, <<~PATTERN
|
150
|
+
(send (const {nil? cbase} :Rails) {:root :public_path})
|
151
|
+
PATTERN
|
152
|
+
|
153
|
+
def on_send(node)
|
154
|
+
evidence(node) do |method, path, args, rails_root|
|
155
|
+
add_offense(node, message: format(MSG, method: method, rails_root: rails_root.source)) do |corrector|
|
156
|
+
replacement = "#{path.source}.#{method}"
|
157
|
+
replacement += "(#{args.map(&:source).join(', ')})" unless args.empty?
|
158
|
+
|
159
|
+
corrector.replace(node, replacement)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def evidence(node)
|
167
|
+
return if node.method?(:open) && node.parent&.send_type?
|
168
|
+
return unless (method, path, args = pathname_method(node)) && (rails_root = rails_root_pathname?(path))
|
169
|
+
|
170
|
+
yield(method, path, args, rails_root)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -31,9 +31,7 @@ module RuboCop
|
|
31
31
|
class SafeNavigationWithBlank < Base
|
32
32
|
extend AutoCorrector
|
33
33
|
|
34
|
-
MSG =
|
35
|
-
'Avoid calling `blank?` with the safe navigation operator ' \
|
36
|
-
'in conditionals.'
|
34
|
+
MSG = 'Avoid calling `blank?` with the safe navigation operator in conditionals.'
|
37
35
|
|
38
36
|
def_node_matcher :safe_navigation_blank_in_conditional?, <<~PATTERN
|
39
37
|
(if $(csend ... :blank?) ...)
|
@@ -121,18 +121,12 @@ module RuboCop
|
|
121
121
|
include NegativeConditional
|
122
122
|
extend AutoCorrector
|
123
123
|
|
124
|
-
MSG = 'Use `%<prefer>s` instead of `%<current>s` if the return '
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
'always truthy.'
|
131
|
-
|
132
|
-
CREATE_PERSIST_METHODS = %i[create create_or_find_by
|
133
|
-
first_or_create find_or_create_by].freeze
|
134
|
-
MODIFY_PERSIST_METHODS = %i[save
|
135
|
-
update update_attributes destroy].freeze
|
124
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s` if the return value is not checked.'
|
125
|
+
CREATE_MSG = "#{MSG} Or check `persisted?` on model returned from `%<current>s`."
|
126
|
+
CREATE_CONDITIONAL_MSG = '`%<current>s` returns a model which is always truthy.'
|
127
|
+
|
128
|
+
CREATE_PERSIST_METHODS = %i[create create_or_find_by first_or_create find_or_create_by].freeze
|
129
|
+
MODIFY_PERSIST_METHODS = %i[save update update_attributes destroy].freeze
|
136
130
|
RESTRICT_ON_SEND = (CREATE_PERSIST_METHODS + MODIFY_PERSIST_METHODS).freeze
|
137
131
|
|
138
132
|
def self.joining_forces
|
@@ -244,8 +238,7 @@ module RuboCop
|
|
244
238
|
parent = node.parent
|
245
239
|
return false unless parent
|
246
240
|
|
247
|
-
operator_or_single_negative?(parent) ||
|
248
|
-
(conditional?(parent) && node == parent.condition)
|
241
|
+
operator_or_single_negative?(parent) || (conditional?(parent) && node == parent.condition)
|
249
242
|
end
|
250
243
|
|
251
244
|
def operator_or_single_negative?(node)
|
@@ -294,9 +287,7 @@ module RuboCop
|
|
294
287
|
# NameSpace::Const != ::Const
|
295
288
|
# Const != NameSpace::Const
|
296
289
|
def const_matches?(const, allowed_const)
|
297
|
-
parts = allowed_const.split('::').reverse.zip(
|
298
|
-
const.split('::').reverse
|
299
|
-
)
|
290
|
+
parts = allowed_const.split('::').reverse.zip(const.split('::').reverse)
|
300
291
|
parts.all? do |(allowed_part, const_part)|
|
301
292
|
allowed_part == const_part.to_s
|
302
293
|
end
|
@@ -335,9 +326,7 @@ module RuboCop
|
|
335
326
|
end
|
336
327
|
|
337
328
|
def persist_method?(node, methods = RESTRICT_ON_SEND)
|
338
|
-
methods.include?(node.method_name) &&
|
339
|
-
expected_signature?(node) &&
|
340
|
-
!allowed_receiver?(node)
|
329
|
+
methods.include?(node.method_name) && expected_signature?(node) && !allowed_receiver?(node)
|
341
330
|
end
|
342
331
|
|
343
332
|
# Check argument signature as no arguments or one hash
|
@@ -345,8 +334,7 @@ module RuboCop
|
|
345
334
|
!node.arguments? ||
|
346
335
|
(node.arguments.one? &&
|
347
336
|
node.method_name != :destroy &&
|
348
|
-
(node.first_argument.hash_type? ||
|
349
|
-
!node.first_argument.literal?))
|
337
|
+
(node.first_argument.hash_type? || !node.first_argument.literal?))
|
350
338
|
end
|
351
339
|
end
|
352
340
|
end
|
@@ -44,10 +44,7 @@ module RuboCop
|
|
44
44
|
|
45
45
|
MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
|
46
46
|
|
47
|
-
PREFERRED_METHODS = {
|
48
|
-
translate: :t,
|
49
|
-
localize: :l
|
50
|
-
}.freeze
|
47
|
+
PREFERRED_METHODS = { translate: :t, localize: :l }.freeze
|
51
48
|
|
52
49
|
RESTRICT_ON_SEND = PREFERRED_METHODS.keys.freeze
|
53
50
|
|
@@ -43,21 +43,17 @@ module RuboCop
|
|
43
43
|
include ConfigurableEnforcedStyle
|
44
44
|
extend AutoCorrector
|
45
45
|
|
46
|
-
MSG = 'Do not use `%<current>s` without zone. Use `%<prefer>s` '
|
47
|
-
'instead.'
|
46
|
+
MSG = 'Do not use `%<current>s` without zone. Use `%<prefer>s` instead.'
|
48
47
|
|
49
|
-
MSG_ACCEPTABLE = 'Do not use `%<current>s` without zone. '
|
50
|
-
'Use one of %<prefer>s instead.'
|
48
|
+
MSG_ACCEPTABLE = 'Do not use `%<current>s` without zone. Use one of %<prefer>s instead.'
|
51
49
|
|
52
|
-
MSG_LOCALTIME = 'Do not use `Time.localtime` without '
|
53
|
-
'offset or zone.'
|
50
|
+
MSG_LOCALTIME = 'Do not use `Time.localtime` without offset or zone.'
|
54
51
|
|
55
52
|
GOOD_METHODS = %i[zone zone_default find_zone find_zone!].freeze
|
56
53
|
|
57
54
|
DANGEROUS_METHODS = %i[now local new parse at].freeze
|
58
55
|
|
59
|
-
ACCEPTED_METHODS = %i[in_time_zone utc getlocal xmlschema iso8601
|
60
|
-
jisx0301 rfc3339 httpdate to_i to_f].freeze
|
56
|
+
ACCEPTED_METHODS = %i[in_time_zone utc getlocal xmlschema iso8601 jisx0301 rfc3339 httpdate to_i to_f].freeze
|
61
57
|
|
62
58
|
TIMEZONE_SPECIFIER = /[A-z]/.freeze
|
63
59
|
|
@@ -100,13 +96,11 @@ module RuboCop
|
|
100
96
|
# remove redundant `.in_time_zone` from `Time.zone.now.in_time_zone`
|
101
97
|
def remove_redundant_in_time_zone(corrector, node)
|
102
98
|
time_methods_called = extract_method_chain(node)
|
103
|
-
return unless time_methods_called.include?(:in_time_zone) ||
|
104
|
-
time_methods_called.include?(:zone)
|
99
|
+
return unless time_methods_called.include?(:in_time_zone) || time_methods_called.include?(:zone)
|
105
100
|
|
106
101
|
while node&.send_type?
|
107
102
|
if node.children.last == :in_time_zone
|
108
|
-
in_time_zone_with_dot =
|
109
|
-
node.loc.selector.adjust(begin_pos: -1)
|
103
|
+
in_time_zone_with_dot = node.loc.selector.adjust(begin_pos: -1)
|
110
104
|
corrector.remove(in_time_zone_with_dot)
|
111
105
|
end
|
112
106
|
node = node.parent
|
@@ -144,9 +138,7 @@ module RuboCop
|
|
144
138
|
)
|
145
139
|
else
|
146
140
|
safe_method_name = safe_method(method_name, node)
|
147
|
-
format(MSG,
|
148
|
-
current: "#{klass}.#{method_name}",
|
149
|
-
prefer: "Time.zone.#{safe_method_name}")
|
141
|
+
format(MSG, current: "#{klass}.#{method_name}", prefer: "Time.zone.#{safe_method_name}")
|
150
142
|
end
|
151
143
|
end
|
152
144
|
|
@@ -227,10 +219,7 @@ module RuboCop
|
|
227
219
|
end
|
228
220
|
|
229
221
|
def acceptable_methods(klass, method_name, node)
|
230
|
-
acceptable = [
|
231
|
-
"`Time.zone.#{safe_method(method_name, node)}`",
|
232
|
-
"`#{klass}.current`"
|
233
|
-
]
|
222
|
+
acceptable = ["`Time.zone.#{safe_method(method_name, node)}`", "`#{klass}.current`"]
|
234
223
|
|
235
224
|
ACCEPTED_METHODS.each do |am|
|
236
225
|
acceptable << "`#{klass}.#{method_name}.#{am}`"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Identifies passing any argument to `#to_s`.
|
7
|
+
#
|
8
|
+
# @safety
|
9
|
+
# This cop is marked as unsafe because it may detect `#to_s` calls
|
10
|
+
# that are not related to Active Support implementation.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# obj.to_s(:delimited)
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# obj.to_formatted_s(:delimited)
|
19
|
+
#
|
20
|
+
class ToSWithArgument < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
extend TargetRailsVersion
|
23
|
+
|
24
|
+
MSG = 'Use `to_formatted_s` instead.'
|
25
|
+
|
26
|
+
RESTRICT_ON_SEND = %i[to_s].freeze
|
27
|
+
|
28
|
+
minimum_target_rails_version 7.0
|
29
|
+
|
30
|
+
def on_send(node)
|
31
|
+
return if node.arguments.empty?
|
32
|
+
|
33
|
+
add_offense(node.loc.selector) do |corrector|
|
34
|
+
corrector.replace(node.loc.selector, 'to_formatted_s')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
alias on_csend on_send
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Identifies top-level `HashWithIndifferentAccess`.
|
7
|
+
# This has been soft-deprecated since Rails 5.1.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# HashWithIndifferentAccess.new(foo: 'bar')
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar')
|
15
|
+
#
|
16
|
+
class TopLevelHashWithIndifferentAccess < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
extend TargetRailsVersion
|
19
|
+
|
20
|
+
minimum_target_rails_version 5.1
|
21
|
+
|
22
|
+
MSG = 'Avoid top-level `HashWithIndifferentAccess`.'
|
23
|
+
|
24
|
+
# @!method top_level_hash_with_indifferent_access?(node)
|
25
|
+
# @param [RuboCop::AST::ConstNode] node
|
26
|
+
# @return [Boolean]
|
27
|
+
def_node_matcher :top_level_hash_with_indifferent_access?, <<~PATTERN
|
28
|
+
(const {nil? cbase} :HashWithIndifferentAccess)
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
# @param [RuboCop::AST::ConstNode] node
|
32
|
+
def on_const(node)
|
33
|
+
return unless top_level_hash_with_indifferent_access?(node)
|
34
|
+
|
35
|
+
add_offense(node) do |corrector|
|
36
|
+
autocorrect(corrector, node)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def autocorrect(corrector, node)
|
43
|
+
corrector.insert_before(node.location.name, 'ActiveSupport::')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -54,11 +54,9 @@ module RuboCop
|
|
54
54
|
NEWLINE = "\n"
|
55
55
|
PATTERN = '[!^block (send (send %<type>s :pluck ...) :uniq ...)]'
|
56
56
|
|
57
|
-
def_node_matcher :conservative_node_match,
|
58
|
-
format(PATTERN, type: 'const')
|
57
|
+
def_node_matcher :conservative_node_match, format(PATTERN, type: 'const')
|
59
58
|
|
60
|
-
def_node_matcher :aggressive_node_match,
|
61
|
-
format(PATTERN, type: '_')
|
59
|
+
def_node_matcher :aggressive_node_match, format(PATTERN, type: '_')
|
62
60
|
|
63
61
|
def on_send(node)
|
64
62
|
uniq = if style == :conservative
|
@@ -80,8 +78,7 @@ module RuboCop
|
|
80
78
|
private
|
81
79
|
|
82
80
|
def dot_method_with_whitespace(method, node)
|
83
|
-
range_between(dot_method_begin_pos(method, node),
|
84
|
-
node.loc.selector.end_pos)
|
81
|
+
range_between(dot_method_begin_pos(method, node), node.loc.selector.end_pos)
|
85
82
|
end
|
86
83
|
|
87
84
|
def dot_method_begin_pos(method, node)
|
@@ -59,9 +59,7 @@ module RuboCop
|
|
59
59
|
add_indices = schema.add_indices_by(table_name: table_name(klass))
|
60
60
|
|
61
61
|
(table.indices + add_indices).any? do |index|
|
62
|
-
index.unique &&
|
63
|
-
(index.columns.to_set == names ||
|
64
|
-
include_column_names_in_expression_index?(index, names))
|
62
|
+
index.unique && (index.columns.to_set == names || include_column_names_in_expression_index?(index, names))
|
65
63
|
end
|
66
64
|
end
|
67
65
|
|
@@ -19,8 +19,7 @@ module RuboCop
|
|
19
19
|
# Rails.env == 'production'
|
20
20
|
class UnknownEnv < Base
|
21
21
|
MSG = 'Unknown environment `%<name>s`.'
|
22
|
-
MSG_SIMILAR = 'Unknown environment `%<name>s`. '
|
23
|
-
'Did you mean `%<similar>s`?'
|
22
|
+
MSG_SIMILAR = 'Unknown environment `%<name>s`. Did you mean `%<similar>s`?'
|
24
23
|
|
25
24
|
def_node_matcher :rails_env?, <<~PATTERN
|
26
25
|
(send
|
@@ -79,8 +78,7 @@ module RuboCop
|
|
79
78
|
|
80
79
|
def unknown_env_predicate?(name)
|
81
80
|
name = name.to_s
|
82
|
-
name.end_with?('?') &&
|
83
|
-
!environments.include?(name[0..-2])
|
81
|
+
name.end_with?('?') && !environments.include?(name[0..-2])
|
84
82
|
end
|
85
83
|
|
86
84
|
def unknown_env_name?(name)
|