rubocop-rails 2.23.1 → 2.26.2

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -2
  3. data/config/default.yml +32 -7
  4. data/lib/rubocop/cop/mixin/active_record_helper.rb +6 -1
  5. data/lib/rubocop/cop/mixin/target_rails_version.rb +29 -2
  6. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +2 -0
  7. data/lib/rubocop/cop/rails/action_order.rb +1 -5
  8. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +1 -5
  9. data/lib/rubocop/cop/rails/active_support_on_load.rb +21 -1
  10. data/lib/rubocop/cop/rails/application_record.rb +4 -0
  11. data/lib/rubocop/cop/rails/bulk_change_table.rb +10 -4
  12. data/lib/rubocop/cop/rails/compact_blank.rb +29 -8
  13. data/lib/rubocop/cop/rails/dangerous_column_names.rb +1 -2
  14. data/lib/rubocop/cop/rails/date.rb +2 -2
  15. data/lib/rubocop/cop/rails/enum_hash.rb +31 -8
  16. data/lib/rubocop/cop/rails/enum_syntax.rb +128 -0
  17. data/lib/rubocop/cop/rails/enum_uniqueness.rb +29 -7
  18. data/lib/rubocop/cop/rails/expanded_date_range.rb +1 -1
  19. data/lib/rubocop/cop/rails/file_path.rb +1 -1
  20. data/lib/rubocop/cop/rails/find_by.rb +1 -1
  21. data/lib/rubocop/cop/rails/http_status.rb +12 -2
  22. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +1 -1
  23. data/lib/rubocop/cop/rails/link_to_blank.rb +2 -2
  24. data/lib/rubocop/cop/rails/not_null_column.rb +93 -13
  25. data/lib/rubocop/cop/rails/pick.rb +4 -0
  26. data/lib/rubocop/cop/rails/pluck_in_where.rb +17 -8
  27. data/lib/rubocop/cop/rails/pluralization_grammar.rb +29 -15
  28. data/lib/rubocop/cop/rails/present.rb +0 -2
  29. data/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +0 -29
  30. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  31. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +9 -0
  32. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -1
  33. data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
  34. data/lib/rubocop/cop/rails/render_plain_text.rb +6 -3
  35. data/lib/rubocop/cop/rails/request_referer.rb +1 -1
  36. data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
  37. data/lib/rubocop/cop/rails/root_pathname_methods.rb +15 -11
  38. data/lib/rubocop/cop/rails/save_bang.rb +2 -0
  39. data/lib/rubocop/cop/rails/skips_model_validations.rb +8 -3
  40. data/lib/rubocop/cop/rails/time_zone.rb +2 -1
  41. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +12 -4
  42. data/lib/rubocop/cop/rails/unknown_env.rb +1 -1
  43. data/lib/rubocop/cop/rails/unused_ignored_columns.rb +6 -0
  44. data/lib/rubocop/cop/rails/validation.rb +8 -3
  45. data/lib/rubocop/cop/rails/where_equals.rb +28 -12
  46. data/lib/rubocop/cop/rails/where_exists.rb +3 -3
  47. data/lib/rubocop/cop/rails/where_missing.rb +5 -1
  48. data/lib/rubocop/cop/rails/where_not.rb +11 -6
  49. data/lib/rubocop/cop/rails/where_range.rb +203 -0
  50. data/lib/rubocop/cop/rails_cops.rb +2 -0
  51. data/lib/rubocop/rails/schema_loader/schema.rb +2 -1
  52. data/lib/rubocop/rails/schema_loader.rb +5 -15
  53. data/lib/rubocop/rails/version.rb +1 -1
  54. metadata +10 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f90e14aba3397c0edacdc63f7dd9d5b83ed7d79382041f5f37e3201dea96c3db
4
- data.tar.gz: 31ebefe705b4148901128b2b5feb5948b737acdd5fae210f8da6cec845f17023
3
+ metadata.gz: c6d480f2ef30bba709b183d1a3b71dee6c0838ea2815975b5fd25ab5933277ad
4
+ data.tar.gz: 1d36f2779e44e1fa03437154f388bf2e865c3af810e0238f5ddc6580f024fd04
5
5
  SHA512:
