rubocop-rails 2.13.0 → 2.14.0

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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/config/default.yml +75 -4
  4. data/lib/rubocop/cop/mixin/class_send_node_helper.rb +20 -0
  5. data/lib/rubocop/cop/mixin/migrations_helper.rb +26 -0
  6. data/lib/rubocop/cop/rails/action_controller_test_case.rb +47 -0
  7. data/lib/rubocop/cop/rails/after_commit_override.rb +2 -12
  8. data/lib/rubocop/cop/rails/bulk_change_table.rb +20 -6
  9. data/lib/rubocop/cop/rails/compact_blank.rb +22 -13
  10. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +108 -0
  11. data/lib/rubocop/cop/rails/duplicate_association.rb +56 -0
  12. data/lib/rubocop/cop/rails/duplicate_scope.rb +46 -0
  13. data/lib/rubocop/cop/rails/duration_arithmetic.rb +2 -1
  14. data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +94 -0
  15. data/lib/rubocop/cop/rails/i18n_locale_texts.rb +110 -0
  16. data/lib/rubocop/cop/rails/index_by.rb +6 -6
  17. data/lib/rubocop/cop/rails/index_with.rb +6 -6
  18. data/lib/rubocop/cop/rails/inverse_of.rb +17 -1
  19. data/lib/rubocop/cop/rails/migration_class_name.rb +61 -0
  20. data/lib/rubocop/cop/rails/pluck.rb +15 -7
  21. data/lib/rubocop/cop/rails/read_write_attribute.rb +51 -14
  22. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +93 -28
  23. data/lib/rubocop/cop/rails/reversible_migration.rb +5 -3
  24. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +2 -10
  25. data/lib/rubocop/cop/rails/table_name_assignment.rb +44 -0
  26. data/lib/rubocop/cop/rails/transaction_exit_statement.rb +77 -0
  27. data/lib/rubocop/cop/rails/unused_ignored_columns.rb +2 -0
  28. data/lib/rubocop/cop/rails_cops.rb +11 -0
  29. data/lib/rubocop/rails/version.rb +1 -1
  30. metadata +15 -4
@@ -8,6 +8,10 @@ module RuboCop
8
8
  # explicitly set to `false`. The presence validator is added
9
9
  # automatically, and explicit presence validation is redundant.
10
10
  #
11
+ # @safety
12
+ # This cop's autocorrection is unsafe because it changes the default error message
13
+ # from "can't be blank" to "must exist".
14
+ #
11
15
  # @example
12
16
  # # bad
13
17
  # belongs_to :user
@@ -32,7 +36,7 @@ module RuboCop
32
36
  extend AutoCorrector
33
37
  extend TargetRailsVersion
34
38
 
35
- MSG = 'Remove explicit presence validation for `%<association>s`.'
39
+ MSG = 'Remove explicit presence validation for %<association>s.'
36
40
  RESTRICT_ON_SEND = %i[validates].freeze
37
41
 
38
42
  minimum_target_rails_version 5.0
@@ -43,28 +47,36 @@ module RuboCop
43
47
  # @example source that matches - by association
44
48
  # validates :user, presence: true
45
49
  #
46
- # @example source that matches - with presence options
47
- # validates :user, presence: { message: 'duplicate' }
50
+ # @example source that matches - by association
51
+ # validates :name, :user, presence: true
48
52
  #
49
53
  # @example source that matches - by a foreign key
50
54
  # validates :user_id, presence: true
55
+ #
56
+ # @example source that DOES NOT match - strict validation
57
+ # validates :user_id, presence: true, strict: true
58
+ #
59
+ # @example source that DOES NOT match - custom strict validation
60
+ # validates :user_id, presence: true, strict: MissingUserError
51
61
  def_node_matcher :presence_validation?, <<~PATTERN
