rubocop-rails 2.8.1 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +18 -2
  4. data/config/default.yml +144 -6
  5. data/config/obsoletion.yml +7 -0
  6. data/lib/rubocop/cop/mixin/active_record_helper.rb +15 -3
  7. data/lib/rubocop/cop/mixin/enforce_superclass.rb +40 -0
  8. data/lib/rubocop/cop/mixin/index_method.rb +8 -11
  9. data/lib/rubocop/cop/rails/action_filter.rb +10 -14
  10. data/lib/rubocop/cop/rails/active_record_aliases.rb +13 -17
  11. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +17 -12
  12. data/lib/rubocop/cop/rails/active_record_override.rb +1 -1
  13. data/lib/rubocop/cop/rails/active_support_aliases.rb +12 -21
  14. data/lib/rubocop/cop/rails/add_column_index.rb +64 -0
  15. data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
  16. data/lib/rubocop/cop/rails/application_controller.rb +3 -7
  17. data/lib/rubocop/cop/rails/application_job.rb +2 -1
  18. data/lib/rubocop/cop/rails/application_mailer.rb +2 -7
  19. data/lib/rubocop/cop/rails/application_record.rb +2 -7
  20. data/lib/rubocop/cop/rails/arel_star.rb +41 -0
  21. data/lib/rubocop/cop/rails/assert_not.rb +8 -10
  22. data/lib/rubocop/cop/rails/attribute_default_block_value.rb +90 -0
  23. data/lib/rubocop/cop/rails/belongs_to.rb +10 -19
  24. data/lib/rubocop/cop/rails/blank.rb +31 -27
  25. data/lib/rubocop/cop/rails/bulk_change_table.rb +1 -1
  26. data/lib/rubocop/cop/rails/content_tag.rb +33 -18
  27. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +2 -1
  28. data/lib/rubocop/cop/rails/date.rb +27 -17
  29. data/lib/rubocop/cop/rails/default_scope.rb +11 -4
  30. data/lib/rubocop/cop/rails/delegate.rb +9 -9
  31. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +7 -8
  32. data/lib/rubocop/cop/rails/dynamic_find_by.rb +16 -13
  33. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +78 -0
  34. data/lib/rubocop/cop/rails/enum_hash.rb +11 -10
  35. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -1
  36. data/lib/rubocop/cop/rails/environment_comparison.rb +18 -14
  37. data/lib/rubocop/cop/rails/environment_variable_access.rb +67 -0
  38. data/lib/rubocop/cop/rails/exit.rb +4 -10
  39. data/lib/rubocop/cop/rails/expanded_date_range.rb +86 -0
  40. data/lib/rubocop/cop/rails/file_path.rb +6 -7
  41. data/lib/rubocop/cop/rails/find_by.rb +32 -24
  42. data/lib/rubocop/cop/rails/find_by_id.rb +12 -21
  43. data/lib/rubocop/cop/rails/find_each.rb +19 -18
  44. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +3 -2
  45. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +37 -6
  46. data/lib/rubocop/cop/rails/helper_instance_variable.rb +29 -3
  47. data/lib/rubocop/cop/rails/http_positional_arguments.rb +26 -21
  48. data/lib/rubocop/cop/rails/http_status.rb +18 -11
  49. data/lib/rubocop/cop/rails/i18n_locale_assignment.rb +37 -0
  50. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +8 -6
  51. data/lib/rubocop/cop/rails/index_by.rb +2 -1
  52. data/lib/rubocop/cop/rails/index_with.rb +2 -1
  53. data/lib/rubocop/cop/rails/inquiry.rb +4 -3
  54. data/lib/rubocop/cop/rails/inverse_of.rb +3 -2
  55. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +17 -15
  56. data/lib/rubocop/cop/rails/link_to_blank.rb +25 -23
  57. data/lib/rubocop/cop/rails/mailer_name.rb +19 -13
  58. data/lib/rubocop/cop/rails/match_route.rb +14 -13
  59. data/lib/rubocop/cop/rails/negate_include.rb +10 -8
  60. data/lib/rubocop/cop/rails/not_null_column.rb +2 -1
  61. data/lib/rubocop/cop/rails/order_by_id.rb +1 -2
  62. data/lib/rubocop/cop/rails/output.rb +5 -2
  63. data/lib/rubocop/cop/rails/output_safety.rb +3 -2
  64. data/lib/rubocop/cop/rails/pick.rb +14 -12
  65. data/lib/rubocop/cop/rails/pluck.rb +6 -9
  66. data/lib/rubocop/cop/rails/pluck_id.rb +4 -6
  67. data/lib/rubocop/cop/rails/pluck_in_where.rb +7 -7
  68. data/lib/rubocop/cop/rails/pluralization_grammar.rb +10 -14
  69. data/lib/rubocop/cop/rails/presence.rb +12 -13
  70. data/lib/rubocop/cop/rails/present.rb +30 -24
  71. data/lib/rubocop/cop/rails/rake_environment.rb +8 -10
  72. data/lib/rubocop/cop/rails/read_write_attribute.rb +12 -11
  73. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +29 -31
  74. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +9 -12
  75. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +11 -10
  76. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -3
  77. data/lib/rubocop/cop/rails/refute_methods.rb +9 -10
  78. data/lib/rubocop/cop/rails/relative_date_constant.rb +34 -27
  79. data/lib/rubocop/cop/rails/render_inline.rb +2 -1
  80. data/lib/rubocop/cop/rails/render_plain_text.rb +9 -14
  81. data/lib/rubocop/cop/rails/request_referer.rb +7 -7
  82. data/lib/rubocop/cop/rails/require_dependency.rb +38 -0
  83. data/lib/rubocop/cop/rails/reversible_migration.rb +3 -7
  84. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +75 -0
  85. data/lib/rubocop/cop/rails/safe_navigation.rb +30 -11
  86. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +5 -10
  87. data/lib/rubocop/cop/rails/save_bang.rb +17 -20
  88. data/lib/rubocop/cop/rails/scope_args.rb +2 -1
  89. data/lib/rubocop/cop/rails/short_i18n.rb +7 -9
  90. data/lib/rubocop/cop/rails/skips_model_validations.rb +4 -4
  91. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +5 -6
  92. data/lib/rubocop/cop/rails/time_zone.rb +44 -42
  93. data/lib/rubocop/cop/rails/time_zone_assignment.rb +37 -0
  94. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +4 -6
  95. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +2 -2
  96. data/lib/rubocop/cop/rails/unknown_env.rb +3 -3
  97. data/lib/rubocop/cop/rails/unused_ignored_columns.rb +69 -0
  98. data/lib/rubocop/cop/rails/validation.rb +15 -14
  99. data/lib/rubocop/cop/rails/where_equals.rb +98 -0
  100. data/lib/rubocop/cop/rails/where_exists.rb +19 -13
  101. data/lib/rubocop/cop/rails/where_not.rb +10 -17
  102. data/lib/rubocop/cop/rails_cops.rb +13 -0
  103. data/lib/rubocop/rails.rb +2 -0
  104. data/lib/rubocop/rails/schema_loader.rb +4 -4
  105. data/lib/rubocop/rails/schema_loader/schema.rb +3 -5
  106. data/lib/rubocop/rails/version.rb +5 -1
  107. metadata +34 -14
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # validations which are listed in
8
8
  # https://guides.rubyonrails.org/active_record_validations.html#skipping-validations
