rubocop-rails 2.14.2 → 2.19.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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -2
  4. data/config/default.yml +190 -12
  5. data/config/obsoletion.yml +10 -0
  6. data/lib/rubocop/cop/mixin/active_record_helper.rb +3 -6
  7. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
  8. data/lib/rubocop/cop/mixin/enforce_superclass.rb +1 -1
  9. data/lib/rubocop/cop/mixin/index_method.rb +7 -17
  10. data/lib/rubocop/cop/mixin/migrations_helper.rb +1 -1
  11. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +112 -0
  12. data/lib/rubocop/cop/rails/action_controller_test_case.rb +2 -2
  13. data/lib/rubocop/cop/rails/action_filter.rb +2 -2
  14. data/lib/rubocop/cop/rails/action_order.rb +116 -0
  15. data/lib/rubocop/cop/rails/active_record_aliases.rb +3 -4
  16. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +7 -4
  17. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  18. data/lib/rubocop/cop/rails/active_support_aliases.rb +1 -1
  19. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  20. data/lib/rubocop/cop/rails/add_column_index.rb +3 -6
  21. data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
  22. data/lib/rubocop/cop/rails/application_controller.rb +2 -2
  23. data/lib/rubocop/cop/rails/application_job.rb +3 -3
  24. data/lib/rubocop/cop/rails/application_mailer.rb +2 -2
  25. data/lib/rubocop/cop/rails/application_record.rb +2 -2
  26. data/lib/rubocop/cop/rails/arel_star.rb +2 -2
  27. data/lib/rubocop/cop/rails/assert_not.rb +1 -1
  28. data/lib/rubocop/cop/rails/attribute_default_block_value.rb +1 -1
  29. data/lib/rubocop/cop/rails/belongs_to.rb +2 -5
  30. data/lib/rubocop/cop/rails/blank.rb +10 -11
  31. data/lib/rubocop/cop/rails/bulk_change_table.rb +8 -25
  32. data/lib/rubocop/cop/rails/compact_blank.rb +6 -2
  33. data/lib/rubocop/cop/rails/content_tag.rb +6 -7
  34. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +16 -3
  35. data/lib/rubocop/cop/rails/date.rb +12 -17
  36. data/lib/rubocop/cop/rails/default_scope.rb +1 -1
  37. data/lib/rubocop/cop/rails/delegate.rb +24 -18
  38. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +2 -2
  39. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +63 -3
  40. data/lib/rubocop/cop/rails/dot_separated_keys.rb +71 -0
  41. data/lib/rubocop/cop/rails/duplicate_association.rb +2 -2
  42. data/lib/rubocop/cop/rails/duplicate_scope.rb +1 -1
  43. data/lib/rubocop/cop/rails/duration_arithmetic.rb +4 -4
  44. data/lib/rubocop/cop/rails/dynamic_find_by.rb +26 -14
  45. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +6 -2
  46. data/lib/rubocop/cop/rails/enum_hash.rb +3 -4
  47. data/lib/rubocop/cop/rails/enum_uniqueness.rb +3 -6
  48. data/lib/rubocop/cop/rails/environment_comparison.rb +3 -4
  49. data/lib/rubocop/cop/rails/environment_variable_access.rb +1 -1
  50. data/lib/rubocop/cop/rails/exit.rb +1 -1
  51. data/lib/rubocop/cop/rails/expanded_date_range.rb +39 -23
  52. data/lib/rubocop/cop/rails/file_path.rb +41 -24
  53. data/lib/rubocop/cop/rails/find_by.rb +1 -1
  54. data/lib/rubocop/cop/rails/find_by_id.rb +3 -3
  55. data/lib/rubocop/cop/rails/find_each.rb +14 -4
  56. data/lib/rubocop/cop/rails/freeze_time.rb +79 -0
  57. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +1 -1
  58. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +14 -8
  59. data/lib/rubocop/cop/rails/helper_instance_variable.rb +3 -3
  60. data/lib/rubocop/cop/rails/http_positional_arguments.rb +23 -12
  61. data/lib/rubocop/cop/rails/http_status.rb +6 -11
  62. data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +3 -1
  63. data/lib/rubocop/cop/rails/i18n_locale_assignment.rb +1 -1
  64. data/lib/rubocop/cop/rails/i18n_locale_texts.rb +2 -2
  65. data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
  66. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +5 -14
  67. data/lib/rubocop/cop/rails/index_by.rb +2 -2
  68. data/lib/rubocop/cop/rails/index_with.rb +2 -2
  69. data/lib/rubocop/cop/rails/inquiry.rb +1 -1
  70. data/lib/rubocop/cop/rails/inverse_of.rb +4 -10
  71. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +22 -16
  72. data/lib/rubocop/cop/rails/link_to_blank.rb +2 -5
  73. data/lib/rubocop/cop/rails/mailer_name.rb +5 -5
  74. data/lib/rubocop/cop/rails/match_route.rb +1 -1
  75. data/lib/rubocop/cop/rails/migration_class_name.rb +2 -2
  76. data/lib/rubocop/cop/rails/negate_include.rb +2 -2
  77. data/lib/rubocop/cop/rails/not_null_column.rb +10 -7
  78. data/lib/rubocop/cop/rails/order_by_id.rb +2 -3
  79. data/lib/rubocop/cop/rails/output.rb +7 -9
  80. data/lib/rubocop/cop/rails/output_safety.rb +6 -2
  81. data/lib/rubocop/cop/rails/pick.rb +1 -1
  82. data/lib/rubocop/cop/rails/pluck.rb +45 -13
  83. data/lib/rubocop/cop/rails/pluck_id.rb +2 -2
  84. data/lib/rubocop/cop/rails/pluck_in_where.rb +1 -1
  85. data/lib/rubocop/cop/rails/pluralization_grammar.rb +2 -3
  86. data/lib/rubocop/cop/rails/presence.rb +22 -13
  87. data/lib/rubocop/cop/rails/present.rb +10 -13
  88. data/lib/rubocop/cop/rails/rake_environment.rb +3 -3
  89. data/lib/rubocop/cop/rails/read_write_attribute.rb +2 -2
  90. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +5 -7
  91. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +3 -3
  92. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
  93. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +31 -27
  94. data/lib/rubocop/cop/rails/redundant_travel_back.rb +1 -1
  95. data/lib/rubocop/cop/rails/reflection_class_name.rb +35 -2
  96. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  97. data/lib/rubocop/cop/rails/relative_date_constant.rb +5 -8
  98. data/lib/rubocop/cop/rails/render_inline.rb +1 -1
  99. data/lib/rubocop/cop/rails/render_plain_text.rb +1 -1
  100. data/lib/rubocop/cop/rails/request_referer.rb +2 -3
  101. data/lib/rubocop/cop/rails/require_dependency.rb +2 -2
  102. data/lib/rubocop/cop/rails/response_parsed_body.rb +57 -0
  103. data/lib/rubocop/cop/rails/reversible_migration.rb +15 -63
  104. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +5 -6
  105. data/lib/rubocop/cop/rails/root_join_chain.rb +1 -1
  106. data/lib/rubocop/cop/rails/root_pathname_methods.rb +238 -0
  107. data/lib/rubocop/cop/rails/root_public_path.rb +59 -0
  108. data/lib/rubocop/cop/rails/safe_navigation.rb +8 -13
  109. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +2 -4
  110. data/lib/rubocop/cop/rails/save_bang.rb +12 -24
  111. data/lib/rubocop/cop/rails/schema_comment.rb +1 -1
  112. data/lib/rubocop/cop/rails/scope_args.rb +1 -1
  113. data/lib/rubocop/cop/rails/short_i18n.rb +3 -6
  114. data/lib/rubocop/cop/rails/skips_model_validations.rb +3 -4
  115. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +10 -7
  116. data/lib/rubocop/cop/rails/strip_heredoc.rb +56 -0
  117. data/lib/rubocop/cop/rails/table_name_assignment.rb +1 -1
  118. data/lib/rubocop/cop/rails/three_state_boolean_column.rb +73 -0
  119. data/lib/rubocop/cop/rails/time_zone.rb +34 -32
  120. data/lib/rubocop/cop/rails/time_zone_assignment.rb +4 -4
  121. data/lib/rubocop/cop/rails/to_formatted_s.rb +46 -0
  122. data/lib/rubocop/cop/rails/to_s_with_argument.rb +78 -0
  123. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  124. data/lib/rubocop/cop/rails/transaction_exit_statement.rb +17 -12
  125. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  126. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +14 -7
  127. data/lib/rubocop/cop/rails/unknown_env.rb +3 -5
  128. data/lib/rubocop/cop/rails/unused_ignored_columns.rb +7 -2
  129. data/lib/rubocop/cop/rails/validation.rb +5 -13
  130. data/lib/rubocop/cop/rails/where_equals.rb +2 -2
  131. data/lib/rubocop/cop/rails/where_exists.rb +3 -3
  132. data/lib/rubocop/cop/rails/where_missing.rb +118 -0
  133. data/lib/rubocop/cop/rails/where_not.rb +2 -2
  134. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
  135. data/lib/rubocop/cop/rails_cops.rb +16 -0
  136. data/lib/rubocop/rails/schema_loader/schema.rb +8 -5
  137. data/lib/rubocop/rails/version.rb +1 -1
  138. data/lib/rubocop/rails.rb +1 -1
  139. data/lib/rubocop-rails.rb +19 -0
  140. metadata +23 -9
  141. data/bin/console +0 -11
  142. data/bin/setup +0 -7
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Using `flash` assignment before `render` in Rails controllers will persist the message for too long.
7
+ # Check https://guides.rubyonrails.org/action_controller_overview.html#flash-now
8
+ #
9
+ # @safety
10
+ # This cop's autocorrection is unsafe because it replaces `flash` by `flash.now`.
11
+ # Even though it is usually a mistake, it might be used intentionally.
12
+ #
13
+ # @example
14
+ #
15
+ # # bad
16
+ # class HomeController < ApplicationController
17
+ # def create
18
+ # flash[:alert] = "msg"
19
+ # render :index
20
+ # end
21
+ # end
22
+ #
23
+ # # good
24
+ # class HomeController < ApplicationController
25
+ # def create
26
+ # flash.now[:alert] = "msg"
27
+ # render :index
28
+ # end
29
+ # end
30
+ #
31
+ class ActionControllerFlashBeforeRender < Base
32
+ extend AutoCorrector
33
+
34
+ MSG = 'Use `flash.now` before `render`.'
35
+
36
+ def_node_search :flash_assignment?, <<~PATTERN
37
+ ^(send (send nil? :flash) :[]= ...)
38
+ PATTERN
39
+
40
+ def_node_search :render?, <<~PATTERN
41
+ (send nil? :render ...)
42
+ PATTERN
43
+
44
+ def_node_search :action_controller?, <<~PATTERN
45
+ {
46
+ (const {nil? cbase} :ApplicationController)
47
+ (const (const {nil? cbase} :ActionController) :Base)
48
+ }
49
+ PATTERN
50
+
51
+ RESTRICT_ON_SEND = [:flash].freeze
52
+
53
+ def on_send(flash_node)
54
+ return unless flash_assignment?(flash_node)
55
+
56
+ return unless followed_by_render?(flash_node)
57
+
58
+ return unless instance_method_or_block?(flash_node)
59
+
60
+ return unless inherit_action_controller_base?(flash_node)
61
+
62
+ add_offense(flash_node) do |corrector|
63
+ corrector.replace(flash_node, 'flash.now')
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def followed_by_render?(flash_node)
70
+ flash_assignment_node = find_ancestor(flash_node, type: :send)
71
+ context = flash_assignment_node
72
+ if (node = context.each_ancestor(:if, :rescue).first)
73
+ return false if use_redirect_to?(context)
74
+
75
+ context = node
76
+ elsif context.right_siblings.empty?
77
+ return true
78
+ end
79
+ context = context.right_siblings
80
+
81
+ context.compact.any? do |render_candidate|
82
+ render?(render_candidate)
83
+ end
84
+ end
85
+
86
+ def inherit_action_controller_base?(node)
87
+ class_node = find_ancestor(node, type: :class)
88
+ return unless class_node
89
+
90
+ action_controller?(class_node)
91
+ end
92
+
93
+ def instance_method_or_block?(node)
94
+ def_node = find_ancestor(node, type: :def)
95
+ block_node = find_ancestor(node, type: :block)
96
+
97
+ def_node || block_node
98
+ end
99
+
100
+ def use_redirect_to?(context)
101
+ context.right_siblings.compact.any? do |sibling|
102
+ sibling.send_type? && sibling.method?(:redirect_to)
103
+ end
104
+ end
105
+
106
+ def find_ancestor(node, type:)
107
+ node.each_ancestor(type).first
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -30,8 +30,8 @@ module RuboCop
30
30
 
