rubocop-rails 2.15.2 → 2.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +120 -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 +99 -0
  8. data/lib/rubocop/cop/rails/action_controller_test_case.rb +1 -1
  9. data/lib/rubocop/cop/rails/action_filter.rb +1 -1
  10. data/lib/rubocop/cop/rails/action_order.rb +81 -0
  11. data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
  12. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  13. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  14. data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
  15. data/lib/rubocop/cop/rails/blank.rb +1 -2
  16. data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
  17. data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
  18. data/lib/rubocop/cop/rails/content_tag.rb +3 -4
  19. data/lib/rubocop/cop/rails/date.rb +4 -9
  20. data/lib/rubocop/cop/rails/delegate.rb +2 -5
  21. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
  22. data/lib/rubocop/cop/rails/dot_separated_keys.rb +1 -1
  23. data/lib/rubocop/cop/rails/dynamic_find_by.rb +8 -6
  24. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +4 -0
  25. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
  26. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
  27. data/lib/rubocop/cop/rails/file_path.rb +2 -4
  28. data/lib/rubocop/cop/rails/find_each.rb +8 -2
  29. data/lib/rubocop/cop/rails/freeze_time.rb +74 -0
  30. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -3
  31. data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
  32. data/lib/rubocop/cop/rails/http_status.rb +11 -11
  33. data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
  34. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
  35. data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
  36. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
  37. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
  38. data/lib/rubocop/cop/rails/output.rb +2 -5
  39. data/lib/rubocop/cop/rails/pluck.rb +8 -7
  40. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
  41. data/lib/rubocop/cop/rails/presence.rb +21 -12
  42. data/lib/rubocop/cop/rails/present.rb +3 -6
  43. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  44. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
  45. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  46. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
  47. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +30 -26
  48. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
  49. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  50. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
  51. data/lib/rubocop/cop/rails/request_referer.rb +1 -2
  52. data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
  53. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
  54. data/lib/rubocop/cop/rails/root_pathname_methods.rb +214 -0
  55. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
  56. data/lib/rubocop/cop/rails/save_bang.rb +10 -22
  57. data/lib/rubocop/cop/rails/short_i18n.rb +1 -4
  58. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -2
  59. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
  60. data/lib/rubocop/cop/rails/time_zone.rb +10 -21
  61. data/lib/rubocop/cop/rails/to_s_with_argument.rb +41 -0
  62. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  63. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  64. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
  65. data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
  66. data/lib/rubocop/cop/rails/validation.rb +4 -12
  67. data/lib/rubocop/cop/rails/where_missing.rb +111 -0
  68. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
  69. data/lib/rubocop/cop/rails_cops.rb +10 -0
  70. data/lib/rubocop/rails/version.rb +1 -1
  71. data/lib/rubocop-rails.rb +10 -0
  72. metadata +16 -8
  73. data/bin/console +0 -11
  74. 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: 2a7a516c82d0953f3f1995b190ddc427aa251583287a9232229e82a218c93ba6
4
+ data.tar.gz: f224a35df6de69c04c7c6f6314f9cfa713cc5accfba1bbce9d5554c7fd50a121
5
5
  SHA512:
6
- metadata.gz: 51d495edd3e825db49ece8f51bfc118c73887681f414b86d31cd47d85dc5a1a22a385a2a17ed4ebf7d1c6332989795e2cde999a364d911c60f452993dc926c4b
7
- data.tar.gz: 4546785b39af93e6c7fe5a6a3b637fa5c21d4b358c38ea8ad3ebd5c272d1d0a504e8206e8201cfe3771af9199c336649d033e32b324f16b06fc7d150054dc488
6
+ metadata.gz: 5b3277765f3819855d3e29d3226c81ebc6231b1b1aaf583e1ae86db9e18b7b450bbc2b3f9bccaaa85623ca57e0ac139abde604c35bccc81c3081a80c4392f35d
7
+ data.tar.gz: a3d7b79f10c2090b04a05d1b30cc3c639645aa6b3c2ad33247fecfa7597907238d8f6e727a8e0dd088b92d69842c488489e9883f9acfd4551e08a9b8f3dd1f8c
data/config/default.yml CHANGED
@@ -10,6 +10,12 @@ 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
+ - log/**/*
14
+ - public/**/*
15
+ - storage/**/*
16
+ # Enable checking Active Support extensions.
17
+ # See: https://docs.rubocop.org/rubocop/configuration.html#enable-checking-active-support-extensions
18
+ ActiveSupportExtensionsEnabled: true
13
19
  # What version of Rails is the inspected code using? If a value is specified