9
9
  #
10
- # Methods may be ignored from this rule by configuring a `Whitelist`.
10
+ # Methods may be ignored from this rule by configuring a `AllowedMethods`.
11
11
  #
12
12
  # @example
13
13
  # # bad
@@ -26,7 +26,7 @@ module RuboCop
26
26
  # user.update(website: 'example.com')
27
27
  # FileUtils.touch('file')
28
28
  #
29
- # @example Whitelist: ["touch"]
29
+ # @example AllowedMethods: ["touch"]
30
30
  # # bad
31
31
  # DiscussionBoard.decrement_counter(:post_count, 5)
32
32
  # DiscussionBoard.increment_counter(:post_count, 5)
@@ -35,7 +35,7 @@ module RuboCop
35
35
  # # good
36
36
  # user.touch
37
37
  #
38
- class SkipsModelValidations < Cop
38
+ class SkipsModelValidations < Base
39
39
  MSG = 'Avoid using `%<method>s` because it skips validations.'
40
40
 
41
41
  METHODS_WITH_ARGUMENTS = %w[decrement!
@@ -76,7 +76,7 @@ module RuboCop
76
76
  return if good_touch?(node)
77
77
  return if good_insert?(node)
78
78
 
79
- add_offense(node, location: :selector)
79
+ add_offense(node.loc.selector, message: message(node))
80
80
  end
81
81
  alias on_csend on_send
82
82
 
@@ -5,6 +5,8 @@ module RuboCop
5
5
  module Rails
6
6
  #
7
7
  # Checks SQL heredocs to use `.squish`.
8
+ # Some SQL syntax (e.g. PostgreSQL comments and functions) requires newlines
9
+ # to be preserved in order to work, thus auto-correction for this cop is not safe.
8
10
  #
9
11
  # @example
10
12
  # # bad
@@ -37,8 +39,9 @@ module RuboCop
37
39
  # WHERE post_id = 1
38
40
  # SQL
39
41
  #
40
- class SquishedSQLHeredocs < Cop
42
+ class SquishedSQLHeredocs < Base
41
43
  include Heredoc
44
+ extend AutoCorrector
42
45
 
43
46
  SQL = 'SQL'
44
47
  SQUISH = '.squish'
@@ -47,11 +50,7 @@ module RuboCop
47
50
  def on_heredoc(node)
48
51
  return unless offense_detected?(node)
49
52
 
50
- add_offense(node)
51
- end
52
-
53
- def autocorrect(node)
54
- lambda do |corrector|
53
+ add_offense(node) do |corrector|
55
54
  corrector.insert_after(node, SQUISH)
56
55
  end
57
56
  end
@@ -8,43 +8,37 @@ module RuboCop
8
8
  # Built on top of Ruby on Rails style guide (https://rails.rubystyle.guide#time)
9
9
  # and the article http://danilenko.org/2012/7/6/rails_timezones/
10
10
  #
11
- # Two styles are supported for this cop. When EnforcedStyle is 'strict'
12
- # then only use of Time.zone is allowed.
11
+ # Two styles are supported for this cop. When `EnforcedStyle` is 'strict'
12
+ # then only use of `Time.zone` is allowed.
13
13
  #
14
14
  # When EnforcedStyle is 'flexible' then it's also allowed
15
- # to use Time.in_time_zone.
16
- #
17
- # @example EnforcedStyle: strict
18
- # # `strict` means that `Time` should be used with `zone`.
15
+ # to use `Time#in_time_zone`.
19
16
  #
17
+ # @example
20
18
  # # bad
21
19
  # Time.now
22
- # Time.parse('2015-03-02 19:05:37')
23
- #
24
- # # bad
25
- # Time.current
26
- # Time.at(timestamp).in_time_zone
20
+ # Time.parse('2015-03-02T19:05:37')
27
21
  #
28
22
  # # good
23
+ # Time.current
29
24
  # Time.zone.now
30
- # Time.zone.parse('2015-03-02 19:05:37')
25
+ # Time.zone.parse('2015-03-02T19:05:37')
26
+ # Time.zone.parse('2015-03-02T19:05:37Z') # Respect ISO 8601 format with timezone specifier.
31
27
  #
32
- # @example EnforcedStyle: flexible (default)
33
- # # `flexible` allows usage of `in_time_zone` instead of `zone`.
28
+ # @example EnforcedStyle: strict
29
+ # # `strict` means that `Time` should be used with `zone`.
34
30
  #
35
31
  # # bad
36
- # Time.now
37
- # Time.parse('2015-03-02 19:05:37')
32
+ # Time.at(timestamp).in_time_zone
38
33
  #
39
- # # good
40
- # Time.zone.now
41
- # Time.zone.parse('2015-03-02 19:05:37')
34
+ # @example EnforcedStyle: flexible (default)
35
+ # # `flexible` allows usage of `in_time_zone` instead of `zone`.
42
36
  #
43
37
  # # good
44
- # Time.current
45
38
  # Time.at(timestamp).in_time_zone
46
- class TimeZone < Cop
39
+ class TimeZone < Base
47
40
  include ConfigurableEnforcedStyle
41
+ extend AutoCorrector
48
42
 
49
43
  MSG = 'Do not use `%<current>s` without zone. Use `%<prefer>s` ' \
50
44
  'instead.'
@@ -57,11 +51,13 @@ module RuboCop
57
51
 
58
52
  GOOD_METHODS = %i[zone zone_default find_zone find_zone!].freeze
59
53
 
60
- DANGEROUS_METHODS = %i[now local new parse at current].freeze
54
+ DANGEROUS_METHODS = %i[now local new parse at].freeze
61
55
 
62
56
  ACCEPTED_METHODS = %i[in_time_zone utc getlocal xmlschema iso8601
63
57
  jisx0301 rfc3339 httpdate to_i to_f].freeze
64
58
 
59
+ TIMEZONE_SPECIFIER = /[A-z]/.freeze
60
+
65
61
  def on_const(node)
66
62
  mod, klass = *node
67
63
  # we should only check core classes
@@ -71,26 +67,24 @@ module RuboCop
71
67
  check_time_node(klass, node.parent) if klass == :Time
72
68
  end
73
69
 
74
- def autocorrect(node)
75
- lambda do |corrector|
76
- # add `.zone`: `Time.at` => `Time.zone.at`
77
- corrector.insert_after(node.children[0].source_range, '.zone')
70
+ private
78
71
 
79
- case node.method_name
80
- when :current
81
- # replace `Time.zone.current` => `Time.zone.now`
82
- corrector.replace(node.loc.selector, 'now')
83
- when :new
84
- autocorrect_time_new(node, corrector)
85
- end
72
+ def autocorrect(corrector, node)
73
+ # add `.zone`: `Time.at` => `Time.zone.at`
74
+ corrector.insert_after(node.children[0].source_range, '.zone')
86
75
 
87
- # prefer `Time` over `DateTime` class
88
- corrector.replace(node.children.first.source_range, 'Time') if strict?
89
- remove_redundant_in_time_zone(corrector, node)
76
+ case node.method_name
77
+ when :current
78
+ # replace `Time.zone.current` => `Time.zone.now`
79
+ corrector.replace(node.loc.selector, 'now')
80
+ when :new
81
+ autocorrect_time_new(node, corrector)
90
82
  end
91
- end
92
83
 
93
- private
84
+ # prefer `Time` over `DateTime` class
85
+ corrector.replace(node.children.first.source_range, 'Time') if strict?
86
+ remove_redundant_in_time_zone(corrector, node)
87
+ end
94
88
 
95
89
  def autocorrect_time_new(node, corrector)
96
90
  if node.arguments?
@@ -117,9 +111,10 @@ module RuboCop
117
111
  end
118
112
 
119
113
  def check_time_node(klass, node)
114
+ return if attach_timezone_specifier?(node.first_argument)
115
+
120
116
  chain = extract_method_chain(node)
121
117
  return if not_danger_chain?(chain)
122
-
123
118
  return check_localtime(node) if need_check_localtime?(chain)
124
119
 
125
120
  method_name = (chain & DANGEROUS_METHODS).join('.')
@@ -128,7 +123,13 @@ module RuboCop
128
123
 
129
124
  message = build_message(klass, method_name, node)
130
125
 
131
- add_offense(node, location: :selector, message: message)
126
+ add_offense(node.loc.selector, message: message) do |corrector|
127
+ autocorrect(corrector, node)
128
+ end
129
+ end
130
+
131
+ def attach_timezone_specifier?(date)
132
+ date.respond_to?(:value) && TIMEZONE_SPECIFIER.match?(date.value.to_s[-1])
132
133
  end
133
134
 
134
135
  def build_message(klass, method_name, node)
@@ -193,8 +194,9 @@ module RuboCop
193
194
 
194
195
  return if node.arguments?
195
196
 
196
- add_offense(selector_node,
197
- location: :selector, message: MSG_LOCALTIME)
197
+ add_offense(selector_node.loc.selector, message: MSG_LOCALTIME) do |corrector|
198
+ autocorrect(corrector, selector_node)
199
+ end
198
200
  end
199
201
 
200
202
  def not_danger_chain?(chain)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks for the use of `Time.zone=` method.
7
+ #
8
+ # The `zone` attribute persists for the rest of the Ruby runtime, potentially causing
9
+ # unexpected behavior at a later time.
10
+ # Using `Time.use_zone` ensures the code passed in the block is the only place Time.zone is affected.
11
+ # It eliminates the possibility of a `zone` sticking around longer than intended.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # Time.zone = 'EST'
16
+ #
17
+ # # good
18
+ # Time.use_zone('EST') do
19
+ # end
20
+ #
21
+ class TimeZoneAssignment < Base
22
+ MSG = 'Use `Time.use_zone` with block instead of `Time.zone=`.'
23
+ RESTRICT_ON_SEND = %i[zone=].freeze
24
+
25
+ def_node_matcher :time_zone_assignement?, <<~PATTERN
26
+ (send (const nil? :Time) :zone= ...)
27
+ PATTERN
28
+
29
+ def on_send(node)
30
+ return unless time_zone_assignement?(node)
31
+
32
+ add_offense(node)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -45,11 +45,13 @@ module RuboCop
45
45
  # # good
46
46
  # Model.distinct.pluck(:id)
47
47
  #
48
- class UniqBeforePluck < RuboCop::Cop::Cop
48
+ class UniqBeforePluck < Base
49
49
  include ConfigurableEnforcedStyle
50
50
  include RangeHelp
51
+ extend AutoCorrector
51
52
 
52
53
  MSG = 'Use `distinct` before `pluck`.'
54
+ RESTRICT_ON_SEND = %i[uniq distinct pluck].freeze
53
55
  NEWLINE = "\n"
54
56
  PATTERN = '[!^block (send (send %<type>s :pluck ...) ' \
55
57
  '${:uniq :distinct} ...)]'
@@ -69,11 +71,7 @@ module RuboCop
69
71
 
70
72
  return unless method
71
73
 
72
- add_offense(node, location: :selector)
73
- end
74
-
75
- def autocorrect(node)
76
- lambda do |corrector|
74
+ add_offense(node.loc.selector) do |corrector|
77
75
  method = node.method_name
78
76
 
79
77
  corrector.remove(dot_method_with_whitespace(method, node))
@@ -24,13 +24,13 @@ module RuboCop
24
24
  # # good - even if the schema does not have a unique index
25
25
  # validates :account, length: { minimum: MIN_LENGTH }
26
26
  #
27
- class UniqueValidationWithoutIndex < Cop
27
+ class UniqueValidationWithoutIndex < Base
28
28
  include ActiveRecordHelper
29
29
 
30
30
  MSG = 'Uniqueness validation should be with a unique index.'
31
+ RESTRICT_ON_SEND = %i[validates].freeze
31
32
 
32
33
  def on_send(node)
33
- return unless node.method?(:validates)
34
34
  return unless uniqueness_part(node)
35
35
  return if condition_part?(node)
36
36
  return unless schema
@@ -17,7 +17,7 @@ module RuboCop
17
17
  # # good
18
18
  # Rails.env.production?
19
19
  # Rails.env == 'production'
20
- class UnknownEnv < Cop
20
+ class UnknownEnv < Base
21
21
  MSG = 'Unknown environment `%<name>s`.'
22
22
  MSG_SIMILAR = 'Unknown environment `%<name>s`. ' \
23
23
  'Did you mean `%<similar>s`?'
@@ -41,7 +41,7 @@ module RuboCop
41
41
 
42
42
  def on_send(node)
43
43
  unknown_environment_predicate?(node) do |name|
44
- add_offense(node, location: :selector, message: message(name))
44
+ add_offense(node.loc.selector, message: message(name))
45
45
  end
46
46
 
47
47
  unknown_environment_equal?(node) do |str_node|
@@ -62,7 +62,7 @@ module RuboCop
62
62
  # DidYouMean::SpellChecker is not available in all versions of Ruby,
63
63
  # and even on versions where it *is* available (>= 2.3), it is not
64
64
  # always required correctly. So we do a feature check first. See:
65
- # https://github.com/rubocop-hq/rubocop/issues/7979
65
+ # https://github.com/rubocop/rubocop/issues/7979
66
66
  similar_names = if defined?(DidYouMean::SpellChecker)
67
67
  spell_checker = DidYouMean::SpellChecker.new(dictionary: environments)
68
68
  spell_checker.correct(name)
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop suggests you remove a column that does not exist in the schema from `ignored_columns`.
7
+ # `ignored_columns` is necessary to drop a column from RDBMS, but you don't need it after the migration
8
+ # to drop the column. You avoid forgetting to remove `ignored_columns` by this cop.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # class User < ApplicationRecord
13
+ # self.ignored_columns = [:already_removed_column]
14
+ # end
15
+ #
16
+ # # good
17
+ # class User < ApplicationRecord
18
+ # self.ignored_columns = [:still_existing_column]
19
+ # end
20
+ #
21
+ class UnusedIgnoredColumns < Base
22
+ include ActiveRecordHelper
23
+
24
+ MSG = 'Remove `%<column_name>s` from `ignored_columns` because the column does not exist.'
25
+ RESTRICT_ON_SEND = %i[ignored_columns=].freeze
26
+
27
+ def_node_matcher :ignored_columns, <<~PATTERN
28
+ (send self :ignored_columns= $array)
29
+ PATTERN
30
+
31
+ def_node_matcher :column_name, <<~PATTERN
32
+ ({str sym} $_)
33
+ PATTERN
34
+
35
+ def on_send(node)
36
+ return unless (columns = ignored_columns(node))
37
+ return unless schema
38
+
39
+ table = table(node)
40
+ return unless table
41
+
42
+ columns.children.each do |column_node|
43
+ check_column_existence(column_node, table)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def check_column_existence(column_node, table)
50
+ column_name = column_name(column_node)
51
+ return unless column_name
52
+ return if table.with_column?(name: column_name.to_s)
53
+
54
+ message = format(MSG, column_name: column_name)
55
+ add_offense(column_node, message: message)
56
+ end
57
+
58
+ def class_node(node)
59
+ node.each_ancestor.find(&:class_type?)
60
+ end
61
+
62
+ def table(node)
63
+ klass = class_node(node)
64
+ schema.table_by(name: table_name(klass))
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -32,7 +32,9 @@ module RuboCop
32
32
  # validates :foo, size: true
33
33
  # validates :foo, uniqueness: true
34
34
  #
35
- class Validation < Cop
35
+ class Validation < Base
36
+ extend AutoCorrector
37
+
36
38
  MSG = 'Prefer the new style validations `%<prefer>s` over ' \
37
39
  '`%<current>s`.'
38
40
 
@@ -50,22 +52,20 @@ module RuboCop
50
52
  uniqueness
51
53
  ].freeze