31
31
  def_node_matcher :action_controller_test_case?, <<~PATTERN
32
32
  (class
33
- (const nil? _)
34
- (const (const {nil? cbase} :ActionController) :TestCase) nil?)
33
+ (const _ _)
34
+ (const (const {nil? cbase} :ActionController) :TestCase) _)
35
35
  PATTERN
36
36
 
37
37
  def on_class(node)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop enforces the consistent use of action filter methods.
6
+ # Enforces the consistent use of action filter methods.
7
7
  #
8
8
  # The cop is configurable and can enforce the use of the older
9
9
  # something_filter methods or the newer something_action methods.
@@ -69,7 +69,7 @@ module RuboCop
69
69
 
70
70
  RESTRICT_ON_SEND = FILTER_METHODS + ACTION_METHODS
71
71
 
72
- def on_block(node)
72
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
73
73
  check_method_node(node.send_node)
74
74
  end
75
75
 
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Enforces consistent ordering of the standard Rails RESTful controller actions.
7
+ #
8
+ # The cop is configurable and can enforce any ordering of the standard actions.
9
+ # All other methods are ignored. So, the actions specified in `ExpectedOrder` should be
10
+ # defined before actions not specified.
11
+ #
12
+ # [source,yaml]
13
+ # ----
14
+ # Rails/ActionOrder:
15
+ # ExpectedOrder:
16
+ # - index
17
+ # - show
18
+ # - new
19
+ # - edit
20
+ # - create
21
+ # - update
22
+ # - destroy
23
+ # ----
24
+ #
25
+ # @example
26
+ # # bad
27
+ # def index; end
28
+ # def destroy; end
29
+ # def show; end
30
+ #
31
+ # # good
32
+ # def index; end
33
+ # def show; end
34
+ # def destroy; end
35
+ class ActionOrder < Base
36
+ extend AutoCorrector
37
+ include VisibilityHelp
38
+ include DefNode
39
+ include RangeHelp
40
+
41
+ MSG = 'Action `%<current>s` should appear before `%<previous>s`.'
42
+
43
+ def_node_search :action_declarations, '(def {%1} ...)'
44
+
45
+ def on_class(node)
46
+ action_declarations(node, actions).each_cons(2) do |previous, current|
47
+ next if node_visibility(current) != :public || non_public?(current)
48
+ next if find_index(current) >= find_index(previous)
49
+
50
+ register_offense(previous, current)
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def expected_order
57
+ cop_config['ExpectedOrder'].map(&:to_sym)
58
+ end
59
+
60
+ def actions
61
+ @actions ||= Set.new(expected_order)
62
+ end
63
+
64
+ def find_index(node)
65
+ expected_order.find_index(node.method_name)
66
+ end
67
+
68
+ def register_offense(previous, current)
69
+ message = format(
70
+ MSG,
71
+ expected_order: expected_order.join(', '),
72
+ previous: previous.method_name,
73
+ current: current.method_name
74
+ )
75
+ add_offense(current, message: message) do |corrector|
76
+ current = correction_target(current)
77
+ previous = correction_target(previous)
78
+
79
+ swap_range(corrector, current, previous)
80
+ end
81
+ end
82
+
83
+ def correction_target(def_node)
84
+ range_with_comments_and_lines(def_node.each_ancestor(:if).first || def_node)
85
+ end
86
+
87
+ def add_range(range1, range2)
88
+ range1.with(
89
+ begin_pos: [range1.begin_pos, range2.begin_pos].min,
90
+ end_pos: [range1.end_pos, range2.end_pos].max
91
+ )
92
+ end
93
+
94
+ def range_with_comments(node)
95
+ # rubocop:todo InternalAffairs/LocationExpression
96
+ # Using `RuboCop::Ext::Comment#source_range` requires RuboCop > 1.46,
97
+ # which introduces https://github.com/rubocop/rubocop/pull/11630.
98
+ ranges = [node, *processed_source.ast_with_comments[node]].map { |comment| comment.loc.expression }
99
+ # rubocop:enable InternalAffairs/LocationExpression
100
+ ranges.reduce do |result, range|
101
+ add_range(result, range)
102
+ end
103
+ end
104
+
105
+ def range_with_comments_and_lines(node)
106
+ range_by_whole_lines(range_with_comments(node), include_final_newline: true)
107
+ end
108
+
109
+ def swap_range(corrector, range1, range2)
110
+ corrector.insert_before(range2, range1.source)
111
+ corrector.remove(range1)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -21,14 +21,13 @@ module RuboCop
21
21
 
