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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +80 -0
  3. data/config/obsoletion.yml +10 -0
  4. data/lib/rubocop/cop/mixin/active_record_helper.rb +1 -4
  5. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
  6. data/lib/rubocop/cop/mixin/index_method.rb +5 -15
  7. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +98 -0
  8. data/lib/rubocop/cop/rails/action_filter.rb +1 -1
  9. data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
  10. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  11. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  12. data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
  13. data/lib/rubocop/cop/rails/blank.rb +1 -2
  14. data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
  15. data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
  16. data/lib/rubocop/cop/rails/content_tag.rb +1 -3
  17. data/lib/rubocop/cop/rails/date.rb +4 -9
  18. data/lib/rubocop/cop/rails/delegate.rb +2 -5
  19. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
  20. data/lib/rubocop/cop/rails/dot_separated_keys.rb +1 -1
  21. data/lib/rubocop/cop/rails/dynamic_find_by.rb +2 -4
  22. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
  23. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
  24. data/lib/rubocop/cop/rails/file_path.rb +2 -4
  25. data/lib/rubocop/cop/rails/find_each.rb +8 -2
  26. data/lib/rubocop/cop/rails/freeze_time.rb +69 -0
  27. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -3
  28. data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
  29. data/lib/rubocop/cop/rails/http_status.rb +5 -10
  30. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
  31. data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
  32. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
  33. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
  34. data/lib/rubocop/cop/rails/output.rb +2 -5
  35. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
  36. data/lib/rubocop/cop/rails/presence.rb +1 -3
  37. data/lib/rubocop/cop/rails/present.rb +3 -6
  38. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  39. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
  40. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  41. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +2 -2
  42. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +28 -26
  43. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
  44. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  45. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
  46. data/lib/rubocop/cop/rails/request_referer.rb +1 -2
  47. data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
  48. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
  49. data/lib/rubocop/cop/rails/root_pathname_methods.rb +175 -0
  50. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
  51. data/lib/rubocop/cop/rails/save_bang.rb +10 -22
  52. data/lib/rubocop/cop/rails/short_i18n.rb +1 -4
  53. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -2
  54. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
  55. data/lib/rubocop/cop/rails/time_zone.rb +8 -19
  56. data/lib/rubocop/cop/rails/to_s_with_argument.rb +41 -0
  57. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +48 -0
  58. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  59. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
  60. data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
  61. data/lib/rubocop/cop/rails/validation.rb +4 -12
  62. data/lib/rubocop/cop/rails/where_missing.rb +111 -0
  63. data/lib/rubocop/cop/rails_cops.rb +7 -0
  64. data/lib/rubocop/rails/version.rb +1 -1
  65. metadata +13 -8
  66. data/bin/console +0 -11
  67. 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
- 'value is not checked.'
126
- CREATE_MSG = (MSG +
127
- ' Or check `persisted?` on model returned from ' \
128
- '`%<current>s`.').freeze
129
- CREATE_CONDITIONAL_MSG = '`%<current>s` returns a model which is ' \
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
 
@@ -93,8 +93,7 @@ module RuboCop
93
93
  end
94
94
 
95
95
  def allowed_method?(node)
96
- METHODS_WITH_ARGUMENTS.include?(node.method_name.to_s) &&
97
- !node.arguments?
96
+ METHODS_WITH_ARGUMENTS.include?(node.method_name.to_s) && !node.arguments?
98
97
  end
99
98
 
100
99
  def forbidden_methods
@@ -72,11 +72,7 @@ module RuboCop
72
72
  end
73
73
 
74
74
  def message(node)
75
- format(
76
- MSG,
77
- expect: "#{node.source}#{SQUISH}",
78
- current: node.source
79
- )
75
+ format(MSG, expect: "#{node.source}#{SQUISH}", current: node.source)
80
76
  end
81
77
  end
82
78
  end
@@ -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)