52
- $(
62
+ (
53
63
  send nil? :validates
54
- (sym $_)
55
- ...
56
- $(hash <$(pair (sym :presence) {true hash}) ...>)
64
+ (sym $_)+
65
+ $[
66
+ (hash <$(pair (sym :presence) true) ...>) # presence: true
67
+ !(hash <$(pair (sym :strict) {true const}) ...>) # strict: true
68
+ ]
57
69
  )
58
70
  PATTERN
59
71
 
60
- # @!method optional_option?(node)
61
- # Match a `belongs_to` association with an optional option in a hash
72
+ # @!method optional?(node)
73
+ # Match a `belongs_to` association with an optional option in a hash
62
74
  def_node_matcher :optional?, <<~PATTERN
63
75
  (send nil? :belongs_to _ ... #optional_option?)
64
76
  PATTERN
65
77
 
66
78
  # @!method optional_option?(node)
67
- # Match an optional option in a hash
79
+ # Match an optional option in a hash
68
80
  def_node_matcher :optional_option?, <<~PATTERN
69
81
  {
70
82
  (hash <(pair (sym :optional) true) ...>) # optional: true
@@ -122,7 +134,7 @@ module RuboCop
122
134
  )
123
135
  PATTERN
124
136
 
125
- # @!method belongs_to_without_fk?(node, fk)
137
+ # @!method belongs_to_without_fk?(node, key)
126
138
  # Match a matching `belongs_to` association, without an explicit `foreign_key` option
127
139
  #
128
140
  # @param node [RuboCop::AST::Node]
@@ -150,21 +162,43 @@ module RuboCop
150
162
  PATTERN
151
163
 
152
164
  def on_send(node)
153
- validation, key, options, presence = presence_validation?(node)
154
- return unless validation
165
+ presence_validation?(node) do |all_keys, options, presence|
166
+ keys = non_optional_belongs_to(node.parent, all_keys)
167
+ return if keys.none?
155
168
 
156
- belongs_to = belongs_to_for(node.parent, key)
157
- return unless belongs_to
158
- return if optional?(belongs_to)
169
+ add_offense_and_correct(node, all_keys, keys, options, presence)
170
+ end
171
+ end
159
172
 
160
- message = format(MSG, association: key.to_s)
173
+ private
161
174
 
162
- add_offense(presence, message: message) do |corrector|
163
- remove_presence_validation(corrector, node, options, presence)
175
+ def add_offense_and_correct(node, all_keys, keys, options, presence)
176
+ add_offense(presence, message: message_for(keys)) do |corrector|
177
+ if options.children.one? # `presence: true` is the only option
178
+ if keys == all_keys
179
+ remove_validation(corrector, node)
180
+ else
181
+ remove_keys_from_validation(corrector, node, keys)
182
+ end
183
+ elsif keys == all_keys
184
+ remove_presence_option(corrector, presence)
185
+ else
186
+ extract_validation_for_keys(corrector, node, keys, options)
187
+ end
164
188
  end
165
189
  end
166
190
 
167
- private
191
+ def message_for(keys)
192
+ display_keys = keys.map { |key| "`#{key}`" }.join('/')
193
+ format(MSG, association: display_keys)
194
+ end
195
+
196
+ def non_optional_belongs_to(node, keys)
197
+ keys.select do |key|
198
+ belongs_to = belongs_to_for(node, key)
199
+ belongs_to && !optional?(belongs_to)
200
+ end
201
+ end
168
202
 
169
203
  def belongs_to_for(model_class_node, key)
170
204
  if key.to_s.end_with?('_id')
@@ -175,17 +209,48 @@ module RuboCop
175
209
  end
176
210
  end
177
211
 
178
- def remove_presence_validation(corrector, node, options, presence)
179
- if options.children.one?
180
- corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
181
- else
182
- range = range_with_surrounding_comma(
183
- range_with_surrounding_space(range: presence.source_range, side: :left),
184
- :left
212
+ def remove_validation(corrector, node)
213
+ corrector.remove(validation_range(node))
214
+ end
215
+
216
+ def remove_keys_from_validation(corrector, node, keys)
217
+ keys.each do |key|
218
+ key_node = node.arguments.find { |arg| arg.value == key }
219
+ key_range = range_with_surrounding_space(
220
+ range: range_with_surrounding_comma(key_node.source_range, :right),
221
+ side: :right
185
222
  )
186
- corrector.remove(range)
223
+ corrector.remove(key_range)
187
224
  end
188
225
  end
226
+
227
+ def remove_presence_option(corrector, presence)
228
+ range = range_with_surrounding_comma(
229
+ range_with_surrounding_space(range: presence.source_range, side: :left),
230
+ :left
231
+ )
232
+ corrector.remove(range)
233
+ end
234
+
235
+ def extract_validation_for_keys(corrector, node, keys, options)
236
+ indentation = ' ' * node.source_range.column
237
+ options_without_presence = options.children.reject { |pair| pair.key.value == :presence }
238
+ source = [
239
+ indentation,
240
+ 'validates ',
241
+ keys.map(&:inspect).join(', '),
242
+ ', ',
243
+ options_without_presence.map(&:source).join(', '),
244
+ "\n"
245
+ ].join
246
+
247
+ remove_keys_from_validation(corrector, node, keys)
248
+ corrector.insert_after(validation_range(node), source)
249
+ end
250
+
251
+ def validation_range(node)
252
+ range_by_whole_lines(node.source_range, include_final_newline: true)
253
+ end
189
254
  end
190
255
  end
191
256
  end
@@ -176,10 +176,12 @@ module RuboCop
176
176
  #
177
177
  # @see https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html
178
178
  class ReversibleMigration < Base
179
+ include MigrationsHelper
180
+
179
181
  MSG = '%<action>s is not reversible.'
180
182
 
181
183
  def_node_matcher :irreversible_schema_statement_call, <<~PATTERN
182
- (send nil? ${:change_column :execute :remove_belongs_to :remove_reference} ...)
184
+ (send nil? ${:change_column :execute} ...)
183
185
  PATTERN
184
186
 
185
187
  def_node_matcher :drop_table_call, <<~PATTERN
@@ -207,7 +209,7 @@ module RuboCop
207
209
  PATTERN
208
210
 
209
211
  def on_send(node)
210
- return unless within_change_method?(node)
212
+ return unless in_migration?(node) && within_change_method?(node)
211
213
  return if within_reversible_or_up_only_block?(node)
212
214
 
213
215
  check_irreversible_schema_statement_node(node)
@@ -220,7 +222,7 @@ module RuboCop
220
222
  end
221
223
 
222
224
  def on_block(node)
223
- return unless within_change_method?(node)
225
+ return unless in_migration?(node) && within_change_method?(node)
224
226
  return if within_reversible_or_up_only_block?(node)
225
227
  return if node.body.nil?
226
228
 
@@ -43,19 +43,11 @@ module RuboCop
43
43
  # end
44
44
  # end
45
45
  class ReversibleMigrationMethodDefinition < Base
46
+ include MigrationsHelper
47
+
46
48
  MSG = 'Migrations must contain either a `change` method, or ' \
47
49
  'both an `up` and a `down` method.'
48
50
 
49
- def_node_matcher :migration_class?, <<~PATTERN
50
- (class
51
- (const nil? _)
52
- (send
53
- (const (const {nil? cbase} :ActiveRecord) :Migration)
54
- :[]
55
- (float _))
56
- _)
57
- PATTERN
58
-
59
51
  def_node_matcher :change_method?, <<~PATTERN
60
52
  [ #migration_class? `(def :change (args) _) ]
61
53
  PATTERN
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop enforces the absence of explicit table name assignment.
7
+ #
8
+ # `self.table_name=` should only be used for very good reasons,
9
+ # such as not having control over the database, or working
10
+ # on a legacy project.
11
+ #
12
+ # If you need to change how your model's name is translated to
13
+ # a table name, you may want to look at Inflections:
14
+ # https://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html
15
+ #
16
+ # If you wish to add a prefix in front of your model, or wish to change
17
+ # the default prefix, `self.table_name_prefix` might better suit your needs:
18
+ # https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema.html#method-c-table_name_prefix-3D
19
+ #
20
+ # STI base classes named `Base` are ignored by this cop.
21
+ # For more information: https://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html
22
+ #
23
+ # @example
24
+ # # bad
25
+ # self.table_name = 'some_table_name'
26
+ # self.table_name = :some_other_name
27
+ class TableNameAssignment < Base
28
+ include ActiveRecordHelper
29
+
30
+ MSG = 'Do not use `self.table_name =`.'
31
+
32
+ def_node_matcher :base_class?, <<~PATTERN
33
+ (class (const ... :Base) ...)
34
+ PATTERN
35
+
36
+ def on_class(class_node)
37
+ return if base_class?(class_node)
38
+
39
+ find_set_table_name(class_node).each { |node| add_offense(node) }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks for the use of exit statements (namely `return`,
7
+ # `break` and `throw`) in transactions. This is due to the eventual
8
+ # unexpected behavior when using ActiveRecord >= 7, where transactions
9
+ # exitted using these statements are being rollbacked rather than
10
+ # committed (pre ActiveRecord 7 behavior).
11
+ #
12
+ # As alternatives, it would be more intuitive to explicitly raise an
13
+ # error when rollback is desired, and to use `next` when commit is
14
+ # desired.
15
+ #
16
+ # @example
17
+ # # bad
18
+ # ApplicationRecord.transaction do
19
+ # return if user.active?
20
+ # end
21
+ #
22
+ # # bad
23
+ # ApplicationRecord.transaction do
24
+ # break if user.active?
25
+ # end
26
+ #
27
+ # # bad
28
+ # ApplicationRecord.transaction do
29
+ # throw if user.active?
30
+ # end
31
+ #
32
+ # # good
33
+ # ApplicationRecord.transaction do
34
+ # # Rollback
35
+ # raise "User is active" if user.active?
36
+ # end
37
+ #
38
+ # # good
39
+ # ApplicationRecord.transaction do
40
+ # # Commit
41
+ # next if user.active?
42
+ # end
43
+ #
44
+ # @see https://github.com/rails/rails/commit/15aa4200e083
45
+ class TransactionExitStatement < Base
46
+ MSG = <<~MSG.chomp
47
+ Exit statement `%<statement>s` is not allowed. Use `raise` (rollback) or `next` (commit).
48
+ MSG
49
+
50
+ RESTRICT_ON_SEND = %i[transaction].freeze
51
+
52
+ def_node_search :exit_statements, <<~PATTERN
53
+ ({return | break | send nil? :throw} ...)
54
+ PATTERN
55
+
56
+ def on_send(node)
57
+ parent = node.parent
58
+
59
+ return unless parent&.block_type?
60
+
61
+ exit_statements(parent.body).each do |statement_node|
62
+ statement = if statement_node.return_type?
63
+ 'return'
64
+ elsif statement_node.break_type?
65
+ 'break'
66
+ else
67
+ statement_node.method_name
68
+ end
69
+ message = format(MSG, statement: statement)
70
+
71
+ add_offense(statement_node, message: message)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -61,6 +61,8 @@ module RuboCop
61
61
 
62
62
  def table(node)
63
63
  klass = class_node(node)
64
+ return unless klass
65
+
64
66
  schema.table_by(name: table_name(klass))
65
67
  end
66
68
  end
@@ -2,10 +2,13 @@
2
2
 
3
3
  require_relative 'mixin/active_record_helper'
4
4
  require_relative 'mixin/active_record_migrations_helper'
5
+ require_relative 'mixin/class_send_node_helper'
5
6
  require_relative 'mixin/enforce_superclass'
6
7
  require_relative 'mixin/index_method'
8
+ require_relative 'mixin/migrations_helper'
7
9
  require_relative 'mixin/target_rails_version'
8
10
 
11
+ require_relative 'rails/action_controller_test_case'
9
12
  require_relative 'rails/action_filter'
10
13
  require_relative 'rails/active_record_aliases'
11
14
  require_relative 'rails/active_record_callbacks_order'
@@ -30,6 +33,9 @@ require_relative 'rails/date'
30
33
  require_relative 'rails/default_scope'
31
34
  require_relative 'rails/delegate'
32
35
  require_relative 'rails/delegate_allow_blank'
36
+ require_relative 'rails/deprecated_active_model_errors_methods'
37
+ require_relative 'rails/duplicate_association'
38
+ require_relative 'rails/duplicate_scope'
33
39
  require_relative 'rails/duration_arithmetic'
34
40
  require_relative 'rails/dynamic_find_by'
35
41
  require_relative 'rails/eager_evaluation_log_message'
@@ -48,7 +54,9 @@ require_relative 'rails/has_many_or_has_one_dependent'
48
54
  require_relative 'rails/helper_instance_variable'
49
55
  require_relative 'rails/http_positional_arguments'
50
56
  require_relative 'rails/http_status'
57
+ require_relative 'rails/i18n_lazy_lookup'
51
58
  require_relative 'rails/i18n_locale_assignment'
59
+ require_relative 'rails/i18n_locale_texts'
52
60
  require_relative 'rails/ignored_skip_action_filter_option'
53
61
  require_relative 'rails/index_by'
54
62
  require_relative 'rails/index_with'
@@ -58,6 +66,7 @@ require_relative 'rails/lexically_scoped_action_filter'
58
66
  require_relative 'rails/link_to_blank'
59
67
  require_relative 'rails/mailer_name'
60
68
  require_relative 'rails/match_route'
69
+ require_relative 'rails/migration_class_name'
61
70
  require_relative 'rails/negate_include'
62
71
  require_relative 'rails/not_null_column'
63
72
  require_relative 'rails/order_by_id'
@@ -95,8 +104,10 @@ require_relative 'rails/scope_args'
95
104
  require_relative 'rails/short_i18n'
96
105
  require_relative 'rails/skips_model_validations'
97
106
  require_relative 'rails/squished_sql_heredocs'
107
+ require_relative 'rails/table_name_assignment'
98
108
  require_relative 'rails/time_zone'
99
109
  require_relative 'rails/time_zone_assignment'
110
+ require_relative 'rails/transaction_exit_statement'
100
111
  require_relative 'rails/uniq_before_pluck'
101
112
  require_relative 'rails/unique_validation_without_index'
102
113
  require_relative 'rails/unknown_env'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Rails
5
5
  # This module holds the RuboCop Rails version information.
6
6
  module Version
7
- STRING = '2.13.0'
7
+ STRING = '2.14.0'
8
8
 
9
9
  def self.document_version
10
10
  STRING.match('\d+\.\d+').to_s
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.13.0
4
+ version: 2.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-12-25 00:00:00.000000000 Z
13
+ date: 2022-03-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -79,9 +79,12 @@ files:
79
79
  - lib/rubocop-rails.rb
80
80
  - lib/rubocop/cop/mixin/active_record_helper.rb
81
81
  - lib/rubocop/cop/mixin/active_record_migrations_helper.rb
82
+ - lib/rubocop/cop/mixin/class_send_node_helper.rb
82
83
  - lib/rubocop/cop/mixin/enforce_superclass.rb
83
84
  - lib/rubocop/cop/mixin/index_method.rb
85
+ - lib/rubocop/cop/mixin/migrations_helper.rb
84
86
  - lib/rubocop/cop/mixin/target_rails_version.rb
87
+ - lib/rubocop/cop/rails/action_controller_test_case.rb
85
88
  - lib/rubocop/cop/rails/action_filter.rb
86
89
  - lib/rubocop/cop/rails/active_record_aliases.rb
87
90
  - lib/rubocop/cop/rails/active_record_callbacks_order.rb
@@ -106,6 +109,9 @@ files:
106
109
  - lib/rubocop/cop/rails/default_scope.rb
107
110
  - lib/rubocop/cop/rails/delegate.rb
108
111
  - lib/rubocop/cop/rails/delegate_allow_blank.rb
112
+ - lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb
113
+ - lib/rubocop/cop/rails/duplicate_association.rb
114
+ - lib/rubocop/cop/rails/duplicate_scope.rb
109
115
  - lib/rubocop/cop/rails/duration_arithmetic.rb
110
116
  - lib/rubocop/cop/rails/dynamic_find_by.rb
111
117
  - lib/rubocop/cop/rails/eager_evaluation_log_message.rb
@@ -124,7 +130,9 @@ files:
124
130
  - lib/rubocop/cop/rails/helper_instance_variable.rb
125
131
  - lib/rubocop/cop/rails/http_positional_arguments.rb
126
132
  - lib/rubocop/cop/rails/http_status.rb
133
+ - lib/rubocop/cop/rails/i18n_lazy_lookup.rb
127
134
  - lib/rubocop/cop/rails/i18n_locale_assignment.rb
135
+ - lib/rubocop/cop/rails/i18n_locale_texts.rb
128
136
  - lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb
129
137
  - lib/rubocop/cop/rails/index_by.rb
130
138
  - lib/rubocop/cop/rails/index_with.rb
@@ -134,6 +142,7 @@ files:
134
142
  - lib/rubocop/cop/rails/link_to_blank.rb
135
143
  - lib/rubocop/cop/rails/mailer_name.rb
136
144
  - lib/rubocop/cop/rails/match_route.rb
145
+ - lib/rubocop/cop/rails/migration_class_name.rb
137
146
  - lib/rubocop/cop/rails/negate_include.rb
138
147
  - lib/rubocop/cop/rails/not_null_column.rb
139
148
  - lib/rubocop/cop/rails/order_by_id.rb
@@ -171,8 +180,10 @@ files:
171
180
  - lib/rubocop/cop/rails/short_i18n.rb
172
181
  - lib/rubocop/cop/rails/skips_model_validations.rb
173
182
  - lib/rubocop/cop/rails/squished_sql_heredocs.rb
183
+ - lib/rubocop/cop/rails/table_name_assignment.rb
174
184
  - lib/rubocop/cop/rails/time_zone.rb
175
185
  - lib/rubocop/cop/rails/time_zone_assignment.rb
186
+ - lib/rubocop/cop/rails/transaction_exit_statement.rb
176
187
  - lib/rubocop/cop/rails/uniq_before_pluck.rb
177
188
  - lib/rubocop/cop/rails/unique_validation_without_index.rb
178
189
  - lib/rubocop/cop/rails/unknown_env.rb
@@ -194,7 +205,7 @@ metadata:
194
205
  homepage_uri: https://docs.rubocop.org/rubocop-rails/
195
206
  changelog_uri: https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md
196
207
  source_code_uri: https://github.com/rubocop/rubocop-rails/
197
- documentation_uri: https://docs.rubocop.org/rubocop-rails/2.13/
208
+ documentation_uri: https://docs.rubocop.org/rubocop-rails/2.14/
198
209
  bug_tracker_uri: https://github.com/rubocop/rubocop-rails/issues
199
210
  rubygems_mfa_required: 'true'
200
211
  post_install_message:
@@ -212,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
223
  - !ruby/object:Gem::Version
213
224
  version: '0'
214
225
  requirements: []
215
- rubygems_version: 3.2.32
226
+ rubygems_version: 3.3.3
216
227
  signing_key:
217
228
  specification_version: 4
218
229
  summary: Automatic Rails code style checking tool.