22
22
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
23
23
 
24
- ALIASES = {
25
- update_attributes: :update,
26
- update_attributes!: :update!
27
- }.freeze
24
+ ALIASES = { update_attributes: :update, update_attributes!: :update! }.freeze
28
25
 
29
26
  RESTRICT_ON_SEND = ALIASES.keys.freeze
30
27
 
31
28
  def on_send(node)
29
+ return if node.arguments.empty?
30
+
32
31
  method_name = node.method_name
33
32
  alias_method = ALIASES[method_name]
34
33
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that Active Record callbacks are declared
6
+ # Checks that Active Record callbacks are declared
7
7
  # in the order in which they will be executed.
8
8
  #
9
9
  # @example
@@ -104,7 +104,7 @@ module RuboCop
104
104
  end
105
105
 
106
106
  def end_position_for(node)
107
- end_line = buffer.line_for_position(node.loc.expression.end_pos)
107
+ end_line = buffer.line_for_position(node.source_range.end_pos)
108
108
  buffer.line_range(end_line).end_pos
109
109
  end
110
110
 
@@ -112,8 +112,7 @@ module RuboCop
112
112
  annotation_line = node.first_line - 1
113
113
  first_comment = nil
114
114
 
115
- processed_source.comments_before_line(annotation_line)
116
- .reverse_each do |comment|
115
+ processed_source.each_comment_in_lines(0..annotation_line).reverse_each do |comment|
117
116
  if comment.location.line == annotation_line && !inline_comment?(comment)