14
20
  # for TargetRailsVersion then it is used. Acceptable values are specified
15
21
  # as a float (i.e. 5.1); the patch version of Rails should not be included.
@@ -23,6 +29,24 @@ Lint/NumberConversion:
23
29
  # Add Rails' duration methods to the ignore list for `Lint/NumberConversion`
24
30
  # so that calling `to_i` on one of these does not register an offense.
25
31
  # See: https://github.com/rubocop/rubocop/issues/8950
32
+ AllowedMethods:
33
+ - ago
34
+ - from_now
35
+ - second
36
+ - seconds
37
+ - minute
38
+ - minutes
39
+ - hour
40
+ - hours
41
+ - day
42
+ - days
43
+ - week
44
+ - weeks
45
+ - fortnight
46
+ - fortnights
47
+ - in_milliseconds
48
+ AllowedPatterns: []
49
+ # Deprecated.
26
50
  IgnoredMethods:
27
51
  - ago
28
52
  - from_now
@@ -40,6 +64,18 @@ Lint/NumberConversion:
40
64
  - fortnights
41
65
  - in_milliseconds
42
66
 
67
+ Rails:
68
+ Enabled: true
69
+ DocumentationBaseURL: https://docs.rubocop.org/rubocop-rails
70
+
71
+ Rails/ActionControllerFlashBeforeRender:
72
+ Description: 'Use `flash.now` instead of `flash` before `render`.'
73
+ StyleGuide: 'https://rails.rubystyle.guide/#flash-before-render'
74
+ Reference: 'https://api.rubyonrails.org/classes/ActionController/FlashBeforeRender.html'
75
+ Enabled: 'pending'
76
+ SafeAutocorrect: false
77
+ VersionAdded: '2.16'
78
+
43
79
  Rails/ActionControllerTestCase:
44
80
  Description: 'Use `ActionDispatch::IntegrationTest` instead of `ActionController::TestCase`.'
45
81
  StyleGuide: 'https://rails.rubystyle.guide/#integration-testing'
@@ -62,6 +98,21 @@ Rails/ActionFilter:
62
98
  - app/controllers/**/*.rb
63
99
  - app/mailers/**/*.rb
64
100
 
101
+ Rails/ActionOrder:
102
+ Description: 'Enforce consistent ordering of controller actions.'
103
+ Enabled: pending
104
+ VersionAdded: '2.17'
105
+ ExpectedOrder:
106
+ - index
107
+ - show
108
+ - new
109
+ - edit
110
+ - create
111
+ - update
112
+ - destroy
113
+ Include:
114
+ - app/controllers/**/*.rb
115
+
65
116
  Rails/ActiveRecordAliases:
66
117
  Description: >-
67
118
  Avoid Active Record aliases:
@@ -96,6 +147,15 @@ Rails/ActiveSupportAliases:
96
147
  Enabled: true
97
148
  VersionAdded: '0.48'
98
149
 
150
+ Rails/ActiveSupportOnLoad:
151
+ Description: 'Use `ActiveSupport.on_load(...)` to patch Rails framework classes.'
152
+ Enabled: 'pending'
153
+ Reference:
154
+ - 'https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html'
155
+ - 'https://guides.rubyonrails.org/engines.html#available-load-hooks'
156
+ SafeAutoCorrect: false
157
+ VersionAdded: '2.16'
158
+
99
159
  Rails/AddColumnIndex:
100
160
  Description: >-
101
161
  Rails migrations don't make use of a given `index` key, but also
@@ -306,10 +366,13 @@ Rails/DynamicFindBy:
306
366
  # The `Whitelist` has been deprecated, Please use `AllowedMethods` instead.
307
367
  Whitelist:
308
368
  - find_by_sql
369
+ - find_by_token_for
309
370
  AllowedMethods:
310
371
  - find_by_sql
372
+ - find_by_token_for
311
373
  AllowedReceivers:
312
374
  - Gem::Specification