52
54
 
53
- DENYLIST = TYPES.map { |p| "validates_#{p}_of".to_sym }.freeze
55
+ RESTRICT_ON_SEND = TYPES.map { |p| "validates_#{p}_of".to_sym }.freeze
54
56
  ALLOWLIST = TYPES.map { |p| "validates :column, #{p}: value" }.freeze
55
57
 
56
58
  def on_send(node)
57
- return unless !node.receiver && DENYLIST.include?(node.method_name)
59
+ return if node.receiver
58
60
 
59
- add_offense(node, location: :selector)
60
- end
61
+ range = node.loc.selector
61
62
 
62
- def autocorrect(node)
63
- last_argument = node.arguments.last
64
- return if !last_argument.literal? && !last_argument.splat_type? &&
65
- !frozen_array_argument?(last_argument)
63
+ add_offense(range, message: message(node)) do |corrector|
64
+ last_argument = node.arguments.last
65
+ return if !last_argument.literal? && !last_argument.splat_type? &&
66
+ !frozen_array_argument?(last_argument)
66
67
 
67
- lambda do |corrector|
68
- corrector.replace(node.loc.selector, 'validates')
68
+ corrector.replace(range, 'validates')
69
69
  correct_validate_type(corrector, node)
70
70
  end
71
71
  end
@@ -73,12 +73,13 @@ module RuboCop
73
73
  private
74
74
 
75
75
  def message(node)
76
- format(MSG, prefer: preferred_method(node.method_name),
77
- current: node.method_name)
76
+ method_name = node.method_name
77
+
78
+ format(MSG, prefer: preferred_method(method_name), current: method_name)
78
79
  end
79
80
 
80
81
  def preferred_method(method)
81
- ALLOWLIST[DENYLIST.index(method.to_sym)]
82
+ ALLOWLIST[RESTRICT_ON_SEND.index(method.to_sym)]
82
83
  end
83
84
 
84
85
  def correct_validate_type(corrector, node)