118
117
  first_comment = comment
119
118
  annotation_line -= 1
@@ -124,7 +123,11 @@ module RuboCop
124
123
  end
125
124
 
126
125
  def inline_comment?(comment)
126
+ # rubocop:todo InternalAffairs/LocationExpression
127
+ # Using `RuboCop::Ext::Comment#source_range` requires RuboCop > 1.46,
128
+ # which introduces https://github.com/rubocop/rubocop/pull/11630.
127
129
  !comment_line?(comment.loc.expression.source_line)
130
+ # rubocop:enable InternalAffairs/LocationExpression
128
131
  end
129
132
 
130
133
  def start_line_position(node)
@@ -25,12 +25,9 @@ module RuboCop
25
25
  # end
26
26
  #
27
27
  class ActiveRecordOverride < Base
28
- MSG =
29
- 'Use %<prefer>s callbacks instead of overriding the Active Record ' \
30
- 'method `%<bad>s`.'
28
+ MSG = 'Use %<prefer>s callbacks instead of overriding the Active Record method `%<bad>s`.'
31
29
  BAD_METHODS = %i[create destroy save update].freeze
32
- ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base
33
- ActiveRecord::Base].freeze
30
+ ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base ActiveRecord::Base].freeze
34
31
 
35
32
  def on_def(node)
