rubocop-rails 2.15.2 → 2.16.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 169ed04b1f5378e9e08fbffdca151afaf4b84fd54b1867a173740aadaede60b3
4
- data.tar.gz: 1a2ac75c313cfcdeec1814d7e3aff4777c5013527d2cf4a2aa4f95aeb45446bf
3
+ metadata.gz: a928896af6bef8228bfc2530b829a683154c23b22ea547557d40ea1e4d08ae7f
4
+ data.tar.gz: 40303c4d80e1e6eaef12ceb0170b64b65b151fc2056957d6c6b6bac1d645d445
5
5
  SHA512:
6
- metadata.gz: 51d495edd3e825db49ece8f51bfc118c73887681f414b86d31cd47d85dc5a1a22a385a2a17ed4ebf7d1c6332989795e2cde999a364d911c60f452993dc926c4b
7
- data.tar.gz: 4546785b39af93e6c7fe5a6a3b637fa5c21d4b358c38ea8ad3ebd5c272d1d0a504e8206e8201cfe3771af9199c336649d033e32b324f16b06fc7d150054dc488
6
+ metadata.gz: a87b9c167cf43287207bae3ec38e385cb6213c26ff0f7e10aa3bf392ab28b724794820a459dc6af6d464e48ea70629c443e74acc4539dca6f0c0a57fee65d87c
7
+ data.tar.gz: fbb0b7333c6d485e50facadd7170bb2d59e425119134d01f42ac3d24eecc01ad52d588f55de184c9373061ba207cf6845d3e8201fe43ce48e3a8d3b22e992dff
data/config/default.yml CHANGED
@@ -10,6 +10,9 @@ AllCops:
10
10
  # Exclude db/schema.rb and db/[CONFIGURATION_NAMESPACE]_schema.rb by default.
11
11
  # See: https://guides.rubyonrails.org/active_record_multiple_databases.html#setting-up-your-application
12
12
  - db/*schema.rb
13
+ # Enable checking Active Support extensions.
14
+ # See: https://docs.rubocop.org/rubocop/configuration.html#enable-checking-active-support-extensions
15
+ ActiveSupportExtensionsEnabled: true
13
16
  # What version of Rails is the inspected code using? If a value is specified
14
17
  # for TargetRailsVersion then it is used. Acceptable values are specified
15
18
  # as a float (i.e. 5.1); the patch version of Rails should not be included.
@@ -23,6 +26,24 @@ Lint/NumberConversion:
23
26
  # Add Rails' duration methods to the ignore list for `Lint/NumberConversion`
24
27
  # so that calling `to_i` on one of these does not register an offense.
25
28
  # See: https://github.com/rubocop/rubocop/issues/8950
29
+ AllowedMethods:
30
+ - ago
31
+ - from_now
32
+ - second
33
+ - seconds
34
+ - minute
35
+ - minutes
36
+ - hour
37
+ - hours
38
+ - day
39
+ - days
40
+ - week
41
+ - weeks
42
+ - fortnight
43
+ - fortnights
44
+ - in_milliseconds
45
+ AllowedPatterns: []
46
+ # Deprecated.
26
47
  IgnoredMethods:
27
48
  - ago
28
49
  - from_now
@@ -40,6 +61,18 @@ Lint/NumberConversion:
40
61
  - fortnights
41
62
  - in_milliseconds
42
63
 
64
+ Rails:
65
+ Enabled: true
66
+ DocumentationBaseURL: https://docs.rubocop.org/rubocop-rails
67
+
68
+ Rails/ActionControllerFlashBeforeRender:
69
+ Description: 'Use `flash.now` instead of `flash` before `render`.'
70
+ StyleGuide: 'https://rails.rubystyle.guide/#flash-before-render'
71
+ Reference: 'https://api.rubyonrails.org/classes/ActionController/FlashBeforeRender.html'
72
+ Enabled: 'pending'
73
+ SafeAutocorrect: false
74
+ VersionAdded: '2.16'
75
+
43
76
  Rails/ActionControllerTestCase:
44
77
  Description: 'Use `ActionDispatch::IntegrationTest` instead of `ActionController::TestCase`.'
45
78
  StyleGuide: 'https://rails.rubystyle.guide/#integration-testing'
@@ -96,6 +129,15 @@ Rails/ActiveSupportAliases:
96
129
  Enabled: true
97
130
  VersionAdded: '0.48'
98
131
 
132
+ Rails/ActiveSupportOnLoad:
133
+ Description: 'Use `ActiveSupport.on_load(...)` to patch Rails framework classes.'
134
+ Enabled: 'pending'
135
+ Reference:
136
+ - 'https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html'
137
+ - 'https://guides.rubyonrails.org/engines.html#available-load-hooks'
138
+ SafeAutoCorrect: false
139
+ VersionAdded: '2.16'
140
+
99
141
  Rails/AddColumnIndex:
100
142
  Description: >-
101
143
  Rails migrations don't make use of a given `index` key, but also
@@ -407,6 +449,14 @@ Rails/FindEach:
407
449
  VersionChanged: '2.9'
408
450
  Include:
409
451
  - app/models/**/*.rb