375
+ - page # Prevents a warning for `page.find_by_id`. See: https://github.com/rubocop/rubocop-rails/issues/778
313
376
 
314
377
  Rails/EagerEvaluationLogMessage:
315
378
  Description: 'Checks that blocks are used for interpolated strings passed to `Rails.logger.debug`.'
@@ -407,6 +470,14 @@ Rails/FindEach:
407
470
  VersionChanged: '2.9'
408
471
  Include:
409
472
  - app/models/**/*.rb
473
+ AllowedMethods:
474
+ # Methods that don't work well with `find_each`.
475
+ - order
476
+ - limit
477
+ - select
478
+ - lock
479
+ AllowedPatterns: []
480
+ # Deprecated.
410
481
  IgnoredMethods:
411
482
  # Methods that don't work well with `find_each`.
412
483
  - order
@@ -414,6 +485,13 @@ Rails/FindEach:
414
485
  - select
415
486
  - lock
416
487
 
488
+ Rails/FreezeTime:
489
+ Description: 'Prefer `freeze_time` over `travel_to` with an argument of the current time.'
490
+ StyleGuide: 'https://rails.rubystyle.guide/#freeze-time'
491
+ Enabled: pending
492
+ VersionAdded: '2.16'
493
+ SafeAutoCorrect: false
494
+
417
495
  Rails/HasAndBelongsToMany:
418
496
  Description: 'Prefer has_many :through to has_and_belongs_to_many.'
419
497
  StyleGuide: 'https://rails.rubystyle.guide#has-many-through'
@@ -478,6 +556,13 @@ Rails/I18nLocaleTexts:
478
556
  Enabled: pending
479
557
  VersionAdded: '2.14'
480
558
 
559
+ Rails/IgnoredColumnsAssignment:
560
+ Description: 'Looks for assignments of `ignored_columns` that override previous assignments.'
561
+ StyleGuide: 'https://rails.rubystyle.guide/#append-ignored-columns'
562
+ Enabled: pending
563
+ SafeAutoCorrect: false
564
+ VersionAdded: '2.17'
565
+
481
566
  Rails/IgnoredSkipActionFilterOption:
482
567
  Description: 'Checks that `if` and `only` (or `except`) are not used together as options of `skip_*` action filter.'
483
568
  Reference: 'https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options'
@@ -785,6 +870,12 @@ Rails/RootJoinChain:
785
870
  Enabled: pending
786
871
  VersionAdded: '2.13'
787
872
 
873
+ Rails/RootPathnameMethods:
874
+ Description: 'Use `Rails.root` IO methods instead of passing it to `File`.'
875
+ Enabled: pending
876
+ SafeAutocorrect: false
877
+ VersionAdded: '2.16'
878
+
788
879
  Rails/RootPublicPath:
789
880
  Description: "Favor `Rails.public_path` over `Rails.root` with `'public'`."
790
881
  Enabled: pending
@@ -937,6 +1028,18 @@ Rails/ToFormattedS:
937
1028
  - to_formatted_s
938
1029
  VersionAdded: '2.15'
939
1030
 
1031
+ Rails/ToSWithArgument:
1032
+ Description: 'Identifies passing any argument to `#to_s`.'
1033
+ Enabled: pending
1034
+ Safe: false
1035
+ VersionAdded: '2.16'
1036
+
1037
+ Rails/TopLevelHashWithIndifferentAccess:
1038
+ Description: 'Identifies top-level `HashWithIndifferentAccess`.'
1039
+ Reference: 'https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#top-level-hashwithindifferentaccess-is-soft-deprecated'
1040
+ Enabled: pending
1041
+ VersionAdded: '2.16'
1042
+
940
1043
  Rails/TransactionExitStatement:
941
1044
  Description: 'Avoid the usage of `return`, `break` and `throw` in transaction blocks.'
942
1045
  Enabled: pending
@@ -1003,12 +1106,29 @@ Rails/WhereExists:
1003
1106
  VersionAdded: '2.7'
1004
1107
  VersionChanged: '2.10'
1005
1108
 
1109
+ Rails/WhereMissing:
1110
+ Description: 'Use `where.missing(...)` to find missing relationship records.'
1111
+ StyleGuide: 'https://rails.rubystyle.guide/#finding-missing-relationship-records'
1112
+ Enabled: pending
1113
+ VersionAdded: '2.16'
1114
+
1006
1115
  Rails/WhereNot:
1007
1116
  Description: 'Use `where.not(...)` instead of manually constructing negated SQL in `where`.'
1008
1117
  StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions'
1009
1118
  Enabled: 'pending'
1010
1119
  VersionAdded: '2.8'
1011
1120
 
1121
+ Rails/WhereNotWithMultipleConditions:
1122
+ Description: 'Do not use `where.not(...)` with multiple conditions.'
1123
+ Enabled: 'pending'
1124
+ VersionAdded: '2.17'
1125
+
1012
1126
  # Accept `redirect_to(...) and return` and similar cases.
1013
1127
  Style/AndOr:
1014
1128
  EnforcedStyle: conditionals
1129
+
1130
+ Style/SymbolProc:
1131
+ AllowedMethods:
1132
+ - define_method
1133
+ - mail
1134
+ - respond_to
@@ -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,99 @@
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 :redirect_to?, <<~PATTERN
41
+ (send nil? :redirect_to ...)
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 if followed_by_redirect_to?(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_redirect_to?(flash_node)
70
+ flash_assigment_node = find_ancestor(flash_node, type: :send)
71
+ context = flash_assigment_node.parent
72
+
73
+ flash_index = context.children.index(flash_assigment_node)
74
+ context.each_child_node.with_index.any? do |node, index|
75
+ index > flash_index && redirect_to?(node)
76
+ end
77
+ end
78
+
79
+ def inherit_action_controller_base?(node)
80
+ class_node = find_ancestor(node, type: :class)
81
+ return unless class_node
82
+
83
+ action_controller?(class_node)
84
+ end
85
+
86
+ def instance_method_or_block?(node)
87
+ def_node = find_ancestor(node, type: :def)
88
+ block_node = find_ancestor(node, type: :block)
89
+
90
+ def_node || block_node
91
+ end
92
+
93
+ def find_ancestor(node, type:)
94
+ node.each_ancestor(type).first
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -31,7 +31,7 @@ module RuboCop
31
31
  def_node_matcher :action_controller_test_case?, <<~PATTERN
32
32
  (class
33
33
  (const nil? _)
34
- (const (const {nil? cbase} :ActionController) :TestCase) nil?)
34
+ (const (const {nil? cbase} :ActionController) :TestCase) _)
35
35
  PATTERN
36
36
 
37
37
  def on_class(node)
@@ -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,81 @@
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.
10
+ #
11
+ # [source,yaml]
12
+ # ----
13
+ # Rails/ActionOrder:
14
+ # ExpectedOrder:
15
+ # - index
16
+ # - show
17
+ # - new
18
+ # - edit
19
+ # - create
20
+ # - update
21
+ # - destroy
22
+ # ----
23
+ #
24
+ # @example
25
+ # # bad
26
+ # def index; end
27
+ # def destroy; end
28
+ # def show; end
29
+ #
30
+ # # good
31
+ # def index; end
32
+ # def show; end
33
+ # def destroy; end
34
+ class ActionOrder < Base
35
+ extend AutoCorrector
36
+ include VisibilityHelp
37
+ include DefNode
38
+
39
+ MSG = 'Action `%<current>s` should appear before `%<previous>s`.'
40
+
41
+ def_node_search :action_declarations, '(def {%1} ...)'
42
+
43
+ def on_class(node)
44
+ action_declarations(node, actions).each_cons(2) do |previous, current|
45
+ next if node_visibility(current) != :public || non_public?(current)
46
+ next if find_index(current) >= find_index(previous)
47
+
48
+ register_offense(previous, current)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def expected_order
55
+ cop_config['ExpectedOrder'].map(&:to_sym)
56
+ end
57
+
58
+ def actions
59
+ @actions ||= Set.new(expected_order)
60
+ end
61
+
62
+ def find_index(node)
63
+ expected_order.find_index(node.method_name)
64
+ end
65
+
66
+ def register_offense(previous, current)
67
+ message = format(
68
+ MSG,
69
+ expected_order: expected_order.join(', '),
70
+ previous: previous.method_name,
71
+ current: current.method_name
72
+ )
73
+ add_offense(current, message: message) do |corrector|
74
+ corrector.replace(current, previous.source)
75
+ corrector.replace(previous, current.source)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -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