36
33
  return unless BAD_METHODS.include?(node.method_name)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that ActiveSupport aliases to core ruby methods
6
+ # Checks that ActiveSupport aliases to core ruby methods
7
7
  # are not used.
8
8
  #
9
9
  # @example
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Checks for Rails framework classes that are patched directly instead of using Active Support load hooks. Direct
7
+ # patching forcibly loads the framework referenced, using hooks defers loading until it's actually needed.
8
+ #
9
+ # @safety
10
+ # While using lazy load hooks is recommended, it changes the order in which is code is loaded and may reveal
11
+ # load order dependency bugs.
12
+ #
13
+ # @example
14
+ #
15
+ # # bad
16
+ # ActiveRecord::Base.include(MyClass)
17
+ #
18
+ # # good
19
+ # ActiveSupport.on_load(:active_record) { include MyClass }
20
+ class ActiveSupportOnLoad < Base
21
+ extend AutoCorrector
22
+
23
+ MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
24
+ RESTRICT_ON_SEND = %i[prepend include extend].freeze
25
+ LOAD_HOOKS = {
26
+ 'ActionCable' => 'action_cable',
27
+ 'ActionCable::Channel::Base' => 'action_cable_channel',
28
+ 'ActionCable::Connection::Base' => 'action_cable_connection',
29
+ 'ActionCable::Connection::TestCase' => 'action_cable_connection_test_case',
30
+ 'ActionController::API' => 'action_controller',
31
+ 'ActionController::Base' => 'action_controller',
32
+ 'ActionController::TestCase' => 'action_controller_test_case',
33
+ 'ActionDispatch::IntegrationTest' => 'action_dispatch_integration_test',
34
+ 'ActionDispatch::Request' => 'action_dispatch_request',
35
+ 'ActionDispatch::Response' => 'action_dispatch_response',
36
+ 'ActionDispatch::SystemTestCase' => 'action_dispatch_system_test_case',
37
+ 'ActionMailbox::Base' => 'action_mailbox',
38
+ 'ActionMailbox::InboundEmail' => 'action_mailbox_inbound_email',
39
+ 'ActionMailbox::Record' => 'action_mailbox_record',
40
+ 'ActionMailbox::TestCase' => 'action_mailbox_test_case',
41
+ 'ActionMailer::Base' => 'action_mailer',
42
+ 'ActionMailer::TestCase' => 'action_mailer_test_case',
43
+ 'ActionText::Content' => 'action_text_content',
44
+ 'ActionText::Record' => 'action_text_record',
45
+ 'ActionText::RichText' => 'action_text_rich_text',
46
+ 'ActionView::Base' => 'action_view',
47
+ 'ActionView::TestCase' => 'action_view_test_case',
48
+ 'ActiveJob::Base' => 'active_job',
49
+ 'ActiveJob::TestCase' => 'active_job_test_case',
50
+ 'ActiveRecord::Base' => 'active_record',
51
+ 'ActiveStorage::Attachment' => 'active_storage_attachment',
52
+ 'ActiveStorage::Blob' => 'active_storage_blob',
53
+ 'ActiveStorage::Record' => 'active_storage_record',
54
+ 'ActiveStorage::VariantRecord' => 'active_storage_variant_record',
55
+ 'ActiveSupport::TestCase' => 'active_support_test_case'
56
+ }.freeze
57
+
58
+ def on_send(node)
59
+ receiver, method, arguments = *node # rubocop:disable InternalAffairs/NodeDestructuring
60
+ return unless receiver && (hook = LOAD_HOOKS[receiver.const_name])
61
+
62
+ preferred = "ActiveSupport.on_load(:#{hook}) { #{method} #{arguments.source} }"
63
+ add_offense(node, message: format(MSG, prefer: preferred, current: node.source)) do |corrector|
64
+ corrector.replace(node, preferred)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for migrations using `add_column` that have an `index`
6
+ # Checks for migrations using `add_column` that have an `index`
7
7
  # key. `add_column` does not accept `index`, but also does not raise an