452
+ AllowedMethods:
453
+ # Methods that don't work well with `find_each`.
454
+ - order
455
+ - limit
456
+ - select
457
+ - lock
458
+ AllowedPatterns: []
459
+ # Deprecated.
410
460
  IgnoredMethods:
411
461
  # Methods that don't work well with `find_each`.
412
462
  - order
@@ -414,6 +464,13 @@ Rails/FindEach:
414
464
  - select
415
465
  - lock
416
466
 
467
+ Rails/FreezeTime:
468
+ Description: 'Prefer `freeze_time` over `travel_to` with an argument of the current time.'
469
+ StyleGuide: 'https://rails.rubystyle.guide/#freeze-time'
470
+ Enabled: pending
471
+ VersionAdded: '2.16'
472
+ SafeAutoCorrect: false
473
+
417
474
  Rails/HasAndBelongsToMany:
418
475
  Description: 'Prefer has_many :through to has_and_belongs_to_many.'
419
476
  StyleGuide: 'https://rails.rubystyle.guide#has-many-through'
@@ -785,6 +842,11 @@ Rails/RootJoinChain:
785
842
  Enabled: pending
786
843
  VersionAdded: '2.13'
787
844
 
845
+ Rails/RootPathnameMethods:
846
+ Description: 'Use `Rails.root` IO methods instead of passing it to `File`.'
847
+ Enabled: pending
848
+ VersionAdded: '2.16'
849
+
788
850
  Rails/RootPublicPath:
789
851
  Description: "Favor `Rails.public_path` over `Rails.root` with `'public'`."
790
852
  Enabled: pending
@@ -937,6 +999,18 @@ Rails/ToFormattedS:
937
999
  - to_formatted_s
938
1000
  VersionAdded: '2.15'
939
1001
 
1002
+ Rails/ToSWithArgument:
1003
+ Description: 'Identifies passing any argument to `#to_s`.'
1004
+ Enabled: pending
1005
+ Safe: false
1006
+ VersionAdded: '2.16'
1007
+
1008
+ Rails/TopLevelHashWithIndifferentAccess:
1009
+ Description: 'Identifies top-level `HashWithIndifferentAccess`.'
1010
+ Reference: 'https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#top-level-hashwithindifferentaccess-is-soft-deprecated'
1011
+ Enabled: pending
1012
+ VersionAdded: '2.16'
1013
+
940
1014
  Rails/TransactionExitStatement:
941
1015
  Description: 'Avoid the usage of `return`, `break` and `throw` in transaction blocks.'
942
1016
  Enabled: pending
@@ -1003,6 +1077,12 @@ Rails/WhereExists:
1003
1077
  VersionAdded: '2.7'
1004
1078
  VersionChanged: '2.10'
1005
1079
 
1080
+ Rails/WhereMissing:
1081
+ Description: 'Use `where.missing(...)` to find missing relationship records.'
1082
+ StyleGuide: 'https://rails.rubystyle.guide/#finding-missing-relationship-records'
1083
+ Enabled: pending
1084
+ VersionAdded: '2.16'
1085
+
1006
1086
  Rails/WhereNot:
1007
1087
  Description: 'Use `where.not(...)` instead of manually constructing negated SQL in `where`.'
1008
1088
  StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions'
@@ -5,3 +5,13 @@
5
5
  #
6
6
  extracted:
7
7
  Rails/*: ~
8
+
9
+ # Cop parameters that have been changed
10
+ # Can be treated as a warning instead of a failure with `severity: warning`
11
+ changed_parameters:
12
+ - cops: Rails/FindEach
13
+ parameters: IgnoredMethods
14
+ alternatives:
15
+ - AllowedMethods
16
+ - AllowedPatterns
17
+ severity: warning
@@ -48,10 +48,7 @@ module RuboCop
48
48
 
49
49
  class_nodes = class_node.defined_module.each_node
50
50
  namespaces = class_node.each_ancestor(:class, :module).map(&:identifier)
51
- [*class_nodes, *namespaces]
52
- .reverse
53
- .map { |node| node.children[1] }.join('_')
54
- .tableize
51
+ [*class_nodes, *namespaces].reverse.map { |node| node.children[1] }.join('_').tableize
55
52
  end
56
53
 
57
54
  # Resolve relation into column name.
@@ -10,9 +10,7 @@ module RuboCop
10
10
  bigint binary boolean date datetime decimal float integer json string
11
11
  text time timestamp virtual
12
12
  ].freeze
13
- RAILS_ABSTRACT_SCHEMA_DEFINITIONS_HELPERS = %i[
14
- column references belongs_to primary_key numeric
15
- ].freeze
13
+ RAILS_ABSTRACT_SCHEMA_DEFINITIONS_HELPERS = %i[column references belongs_to primary_key numeric].freeze
16
14
  POSTGRES_SCHEMA_DEFINITIONS = %i[
17
15
  bigserial bit bit_varying cidr citext daterange hstore inet interval
18
16
  int4range int8range jsonb ltree macaddr money numrange oid point line
@@ -6,7 +6,7 @@ module RuboCop
6
6
  module IndexMethod # rubocop:disable Metrics/ModuleLength
7
7
  RESTRICT_ON_SEND = %i[each_with_object to_h map collect []].freeze
8
8
 
9
- def on_block(node)
9
+ def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler
10
10
  on_bad_each_with_object(node) do |*match|
11
11
  handle_possible_offense(node, match, 'each_with_object')
12
12
  end
@@ -98,10 +98,7 @@ module RuboCop
98
98
 
99
99
  captures = extract_captures(correction.match)
100
100
  correction.set_new_arg_name(captures.transformed_argname, corrector)
101
- correction.set_new_body_expression(
102
- captures.transforming_body_expr,
103
- corrector
104
- )
101
+ correction.set_new_body_expression(captures.transforming_body_expr, corrector)
105
102
  end
106
103
 
107
104
  # Internal helper class to hold match data
@@ -110,8 +107,7 @@ module RuboCop
110
107
  :transforming_body_expr
111
108
  ) do
112
109
  def noop_transformation?
113
- transforming_body_expr.lvar_type? &&
114
- transforming_body_expr.children == [transformed_argname]
110
+ transforming_body_expr.lvar_type? && transforming_body_expr.children == [transformed_argname]
115
111
  end
116
112
  end
117
113
 
@@ -157,17 +153,11 @@ module RuboCop
157
153
  end
158
154
 
159
155
  def set_new_arg_name(transformed_argname, corrector)
160
- corrector.replace(
161
- block_node.arguments.loc.expression,
162
- "|#{transformed_argname}|"
163
- )
156
+ corrector.replace(block_node.arguments.loc.expression, "|#{transformed_argname}|")
164
157
  end
165
158
 
166
159
  def set_new_body_expression(transforming_body_expr, corrector)
167
- corrector.replace(
168
- block_node.body.loc.expression,
169
- transforming_body_expr.loc.expression.source
170
- )
160
+ corrector.replace(block_node.body.loc.expression, transforming_body_expr.loc.expression.source)
171
161
  end
172
162
  end
173
163
  end
@@ -0,0 +1,98 @@
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? :ApplicationController)
47
+ (const (const nil? :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_assigment_node = find_ancestor(flash_node, type: :send)
71
+ context = flash_assigment_node.parent
72
+
73
+ context.each_child_node.any? do |node|
74
+ render?(node)
75
+ end
76
+ end
77
+
78
+ def inherit_action_controller_base?(node)
79
+ class_node = find_ancestor(node, type: :class)
80
+ return unless class_node
81
+
82
+ action_controller?(class_node)
83
+ end
84
+
85
+ def instance_method_or_block?(node)
86
+ def_node = find_ancestor(node, type: :def)
87
+ block_node = find_ancestor(node, type: :block)
88
+
89
+ def_node || block_node
90
+ end
91
+
92
+ def find_ancestor(node, type:)
93
+ node.each_ancestor(type).first
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -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
 
@@ -21,10 +21,7 @@ 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
 
@@ -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)
@@ -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
@@ -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.loc.expression, side: :left), :left)
60
57
  end
61
58
  end
62
59
  end
@@ -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
@@ -111,25 +111,13 @@ module RuboCop
111
111
  remove_timestamps
112
112
  ].freeze
113
113
 
114
- MYSQL_COMBINABLE_TRANSFORMATIONS = %i[
115
- rename
116
- index
117
- remove_index
118
- ].freeze
114
+ MYSQL_COMBINABLE_TRANSFORMATIONS = %i[rename index remove_index].freeze
119
115
 
120
- MYSQL_COMBINABLE_ALTER_METHODS = %i[
121
- rename_column
122
- add_index
123
- remove_index
124
- ].freeze
116
+ MYSQL_COMBINABLE_ALTER_METHODS = %i[rename_column add_index remove_index].freeze
125
117
 
126
- POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[
127
- change_default
128
- ].freeze
118
+ POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[change_default].freeze
129
119
 
130
- POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[
131
- change_column_default
132
- ].freeze
120
+ POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[change_column_default].freeze
133
121
 
134
122
  def on_def(node)
135
123
  return unless support_bulk_alter?
@@ -186,8 +174,7 @@ module RuboCop
186
174
  options = node.arguments[1]
187
175
  return false unless options
188
176
 
189
- options.hash_type? &&
190
- options.keys.any? { |key| key.sym_type? && key.value == :bulk }
177
+ options.hash_type? && options.keys.any? { |key| key.sym_type? && key.value == :bulk }
191
178
  end
192
179
 
193
180
  def database
@@ -237,8 +224,7 @@ module RuboCop
237
224
  end
238
225
 
239
226
  def call_to_combinable_alter_method?(child_node)
240
- child_node.send_type? &&
241
- combinable_alter_methods.include?(child_node.method_name)
227
+ child_node.send_type? && combinable_alter_methods.include?(child_node.method_name)
242
228
  end
243
229
 
244
230
  def combinable_alter_methods
@@ -93,7 +93,11 @@ module RuboCop
93
93
  end
94
94
 
95
95
  def offense_range(node)
96
- end_pos = node.parent&.block_type? ? node.parent.loc.expression.end_pos : node.loc.expression.end_pos
96
+ end_pos = if node.parent&.block_type? && node.parent&.send_node == node
97
+ node.parent.loc.expression.end_pos
98
+ else
99
+ node.loc.expression.end_pos
100
+ end
97
101
 
98
102
  range_between(node.loc.selector.begin_pos, end_pos)
99
103
  end
@@ -37,9 +37,7 @@ module RuboCop
37
37
  return if node.arguments.count >= 3
38
38
 
39
39
  first_argument = node.first_argument
40
- return if !first_argument ||
41
- allowed_argument?(first_argument) ||
42
- corrected_ancestor?(node)
40
+ return if !first_argument || allowed_argument?(first_argument) || corrected_ancestor?(node)
43
41
 
44
42
  preferred_method = node.first_argument.value.to_s.underscore
45
43
  message = format(MSG, preferred_method: preferred_method, current_argument: first_argument.source)
@@ -53,22 +53,17 @@ module RuboCop
53
53
  class Date < Base
54
54
  include ConfigurableEnforcedStyle
55
55
 
56
- MSG = 'Do not use `Date.%<method_called>s` without zone. Use ' \
57
- '`Time.zone.%<day>s` instead.'
56
+ MSG = 'Do not use `Date.%<method_called>s` without zone. Use `Time.zone.%<day>s` instead.'
58
57
 
59
- MSG_SEND = 'Do not use `%<method>s` on Date objects, because they ' \
60
- 'know nothing about the time zone in use.'
58
+ MSG_SEND = 'Do not use `%<method>s` on Date objects, because they know nothing about the time zone in use.'
61
59
 
62
60
  RESTRICT_ON_SEND = %i[to_time to_time_in_current_zone].freeze
63
61
 
64
62
  BAD_DAYS = %i[today current yesterday tomorrow].freeze
65
63
 
66
- DEPRECATED_METHODS = [
67
- { deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }
68
- ].freeze
64
+ DEPRECATED_METHODS = [{ deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }].freeze
69
65
 
70
- DEPRECATED_MSG = '`%<deprecated>s` is deprecated. ' \
71
- 'Use `%<relevant>s` instead.'
66
+ DEPRECATED_MSG = '`%<deprecated>s` is deprecated. Use `%<relevant>s` instead.'
72
67
 
73
68
  def on_const(node)
74
69
  mod, klass = *node.children
@@ -93,15 +93,12 @@ module RuboCop
93
93
  return false if arg_array.size != argument_array.size
94
94
 
95
95
  arg_array.zip(argument_array).all? do |arg, argument|
96
- arg.arg_type? &&
97
- argument.lvar_type? &&
98
- arg.children == argument.children
96
+ arg.arg_type? && argument.lvar_type? && arg.children == argument.children
99
97
  end
100
98
  end
101
99
 
102
100
  def method_name_matches?(method_name, body)
103
- method_name == body.method_name ||
104
- (include_prefix_case? && method_name == prefixed_method_name(body))
101
+ method_name == body.method_name || (include_prefix_case? && method_name == prefixed_method_name(body))
105
102
  end
106
103
 
107
104
  def include_prefix_case?