6
- metadata.gz: b90a96dae0688c93975260b480c2add1449c5ca21503a071453464f63ba030713501e1d20e2ea4fdf3385a58d1cf71003e2ede718ec9b6aa80e86e4a82be00a7
7
- data.tar.gz: ad4ed3bbe86f2d1179766c512f347aaa21ea6e18e8af5a00f07eb20098c6c3c0103955ba4366bf952528773b7b2ff6a21af52369969227fd05233138a1060708
6
+ metadata.gz: 5cc2521c185293872667eb2a23aaaadc4ddee8289b1f16c9fff1e6c87b9498708226a0147697acb9bcc3be69642c3f3ecc063b749056c0df1cdb065a224e4a3d
7
+ data.tar.gz: ea268a009b987a6f61008602d67a8e89659611b7469fe6c1b9c81825b5f9227391035866b2ec593e6109e91a470d607f6f4bb48fd11155b9177d59daf2301111
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # RuboCop Rails
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rubocop-rails.svg)](https://badge.fury.io/rb/rubocop-rails)
4
- [![CircleCI](https://circleci.com/gh/rubocop/rubocop-rails.svg?style=svg)](https://circleci.com/gh/rubocop/rubocop-rails)
4
+ [![CI](https://github.com/rubocop/rubocop-rails/actions/workflows/test.yml/badge.svg)](https://github.com/rubocop/rubocop-rails/actions/workflows/test.yml)
5
5
 
6
6
  A [RuboCop](https://github.com/rubocop/rubocop) extension focused on enforcing Rails best practices and coding conventions.
7
7
 
@@ -65,7 +65,7 @@ end
65
65
 
66
66
  ## Rails configuration tip
67
67
 
68
- If you are using Rails 6.1 or newer, add the following `config.generators.after_generate` setting to
68
+ In Rails 6.1+, add the following `config.generators.after_generate` setting to
69
69
  your `config/environments/development.rb` to apply RuboCop autocorrection to code generated by `bin/rails g`.
70
70
 
71
71
  ```ruby
@@ -84,6 +84,20 @@ It uses `rubocop -A` to apply `Style/FrozenStringLiteralComment` and other unsaf
84
84
  `rubocop -A` is unsafe autocorrection, but code generated by default is simple and less likely to
85
85
  be incompatible with `rubocop -A`. If you have problems you can replace it with `rubocop -a` instead.
86
86
 
87
+ In Rails 7.2+, it is recommended to use `config.generators.apply_rubocop_autocorrect_after_generate!` instead of the above setting:
88
+
89
+ ```diff
90
+ # config/environments/development.rb
91
+ Rails.application.configure do
92
+ (snip)
93
+ # Apply autocorrection by RuboCop to files generated by `bin/rails generate`.
94
+ - # config.generators.apply_rubocop_autocorrect_after_generate!
95
+ + config.generators.apply_rubocop_autocorrect_after_generate!
96
+ end
97
+ ```
98
+
99
+ You only need to uncomment.
100
+
87
101
  ## The Cops
88
102
 
89
103
  All cops are located under
data/config/default.yml CHANGED
@@ -165,6 +165,7 @@ Rails/ActiveSupportOnLoad:
165
165
  - 'https://guides.rubyonrails.org/engines.html#available-load-hooks'
166
166
  SafeAutoCorrect: false
167
167
  VersionAdded: '2.16'
168
+ VersionChanged: '2.24'
168
169
 
169
170
  Rails/AddColumnIndex:
170
171
  Description: >-
@@ -211,7 +212,9 @@ Rails/ApplicationRecord:
211
212
  Enabled: true
212
213
  SafeAutoCorrect: false
213
214
  VersionAdded: '0.49'
214
- VersionChanged: '2.5'
215
+ VersionChanged: '2.26'
216
+ Exclude:
217
+ - db/**/*.rb
215
218
 
216
219
  Rails/ArelStar:
217
220
  Description: 'Enforces `Arel.star` instead of `"*"` for expanded columns.'
@@ -423,6 +426,14 @@ Rails/EnumHash:
423
426
  Include:
424
427
  - app/models/**/*.rb
425
428
 
429
+ Rails/EnumSyntax:
430
+ Description: 'Use positional arguments over keyword arguments when defining enums.'
431
+ Enabled: pending
432
+ Severity: warning
433
+ VersionAdded: '2.26'
434
+ Include:
435
+ - app/models/**/*.rb
436
+
426
437
  Rails/EnumUniqueness:
427
438
  Description: 'Avoid duplicate integers in hash-syntax `enum` declaration.'
428
439
  Enabled: true
@@ -445,9 +456,10 @@ Rails/EnvironmentVariableAccess:
445
456
  # TODO: Set to `pending` status in RuboCop Rails 2 series when migration doc will be written.
446
457
  Enabled: false
447
458
  VersionAdded: '2.10'
448
- VersionChanged: '2.11'
459
+ VersionChanged: '2.24'
449
460
  Include:
450
461
  - app/**/*.rb
462
+ - config/initializers/**/*.rb
451
463
  - lib/**/*.rb
452
464
  Exclude:
453
465
  - lib/**/*.rake
@@ -691,7 +703,7 @@ Rails/NegateInclude:
691
703
  VersionChanged: '2.9'
692
704
 
693
705
  Rails/NotNullColumn:
694
- Description: 'Do not add a NOT NULL column without a default value.'
706
+ Description: 'Do not add a NOT NULL column without a default value to existing tables.'
695
707
  Enabled: true
696
708
  VersionAdded: '0.43'
697
709
  VersionChanged: '2.20'
@@ -1016,8 +1028,9 @@ Rails/SkipsModelValidations:
1016
1028
  See reference for more information.
1017
1029
  Reference: 'https://guides.rubyonrails.org/active_record_validations.html#skipping-validations'
1018
1030
  Enabled: true
1031
+ Safe: false
1019
1032
  VersionAdded: '0.47'
1020
- VersionChanged: '2.7'
1033
+ VersionChanged: '2.25'
1021
1034
  ForbiddenMethods:
1022
1035
  - decrement!
1023
1036
  - decrement_counter
@@ -1161,8 +1174,9 @@ Rails/UnknownEnv:
1161
1174
 
1162
1175
  Rails/UnusedIgnoredColumns:
1163
1176
  Description: 'Remove a column that does not exist from `ignored_columns`.'
1164
- Enabled: pending
1177
+ Enabled: false
1165
1178
  VersionAdded: '2.11'
1179
+ VersionChanged: '2.25'
1166
1180
  Include:
1167
1181
  - app/models/**/*.rb
1168
1182
 
@@ -1181,12 +1195,12 @@ Rails/Validation:
1181
1195
  - app/models/**/*.rb
1182
1196
 
1183
1197
  Rails/WhereEquals:
1184
- Description: 'Pass conditions to `where` as a hash instead of manually constructing SQL.'
1198
+ Description: 'Pass conditions to `where` and `where.not` as a hash instead of manually constructing SQL.'
1185
1199
  StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions'
1186
1200
  Enabled: 'pending'
1187
1201
  SafeAutoCorrect: false
1188
1202
  VersionAdded: '2.9'
1189
- VersionChanged: '2.10'
1203
+ VersionChanged: '2.26'
1190
1204
 
1191
1205
  Rails/WhereExists:
1192
1206
  Description: 'Prefer `exists?(...)` over `where(...).exists?`.'
@@ -1219,10 +1233,21 @@ Rails/WhereNotWithMultipleConditions:
1219
1233
  VersionAdded: '2.17'
1220
1234
  VersionChanged: '2.18'
1221
1235
 
1236
+ Rails/WhereRange:
1237
+ Description: 'Use ranges in `where` instead of manually constructing SQL.'
1238
+ StyleGuide: 'https://rails.rubystyle.guide/#where-ranges'
1239
+ Enabled: pending
1240
+ SafeAutoCorrect: false
1241
+ VersionAdded: '2.25'
1242
+
1222
1243
  # Accept `redirect_to(...) and return` and similar cases.
1223
1244
  Style/AndOr:
1224
1245
  EnforcedStyle: conditionals
1225
1246
 
1247
+ Style/CollectionCompact:
1248
+ AllowedReceivers:
1249
+ - params
1250
+
1226
1251
  Style/FormatStringToken:
1227
1252
  AllowedMethods:
1228
1253
  - redirect
@@ -39,7 +39,12 @@ module RuboCop
39
39
  end
40
40
 
41
41
  def schema
42
- RuboCop::Rails::SchemaLoader.load(target_ruby_version)
42
+ # For compatibility with RuboCop 1.61.0 or lower.
43
+ if respond_to?(:parser_engine)
44
+ RuboCop::Rails::SchemaLoader.load(target_ruby_version, parser_engine)
45
+ else
46
+ RuboCop::Rails::SchemaLoader.load(target_ruby_version, :parser_whitequark)
47
+ end
43
48
  end
44
49
 
45
50
  def table_name(class_node)
@@ -4,13 +4,40 @@ module RuboCop
4
4
  module Cop
5
5
  # Common functionality for checking target rails version.
6
6
  module TargetRailsVersion
7
+ # Informs the base RuboCop gem that it the Rails version is checked via `requires_gem` API,
8
+ # without needing to call this `#support_target_rails_version` method.
9
+ USES_REQUIRES_GEM_API = true
10
+
7
11
  def minimum_target_rails_version(version)
8
- @minimum_target_rails_version = version
12
+ if respond_to?(:requires_gem)
13
+ case version
14
+ when Integer, Float then requires_gem(TARGET_GEM_NAME, ">= #{version}")
15
+ when String then requires_gem(TARGET_GEM_NAME, version)
16
+ end
17
+ else
18
+ # Fallback path for previous versions of RuboCop which don't support the `requires_gem` API yet.
19
+ @minimum_target_rails_version = version
20
+ end
9
21
  end
10
22
 
11
23
  def support_target_rails_version?(version)
12
- @minimum_target_rails_version <= version
24
+ if respond_to?(:requires_gem)
25
+ return false unless gem_requirements
26
+
27
+ gem_requirement = gem_requirements[TARGET_GEM_NAME]
28
+ return true unless gem_requirement # If we have no requirement, then we support all versions
29
+
30
+ gem_requirement.satisfied_by?(Gem::Version.new(version))
31
+ else
32
+ # Fallback path for previous versions of RuboCop which don't support the `requires_gem` API yet.
33
+ @minimum_target_rails_version <= version
34
+ end
13
35
  end
36
+
37
+ # Look for `railties` instead of `rails`, to support apps that only use a subset of `rails`
38
+ # See https://github.com/rubocop/rubocop/pull/11289
39
+ TARGET_GEM_NAME = 'railties'
40
+ private_constant :TARGET_GEM_NAME
14
41
  end
15
42
  end
16
43
  end
@@ -99,6 +99,8 @@ module RuboCop
99
99
 
100
100
  def use_redirect_to?(context)
101
101
  context.right_siblings.compact.any? do |sibling|
102
+ # Unwrap `return redirect_to :index`
103
+ sibling = sibling.children.first if sibling.return_type? && sibling.children.one?
102
104
  sibling.send_type? && sibling.method?(:redirect_to)
103
105
  end
104
106
  end
@@ -92,11 +92,7 @@ module RuboCop
92
92
  end
93
93
 
94
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
95
+ ranges = [node, *processed_source.ast_with_comments[node]].map(&:source_range)
100
96
  ranges.reduce do |result, range|
101
97
  add_range(result, range)
102
98
  end
@@ -123,11 +123,7 @@ module RuboCop
123
123
  end
124
124
 
125
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.
129
- !comment_line?(comment.loc.expression.source_line)
130
- # rubocop:enable InternalAffairs/LocationExpression
126
+ !comment_line?(comment.source_range.source_line)
131
127
  end
132
128
 
133
129
  def start_line_position(node)
@@ -55,15 +55,35 @@ module RuboCop
55
55
  'ActiveSupport::TestCase' => 'active_support_test_case'
56
56
  }.freeze
57
57
 
58
+ RAILS_5_2_LOAD_HOOKS = {
59
+ 'ActiveRecord::ConnectionAdapters::SQLite3Adapter' => 'active_record_sqlite3adapter'
60
+ }.freeze
61
+
62
+ RAILS_7_1_LOAD_HOOKS = {
63
+ 'ActiveRecord::TestFixtures' => 'active_record_fixtures',
64
+ 'ActiveModel::Model' => 'active_model',
65
+ 'ActionText::EncryptedRichText' => 'action_text_encrypted_rich_text',
66
+ 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter' => 'active_record_postgresqladapter',
67
+ 'ActiveRecord::ConnectionAdapters::Mysql2Adapter' => 'active_record_mysql2adapter',
68
+ 'ActiveRecord::ConnectionAdapters::TrilogyAdapter' => 'active_record_trilogyadapter'
69
+ }.freeze
70
+
58
71
  def on_send(node)
59
72
  receiver, method, arguments = *node # rubocop:disable InternalAffairs/NodeDestructuring
60
- return unless receiver && (hook = LOAD_HOOKS[receiver.const_name])
73
+ return unless arguments && (hook = hook_for_const(receiver&.const_name))
61
74
 
62
75
  preferred = "ActiveSupport.on_load(:#{hook}) { #{method} #{arguments.source} }"
63
76
  add_offense(node, message: format(MSG, prefer: preferred, current: node.source)) do |corrector|
64
77
  corrector.replace(node, preferred)
65
78
  end
66
79
  end
80
+
81
+ def hook_for_const(const_name)
82
+ hook = LOAD_HOOKS[const_name]
83
+ hook ||= RAILS_5_2_LOAD_HOOKS[const_name] if target_rails_version >= 5.2
84
+ hook ||= RAILS_7_1_LOAD_HOOKS[const_name] if target_rails_version >= 7.1
85
+ hook
86
+ end
67
87
  end
68
88
  end
69
89
  end
@@ -5,6 +5,10 @@ module RuboCop
5
5
  module Rails
6
6
  # Checks that models subclass `ApplicationRecord` with Rails 5.0.
7
7
  #
8
+ # It is a common practice to define models inside migrations in order to retain forward
9
+ # compatibility by avoiding loading any application code. And so migration files are excluded
10
+ # by default for this cop.
11
+ #
8
12
  # @safety
9
13
  # This cop's autocorrection is unsafe because it may let the logic from `ApplicationRecord`
10
14
  # sneak into an Active Record model that is not purposed to inherit logic common among other
@@ -113,8 +113,10 @@ module RuboCop
113
113
  MYSQL_COMBINABLE_ALTER_METHODS = %i[rename_column add_index remove_index].freeze
114
114
 
115
115
  POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[change_default].freeze
116
+ POSTGRESQL_COMBINABLE_TRANSFORMATIONS_SINCE_6_1 = %i[change_null].freeze
116
117
 
117
118
  POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[change_column_default].freeze
119
+ POSTGRESQL_COMBINABLE_ALTER_METHODS_SINCE_6_1 = %i[change_column_null].freeze
118
120
 
119
121
  def on_def(node)
120
122
  return unless support_bulk_alter?
@@ -138,9 +140,9 @@ module RuboCop
138
140
  return unless support_bulk_alter?
139
141
  return unless node.command?(:change_table)
140
142
  return if include_bulk_options?(node)
141
- return unless node.block_node
143
+ return unless (body = node.block_node&.body)
142
144
 
143
- send_nodes = send_nodes_from_change_table_block(node.block_node.body)
145
+ send_nodes = send_nodes_from_change_table_block(body)
144
146
 
145
147
  add_offense_for_change_table(node) if count_transformations(send_nodes) > 1
146
148
  end
@@ -196,7 +198,9 @@ module RuboCop
196
198
  when MYSQL
197
199
  COMBINABLE_ALTER_METHODS + MYSQL_COMBINABLE_ALTER_METHODS
198
200
  when POSTGRESQL
199
- COMBINABLE_ALTER_METHODS + POSTGRESQL_COMBINABLE_ALTER_METHODS
201
+ result = COMBINABLE_ALTER_METHODS + POSTGRESQL_COMBINABLE_ALTER_METHODS
202
+ result += POSTGRESQL_COMBINABLE_ALTER_METHODS_SINCE_6_1 if target_rails_version >= 6.1
203
+ result
200
204
  end
201
205
  end
202
206
 
@@ -205,7 +209,9 @@ module RuboCop
205
209
  when MYSQL
206
210
  COMBINABLE_TRANSFORMATIONS + MYSQL_COMBINABLE_TRANSFORMATIONS
207
211
  when POSTGRESQL
208
- COMBINABLE_TRANSFORMATIONS + POSTGRESQL_COMBINABLE_TRANSFORMATIONS
212
+ result = COMBINABLE_TRANSFORMATIONS + POSTGRESQL_COMBINABLE_TRANSFORMATIONS
213
+ result += POSTGRESQL_COMBINABLE_TRANSFORMATIONS_SINCE_6_1 if target_rails_version >= 6.1
214
+ result
209
215
  end
210
216
  end
211
217
 
@@ -16,7 +16,6 @@ module RuboCop
16
16
  # And `compact_blank!` has different implementations for `Array`, `Hash`, and
17
17
  # `ActionController::Parameters`.
18
18
  # `Array#compact_blank!`, `Hash#compact_blank!` are equivalent to `delete_if(&:blank?)`.
19
- # `ActionController::Parameters#compact_blank!` is equivalent to `reject!(&:blank?)`.
20
19
  # If the cop makes a mistake, autocorrected code may get unexpected behavior.
21
20
  #
22
21
  # @example
@@ -24,6 +23,10 @@ module RuboCop
24
23
  # # bad
25
24
  # collection.reject(&:blank?)
26
25
  # collection.reject { |_k, v| v.blank? }
26
+ # collection.select(&:present?)
27
+ # collection.select { |_k, v| v.present? }
28
+ # collection.filter(&:present?)
29
+ # collection.filter { |_k, v| v.present? }
27
30
  #
28
31
  # # good
29
32
  # collection.compact_blank
@@ -31,8 +34,8 @@ module RuboCop
31
34
  # # bad
32
35
  # collection.delete_if(&:blank?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
33
36
  # collection.delete_if { |_k, v| v.blank? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
34
- # collection.reject!(&:blank?) # Same behavior as `ActionController::Parameters#compact_blank!`
35
- # collection.reject! { |_k, v| v.blank? } # Same behavior as `ActionController::Parameters#compact_blank!`
37
+ # collection.keep_if(&:present?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
38
+ # collection.keep_if { |_k, v| v.present? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
36
39
  #
37
40
  # # good
38
41
  # collection.compact_blank!
@@ -43,25 +46,41 @@ module RuboCop
43
46
  extend TargetRailsVersion
44
47
 
45
48
  MSG = 'Use `%<preferred_method>s` instead.'
46
- RESTRICT_ON_SEND = %i[reject delete_if reject!].freeze
49
+ RESTRICT_ON_SEND = %i[reject delete_if select filter keep_if].freeze
50
+ DESTRUCTIVE_METHODS = %i[delete_if keep_if].freeze
47
51
 
48
52
  minimum_target_rails_version 6.1
49
53
 
50
54
  def_node_matcher :reject_with_block?, <<~PATTERN
51
55
  (block
52
- (send _ {:reject :delete_if :reject!})
56
+ (send _ {:reject :delete_if})
53
57
  $(args ...)
54
58
  (send
55
59
  $(lvar _) :blank?))
56
60
  PATTERN
57
61
 
58
62
  def_node_matcher :reject_with_block_pass?, <<~PATTERN
59
- (send _ {:reject :delete_if :reject!}
63
+ (send _ {:reject :delete_if}
60
64
  (block_pass
61
65
  (sym :blank?)))
62
66
  PATTERN
63
67
 
68
+ def_node_matcher :select_with_block?, <<~PATTERN
69
+ (block
70
+ (send _ {:select :filter :keep_if})
71
+ $(args ...)
72
+ (send
73
+ $(lvar _) :present?))
74
+ PATTERN
75
+
76
+ def_node_matcher :select_with_block_pass?, <<~PATTERN
77
+ (send _ {:select :filter :keep_if}
78
+ (block-pass
79
+ (sym :present?)))
80
+ PATTERN
81
+
64
82
  def on_send(node)
83
+ return if target_ruby_version < 2.6 && node.method?(:filter)
65
84
  return unless bad_method?(node)
66
85
 
67
86
  range = offense_range(node)
@@ -75,8 +94,10 @@ module RuboCop
75
94
 
76
95
  def bad_method?(node)
77
96
  return true if reject_with_block_pass?(node)
97
+ return true if select_with_block_pass?(node)
78
98
 
79
- if (arguments, receiver_in_block = reject_with_block?(node.parent))
99
+ arguments, receiver_in_block = reject_with_block?(node.parent) || select_with_block?(node.parent)
100
+ if arguments
80
101
  return use_single_value_block_argument?(arguments, receiver_in_block) ||
81
102
  use_hash_value_block_argument?(arguments, receiver_in_block)
82
103
  end
@@ -103,7 +124,7 @@ module RuboCop
103
124
  end
104
125
 
105
126
  def preferred_method(node)
106
- node.method?(:reject) ? 'compact_blank' : 'compact_blank!'
127
+ DESTRUCTIVE_METHODS.include?(node.method_name) ? 'compact_blank!' : 'compact_blank'
107
128
  end
108
129
  end
109
130
  end
@@ -31,7 +31,7 @@ module RuboCop
31
31
  time
32
32
  ].to_set.freeze
33
33
 
34
- # Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.1.0.
34
+ # Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.1.3.
35
35
  # rubocop:disable Metrics/CollectionLiteralLength
36
36
  DANGEROUS_COLUMN_NAMES = %w[
37
37
  __callbacks
@@ -290,7 +290,6 @@ module RuboCop
290
290
  new_record
291
291
  no_touching
292
292
  normalize_reflection_attribute
293
- object_id
294
293
  partial_inserts
295
294
  partial_updates
296
295
  perform_validations
@@ -12,10 +12,10 @@ module RuboCop
12
12
  # The cop also reports warnings when you are using `to_time` method,
13
13
  # because it doesn't know about Rails time zone either.
14
14
  #
15
- # Two styles are supported for this cop. When `EnforcedStyle` is 'strict'
15
+ # Two styles are supported for this cop. When `EnforcedStyle` is `strict`
16
16
  # then the Date methods `today`, `current`, `yesterday`, and `tomorrow`
17
17
  # are prohibited and the usage of both `to_time`
18
- # and 'to_time_in_current_zone' are reported as warning.
18
+ # and `to_time_in_current_zone` are reported as warning.
19
19
  #
20
20
  # When `EnforcedStyle` is `flexible` then only `Date.today` is prohibited.
21
21
  #
@@ -12,6 +12,12 @@ module RuboCop
12
12
  #
13
13
  # @example
14
14
  # # bad
15
+ # enum :status, [:active, :archived]
16
+ #
17
+ # # good
18
+ # enum :status, { active: 0, archived: 1 }
19
+ #
20
+ # # bad
15
21
  # enum status: [:active, :archived]
16
22
  #
17
23
  # # good
@@ -23,7 +29,11 @@ module RuboCop
23
29
  MSG = 'Enum defined as an array found in `%<enum>s` enum declaration. Use hash syntax instead.'
24
30
  RESTRICT_ON_SEND = %i[enum].freeze
25
31
 
26
- def_node_matcher :enum?, <<~PATTERN
32
+ def_node_matcher :enum_with_array?, <<~PATTERN
33
+ (send nil? :enum $_ ${array} ...)
34
+ PATTERN
35
+
36
+ def_node_matcher :enum_with_old_syntax?, <<~PATTERN
27
37
  (send nil? :enum (hash $...))
28
38
  PATTERN
29
39
 
@@ -32,17 +42,19 @@ module RuboCop
32
42
  PATTERN
33
43
 
34
44
  def on_send(node)
35
- enum?(node) do |pairs|
45
+ target_rails_version >= 7.0 && enum_with_array?(node) do |key, array|
46
+ add_offense(array, message: message(key)) do |corrector|
47
+ corrector.replace(array, build_hash(array))
48
+ end
49
+ end
50
+
51
+ enum_with_old_syntax?(node) do |pairs|
36
52
  pairs.each do |pair|
37
53
  key, array = array_pair?(pair)
38
54
  next unless key
39
55
 
40
- add_offense(array, message: format(MSG, enum: enum_name(key))) do |corrector|
41
- hash = array.children.each_with_index.map do |elem, index|
42
- "#{source(elem)} => #{index}"
43
- end.join(', ')
44
-
45
- corrector.replace(array, "{#{hash}}")
56
+ add_offense(array, message: message(key)) do |corrector|
57
+ corrector.replace(array, build_hash(array))
46
58
  end
47
59
  end
48
60
  end
@@ -50,6 +62,10 @@ module RuboCop
50
62
 
51
63
  private
52
64
 
65
+ def message(key)
66
+ format(MSG, enum: enum_name(key))
67
+ end
68
+
53
69
  def enum_name(key)
54
70
  case key.type
55
71
  when :sym, :str
@@ -69,6 +85,13 @@ module RuboCop
69
85
  elem.source
70
86
  end
71
87
  end
88
+
89
+ def build_hash(array)
90
+ hash = array.children.each_with_index.map do |elem, index|
91
+ "#{source(elem)} => #{index}"
92
+ end.join(', ')
93
+ "{#{hash}}"
94
+ end
72
95
  end
73
96
  end
74
97
  end