8
8
  # error for extra keys, so it is possible to mistakenly add the key without
9
9
  # realizing it will not actually add an index.
@@ -42,7 +42,7 @@ module RuboCop
42
42
  add_index_opts = ''
43
43
 
44
44
  if value.hash_type?
45
- hash = value.loc.expression.adjust(begin_pos: 1, end_pos: -1).source.strip
45
+ hash = value.source_range.adjust(begin_pos: 1, end_pos: -1).source.strip
46
46
  add_index_opts = ", #{hash}"
47
47
  end
48
48
 
@@ -53,10 +53,7 @@ module RuboCop
53
53
  private
54
54
 
55
55
  def index_range(pair_node)
56
- range_with_surrounding_comma(
57
- range_with_surrounding_space(range: pair_node.loc.expression, side: :left),
58
- :left
59
- )
56
+ range_with_surrounding_comma(range_with_surrounding_space(pair_node.source_range, side: :left), :left)
60
57
  end
61
58
  end
62
59
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop enforces that there is only one call to `after_commit`
6
+ # Enforces that there is only one call to `after_commit`
7
7
  # (and its aliases - `after_create_commit`, `after_update_commit`,
8
8
  # and `after_destroy_commit`) with the same callback name per model.
9
9
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that controllers subclass `ApplicationController`.
6
+ # Checks that controllers subclass `ApplicationController`.
7
7
  #
8
8
  # @safety
9
9
  # This cop's autocorrection is unsafe because it may let the logic from `ApplicationController`
@@ -25,7 +25,7 @@ module RuboCop
25
25
 
26
26
  MSG = 'Controllers should subclass `ApplicationController`.'
27
27
  SUPERCLASS = 'ApplicationController'
28
- BASE_PATTERN = '(const (const nil? :ActionController) :Base)'
28
+ BASE_PATTERN = '(const (const {nil? cbase} :ActionController) :Base)'
29
29
 
30
30
  # rubocop:disable Layout/ClassStructure
31
31
  include RuboCop::Cop::EnforceSuperclass
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that jobs subclass `ApplicationJob` with Rails 5.0.
6
+ # Checks that jobs subclass `ApplicationJob` with Rails 5.0.
7
7
  #
8
8
  # @safety
9
9
  # This cop's autocorrection is unsafe because it may let the logic from `ApplicationJob`
@@ -28,7 +28,7 @@ module RuboCop
28
28
 
29
29
  MSG = 'Jobs should subclass `ApplicationJob`.'
30
30
  SUPERCLASS = 'ApplicationJob'
31
- BASE_PATTERN = '(const (const nil? :ActiveJob) :Base)'
31
+ BASE_PATTERN = '(const (const {nil? cbase} :ActiveJob) :Base)'
32
32
 
33
33
  # rubocop:disable Layout/ClassStructure
34
34
  include RuboCop::Cop::EnforceSuperclass
@@ -36,7 +36,7 @@ module RuboCop
36
36
 
37
37
  def autocorrect(node)
38
38
  lambda do |corrector|
39
- corrector.replace(node.source_range, self.class::SUPERCLASS)
39
+ corrector.replace(node, self.class::SUPERCLASS)
40
40
  end
41
41
  end
42
42
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that mailers subclass `ApplicationMailer` with Rails 5.0.
6
+ # Checks that mailers subclass `ApplicationMailer` with Rails 5.0.
7
7
  #
8
8
  # @safety
9
9
  # This cop's autocorrection is unsafe because it may let the logic from `ApplicationMailer`
@@ -28,7 +28,7 @@ module RuboCop
28
28
 
29
29
  MSG = 'Mailers should subclass `ApplicationMailer`.'
30
30
  SUPERCLASS = 'ApplicationMailer'
31
- BASE_PATTERN = '(const (const nil? :ActionMailer) :Base)'
31
+ BASE_PATTERN = '(const (const {nil? cbase} :ActionMailer) :Base)'
32
32
 
33
33
  # rubocop:disable Layout/ClassStructure
34
34
  include RuboCop::Cop::EnforceSuperclass
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that models subclass `ApplicationRecord` with Rails 5.0.
6
+ # Checks that models subclass `ApplicationRecord` with Rails 5.0.
7
7
  #
8
8
  # @safety
9
9
  # This cop's autocorrection is unsafe because it may let the logic from `ApplicationRecord`
@@ -29,7 +29,7 @@ module RuboCop
29
29
 
30
30
  MSG = 'Models should subclass `ApplicationRecord`.'
31
31
  SUPERCLASS = 'ApplicationRecord'
32
- BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)'
32
+ BASE_PATTERN = '(const (const {nil? cbase} :ActiveRecord) :Base)'
33
33
 
34
34
  # rubocop:disable Layout/ClassStructure
35
35
  include RuboCop::Cop::EnforceSuperclass
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop prevents usage of `"*"` on an Arel::Table column reference.
6
+ # Prevents usage of `"*"` on an Arel::Table column reference.
7
7
  #
8
8
  # Using `arel_table["*"]` causes the outputted string to be a literal
9
9
  # quoted asterisk (e.g. <tt>`my_model`.`*`</tt>). This causes the
@@ -38,7 +38,7 @@ module RuboCop
38
38
  return unless (star = star_bracket?(node))
39
39
 
40
40
  add_offense(star) do |corrector|
41
- corrector.replace(star.loc.expression, 'Arel.star')
41
+ corrector.replace(star, 'Arel.star')
42
42
  end
43
43
  end
44
44
  end
@@ -25,7 +25,7 @@ module RuboCop
25
25
  return unless offensive?(node)
26
26
 
27
27
  add_offense(node) do |corrector|
28
- expression = node.loc.expression
28
+ expression = node.source_range
29
29
 
30
30
  corrector.replace(expression, corrected_source(expression.source))
31
31
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop looks for `attribute` class methods that specify a `:default` option
6
+ # Looks for `attribute` class methods that specify a `:default` option
7
7
  # which value is an array, string literal or method call without a block.
8
8
  # It will accept all other values, such as string, symbol, integer and float literals
9
9
  # as well as constants.
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop looks for belongs_to associations where we control whether the
6
+ # Looks for belongs_to associations where we control whether the
7
7
  # association is required via the deprecated `required` option instead.
8
8
  #
9
9
  # Since Rails 5, belongs_to associations are required by default and this
@@ -47,9 +47,6 @@ module RuboCop
47
47
  # class Post < ApplicationRecord
48
48
  # belongs_to :blog, optional: false
49
49
  # end
50
- #
51
- # @see https://guides.rubyonrails.org/5_0_release_notes.html
52
- # @see https://github.com/rails/rails/pull/18937
53
50
  class BelongsTo < Base
54
51
  extend AutoCorrector
55
52
  extend TargetRailsVersion
@@ -83,7 +80,7 @@ module RuboCop
83
80
  end
84
81
 
85
82
  add_offense(node.loc.selector, message: message) do |corrector|
86
- corrector.replace(option_node.loc.expression, replacement)
83
+ corrector.replace(option_node, replacement)
87
84
  end
88
85
  end
89
86
  end
@@ -3,17 +3,17 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for code that can be written with simpler conditionals
6
+ # Checks for code that can be written with simpler conditionals
7
7
  # using `Object#blank?` defined by Active Support.
8
8
  #
9
9
  # Interaction with `Style/UnlessElse`:
10
10
  # The configuration of `NotPresent` will not produce an offense in the
11
- # context of `unless else` if `Style/UnlessElse` is inabled. This is
12
- # to prevent interference between the auto-correction of the two cops.
11
+ # context of `unless else` if `Style/UnlessElse` is enabled. This is
12
+ # to prevent interference between the autocorrection of the two cops.
13
13
  #
14
14
  # @safety
15
- # This cop is unsafe auto-correction, because `' '.empty?` returns false,
16
- # but `' '.blank?` returns true. Therefore, auto-correction is not compatible
15
+ # This cop is unsafe autocorrection, because `' '.empty?` returns false,
16
+ # but `' '.blank?` returns true. Therefore, autocorrection is not compatible
17
17
  # if the receiver is a non-empty blank string, tab, or newline meta characters.
18
18
  #
19
19
  # @example NilOrEmpty: true (default)
@@ -63,8 +63,7 @@ module RuboCop
63
63
 
64
64
  MSG_NIL_OR_EMPTY = 'Use `%<prefer>s` instead of `%<current>s`.'
65
65
  MSG_NOT_PRESENT = 'Use `%<prefer>s` instead of `%<current>s`.'
66
- MSG_UNLESS_PRESENT = 'Use `if %<prefer>s` instead of ' \
67
- '`%<current>s`.'
66
+ MSG_UNLESS_PRESENT = 'Use `if %<prefer>s` instead of `%<current>s`.'
68
67
  RESTRICT_ON_SEND = %i[!].freeze
69
68
 
70
69
  # `(send nil $_)` is not actually a valid match for an offense. Nodes
@@ -143,10 +142,10 @@ module RuboCop
143
142
 
144
143
  if method_call
145
144
  corrector.replace(node.loc.keyword, 'if')
146
- range = method_call.loc.expression
145
+ range = method_call.source_range
147
146
  else
148
147
  variable1, _variable2 = nil_or_empty?(node) || not_present?(node)
149
- range = node.loc.expression
148
+ range = node.source_range
150
149
  end
151
150
 
152
151
  corrector.replace(range, replacement(variable1))
@@ -154,9 +153,9 @@ module RuboCop
154
153
 
155
154
  def unless_condition(node, method_call)
156
155
  if node.modifier_form?
157
- node.loc.keyword.join(node.loc.expression.end)
156
+ node.loc.keyword.join(node.source_range.end)
158
157
  else
159
- node.loc.expression.begin.join(method_call.loc.expression)
158
+ node.source_range.begin.join(method_call.source_range)
160
159
  end
161
160
  end
162
161