rubocop-rails 2.22.1 → 2.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -9
  3. data/config/default.yml +4 -2
  4. data/lib/rubocop/cop/mixin/active_record_helper.rb +15 -3
  5. data/lib/rubocop/cop/mixin/database_type_resolvable.rb +1 -1
  6. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +2 -0
  7. data/lib/rubocop/cop/rails/active_record_aliases.rb +2 -2
  8. data/lib/rubocop/cop/rails/active_support_aliases.rb +6 -5
  9. data/lib/rubocop/cop/rails/active_support_on_load.rb +21 -1
  10. data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
  11. data/lib/rubocop/cop/rails/bulk_change_table.rb +4 -4
  12. data/lib/rubocop/cop/rails/content_tag.rb +1 -1
  13. data/lib/rubocop/cop/rails/dangerous_column_names.rb +2 -3
  14. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +2 -2
  15. data/lib/rubocop/cop/rails/expanded_date_range.rb +1 -1
  16. data/lib/rubocop/cop/rails/file_path.rb +5 -5
  17. data/lib/rubocop/cop/rails/find_by.rb +3 -3
  18. data/lib/rubocop/cop/rails/find_by_id.rb +9 -23
  19. data/lib/rubocop/cop/rails/inquiry.rb +1 -0
  20. data/lib/rubocop/cop/rails/inverse_of.rb +1 -1
  21. data/lib/rubocop/cop/rails/pick.rb +6 -5
  22. data/lib/rubocop/cop/rails/pluck.rb +1 -1
  23. data/lib/rubocop/cop/rails/pluck_id.rb +2 -1
  24. data/lib/rubocop/cop/rails/pluck_in_where.rb +18 -5
  25. data/lib/rubocop/cop/rails/rake_environment.rb +2 -2
  26. data/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +42 -30
  27. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -1
  28. data/lib/rubocop/cop/rails/response_parsed_body.rb +52 -10
  29. data/lib/rubocop/cop/rails/reversible_migration.rb +3 -3
  30. data/lib/rubocop/cop/rails/save_bang.rb +6 -4
  31. data/lib/rubocop/cop/rails/time_zone.rb +2 -1
  32. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +12 -4
  33. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -1
  34. data/lib/rubocop/cop/rails/unknown_env.rb +3 -3
  35. data/lib/rubocop/cop/rails/validation.rb +2 -2
  36. data/lib/rubocop/cop/rails/where_equals.rb +3 -2
  37. data/lib/rubocop/cop/rails/where_exists.rb +9 -8
  38. data/lib/rubocop/cop/rails/where_missing.rb +6 -2
  39. data/lib/rubocop/cop/rails/where_not.rb +8 -6
  40. data/lib/rubocop/rails/schema_loader/schema.rb +3 -2
  41. data/lib/rubocop/rails/schema_loader.rb +5 -15
  42. data/lib/rubocop/rails/version.rb +1 -1
  43. metadata +24 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4d08f111893c16ea5c725b8da3b488a85d193366cdec6c876e780e794d66ba3
4
- data.tar.gz: 40bd526fbf58ea8b3b45ab82ff5b7f809dcf29c7377991023fb30157dc66cc0d
3
+ metadata.gz: ee7d9bdd0fa7838d8bfecece133ccd92cc308603bcdf120c14224c5f2e312344
4
+ data.tar.gz: 7d740b495ffa368d26a73808af9adff990bb9c1d317d905f877b4f3e2025487c
5
5
  SHA512:
6
- metadata.gz: 6dd91e7f4068bba386e8b66ce86ec18961bc6e346d000947220af3fccdaf076907a11d7367786702124370aa070aacadba96bde0c200303ad64eaf1b5de6f8d5
7
- data.tar.gz: 783d1a9013524550b3bbd2271f3d244b13565038b1f0e73b7726565a6ea79e6e409b19f748e043fd7d850c623ea3f56c831f81f7d5bafd2cbd5e08d4181b1172
6
+ metadata.gz: 98172f41e7b1aab55931f351757425815850809edd6fc4f5bc55c59271d9f12459ac51c2002e409534b623f321ab27798c32aaccb2d15d60c7bf309a9c044d58
7
+ data.tar.gz: c78e9a0d9e53e5203a2dd1846a79c3e9c7a16af69e98d94e6b7ae6358ae6a29b71c2ac3f09ddb2a9be06dc64097a736c3379730f50b9309c0e2ae084267aee70
data/README.md CHANGED
@@ -66,17 +66,15 @@ end
66
66
  ## Rails configuration tip
67
67
 
68
68
  If you are using Rails 6.1 or newer, add the following `config.generators.after_generate` setting to
69
- your config/application.rb to apply RuboCop autocorrection to code generated by `bin/rails g`.
69
+ your `config/environments/development.rb` to apply RuboCop autocorrection to code generated by `bin/rails g`.
70
70
 
71
71
  ```ruby
72
- # config/application.rb
73
- module YourCoolApp
74
- class Application < Rails::Application
75
- config.generators.after_generate do |files|
76
- parsable_files = files.filter { |file| file.end_with?('.rb') }
77
- unless parsable_files.empty?
78
- system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true)
79
- end
72
+ # config/environments/development.rb
73
+ Rails.application.configure do
74
+ config.generators.after_generate do |files|
75
+ parsable_files = files.filter { |file| file.end_with?('.rb') }
76
+ unless parsable_files.empty?
77
+ system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true)
80
78
  end
81
79
  end
82
80
  end
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: >-
@@ -445,9 +446,10 @@ Rails/EnvironmentVariableAccess:
445
446
  # TODO: Set to `pending` status in RuboCop Rails 2 series when migration doc will be written.
446
447
  Enabled: false
447
448
  VersionAdded: '2.10'
448
- VersionChanged: '2.11'
449
+ VersionChanged: '2.24'
449
450
  Include:
450
451
  - app/**/*.rb
452
+ - config/initializers/**/*.rb
451
453
  - lib/**/*.rb
452
454
  Exclude:
453
455
  - lib/**/*.rake
@@ -902,7 +904,7 @@ Rails/RequireDependency:
902
904
  VersionAdded: '2.10'
903
905
 
904
906
  Rails/ResponseParsedBody:
905
- Description: Prefer `response.parsed_body` to `JSON.parse(response.body)`.
907
+ Description: Prefer `response.parsed_body` to custom parsing logic for `response.body`.
906
908
  Enabled: pending
907
909
  Safe: false
908
910
  VersionAdded: '2.18'
@@ -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)
@@ -98,8 +103,15 @@ module RuboCop
98
103
  end
99
104
 
100
105
  def in_where?(node)
101
- send_node = node.each_ancestor(:send).first
102
- send_node && WHERE_METHODS.include?(send_node.method_name)
106
+ send_node = node.each_ancestor(:send, :csend).first
107
+ return false unless send_node
108
+
109
+ return true if WHERE_METHODS.include?(send_node.method_name)
110
+
111
+ receiver = send_node.receiver
112
+ return false unless receiver&.send_type?
113
+
114
+ send_node.method?(:not) && WHERE_METHODS.include?(receiver.method_name)
103
115
  end
104
116
  end
105
117
  end
@@ -23,7 +23,7 @@ module RuboCop
23
23
  case database_adapter
24
24
  when 'mysql2', 'trilogy'
25
25
  MYSQL
26
- when 'postgresql'
26
+ when 'postgresql', 'postgis'
27
27
  POSTGRESQL
28
28
  end
29
29
  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
@@ -11,10 +11,10 @@ module RuboCop
11
11
  # `update` but the method name remained same in the method definition.
12
12
  #
13
13
  # @example
14
- # #bad
14
+ # # bad
15
15
  # book.update_attributes!(author: 'Alice')
16
16
  #
17
- # #good
17
+ # # good
18
18
  # book.update!(author: 'Alice')
19
19
  class ActiveRecordAliases < Base
20
20
  extend AutoCorrector
@@ -27,13 +27,13 @@ module RuboCop
27
27
 
28
28
  ALIASES = {
29
29
  starts_with?: {
30
- original: :start_with?, matcher: '(send str :starts_with? _)'
30
+ original: :start_with?, matcher: '(call str :starts_with? _)'
31
31
  },
32
32
  ends_with?: {
33
- original: :end_with?, matcher: '(send str :ends_with? _)'
33
+ original: :end_with?, matcher: '(call str :ends_with? _)'
34
34
  },
35
- append: { original: :<<, matcher: '(send array :append _)' },
36
- prepend: { original: :unshift, matcher: '(send array :prepend _)' }
35
+ append: { original: :<<, matcher: '(call array :append _)' },
36
+ prepend: { original: :unshift, matcher: '(call array :prepend _)' }
37
37
  }.freeze
38
38
 
39
39
  ALIASES.each do |aliased_method, options|
@@ -47,13 +47,14 @@ module RuboCop
47
47
  preferred_method = ALIASES[aliased_method][:original]
48
48
  message = format(MSG, prefer: preferred_method, current: aliased_method)
49
49
 
50
- add_offense(node, message: message) do |corrector|
50
+ add_offense(node.loc.selector.join(node.source_range.end), message: message) do |corrector|
51
51
  next if append(node)
52
52
 
53
53
  corrector.replace(node.loc.selector, preferred_method)
54
54
  end
55
55
  end
56
56
  end
57
+ alias on_csend on_send
57
58
  end
58
59
  end
59
60
  end
@@ -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
@@ -48,7 +48,7 @@ module RuboCop
48
48
  seen_callback_names = {}
49
49
 
50
50
  each_after_commit_callback(class_node) do |node|
51
- callback_name = node.arguments[0].value
51
+ callback_name = node.first_argument.value
52
52
  if seen_callback_names.key?(callback_name)
53
53
  add_offense(node, message: format(MSG, name: callback_name))
54
54
  else
@@ -14,7 +14,7 @@ module RuboCop
14
14
  # automatically detect an adapter from `development` environment
15
15
  # in `config/database.yml` or the environment variable `DATABASE_URL`
16
16
  # when the `Database` option is not set.
17
- # If the adapter is not `mysql2`, `trilogy`, or `postgresql`,
17
+ # If the adapter is not `mysql2`, `trilogy`, `postgresql`, or `postgis`,
18
18
  # this Cop ignores offenses.
19
19
  #
20
20
  # @example
@@ -212,7 +212,7 @@ module RuboCop
212
212
  # @param node [RuboCop::AST::SendNode]
213
213
  def add_offense_for_alter_methods(node)
214
214
  # arguments: [{(sym :table)(str "table")} ...]
215
- table_node = node.arguments[0]
215
+ table_node = node.first_argument
216
216
  return unless table_node.is_a? RuboCop::AST::BasicLiteralNode
217
217
 
218
218
  message = format(MSG_FOR_ALTER_METHODS, table: table_node.value)
@@ -234,10 +234,10 @@ module RuboCop
234
234
  # @param new_node [RuboCop::AST::SendNode]
235
235
  def process(new_node)
236
236
  # arguments: [{(sym :table)(str "table")} ...]
237
- table_node = new_node.arguments[0]
237
+ table_node = new_node.first_argument
238
238
  if table_node.is_a? RuboCop::AST::BasicLiteralNode
239
239
  flush unless @nodes.all? do |node|
240
- node.arguments[0].value.to_s == table_node.value.to_s
240
+ node.first_argument.value.to_s == table_node.value.to_s
241
241
  end
242
242
  @nodes << new_node
243
243
  else
@@ -7,7 +7,7 @@ module RuboCop
7
7
  #
8
8
  # NOTE: Allow `tag` when the first argument is a variable because
9
9
  # `tag(name)` is simpler rather than `tag.public_send(name)`.
10
- # And this cop will be renamed to something like `LegacyTag` in the future. (e.g. RuboCop Rails 2.0)
10
+ # And this cop will be renamed to something like `LegacyTag` in the future. (e.g. RuboCop Rails 3.0)
11
11
  #
12
12
  # @example
13
13
  # # bad
@@ -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
@@ -428,7 +427,7 @@ module RuboCop
428
427
  when :rename_column
429
428
  node.arguments[2]
430
429
  when *COLUMN_TYPE_METHOD_NAMES
431
- node.arguments[0]
430
+ node.first_argument
432
431
  end
433
432
  end
434
433
 
@@ -14,10 +14,10 @@ module RuboCop
14
14
  # when no output would be produced anyway.
15
15
  #
16
16
  # @example
17
- # #bad
17
+ # # bad
18
18
  # Rails.logger.debug "The time is #{Time.zone.now}."
19
19
  #
20
- # #good
20
+ # # good
21
21
  # Rails.logger.debug { "The time is #{Time.zone.now}." }
22
22
  #
23
23
  class EagerEvaluationLogMessage < Base
@@ -51,7 +51,7 @@ module RuboCop
51
51
  return if allow?(begin_node, end_node)
52
52
 
53
53
  preferred_method = preferred_method(begin_node)
54
- if begin_node.method?(:beginning_of_week) && begin_node.arguments.one?
54
+ if begin_node.method?(:beginning_of_week) && begin_node.arguments.one? && end_node.arguments.one?
55
55
  return unless same_argument?(begin_node, end_node)
56
56
 
57
57
  preferred_method << "(#{begin_node.first_argument.source})"
@@ -163,9 +163,9 @@ module RuboCop
163
163
 
164
164
  def autocorrect_extension_after_rails_root_join_in_dstr(corrector, node, rails_root_index, extension_node)
165
165
  rails_root_node = node.children[rails_root_index].children.first
166
- return unless rails_root_node.arguments.last.str_type?
166
+ return unless rails_root_node.last_argument.str_type?
167
167
 
168
- corrector.insert_before(rails_root_node.arguments.last.location.end, extension_node.source)
168
+ corrector.insert_before(rails_root_node.last_argument.location.end, extension_node.source)
169
169
  corrector.remove(extension_node)
170
170
  end
171
171
 
@@ -174,7 +174,7 @@ module RuboCop
174
174
  corrector.remove(
175
175
  range_with_surrounding_space(
176
176
  range_with_surrounding_comma(
177
- node.arguments.first.source_range,
177
+ node.first_argument.source_range,
178
178
  :right
179
179
  ),
180
180
  side: :right
@@ -187,7 +187,7 @@ module RuboCop
187
187
  end
188
188
 
189
189
  def autocorrect_rails_root_join_with_string_arguments(corrector, node)
190
- corrector.replace(node.arguments.first, %("#{node.arguments.map(&:value).join('/')}"))
190
+ corrector.replace(node.first_argument, %("#{node.arguments.map(&:value).join('/')}"))
191
191
  node.arguments[1..].each do |argument|
192
192
  corrector.remove(
193
193
  range_with_surrounding_comma(
@@ -221,7 +221,7 @@ module RuboCop
221
221
  end
222
222
 
223
223
  def append_argument(corrector, node, argument_source)
224
- corrector.insert_after(node.arguments.last, %(, "#{argument_source}"))
224
+ corrector.insert_after(node.last_argument, %(, "#{argument_source}"))
225
225
  end
226
226
 
227
227
  def replace_with_rails_root_join(corrector, node, argument_source)
@@ -28,7 +28,7 @@ module RuboCop
28
28
  include RangeHelp
29
29
  extend AutoCorrector
30
30
 
31
- MSG = 'Use `find_by` instead of `where.%<method>s`.'
31
+ MSG = 'Use `find_by` instead of `where%<dot>s%<method>s`.'
32
32
  RESTRICT_ON_SEND = %i[first take].freeze
33
33
 
34
34
  def on_send(node)
@@ -37,7 +37,7 @@ module RuboCop
37
37
 
38
38
  range = offense_range(node)
39
39
 
40
- add_offense(range, message: format(MSG, method: node.method_name)) do |corrector|
40
+ add_offense(range, message: format(MSG, dot: node.loc.dot.source, method: node.method_name)) do |corrector|
41
41
  autocorrect(corrector, node)
42
42
  end
43
43
  end
@@ -59,7 +59,7 @@ module RuboCop
59
59
  return if node.method?(:first)
60
60
 
61
61
  where_loc = node.receiver.loc.selector
62
- first_loc = range_between(node.loc.dot.begin_pos, node.loc.selector.end_pos)
62
+ first_loc = range_between(node.receiver.source_range.end_pos, node.loc.selector.end_pos)
63
63
 
64
64
  corrector.replace(where_loc, 'find_by')
65
65
  corrector.replace(first_loc, '')
@@ -24,40 +24,39 @@ module RuboCop
24
24
  RESTRICT_ON_SEND = %i[take! find_by_id! find_by!].freeze
25
25
 
26
26
  def_node_matcher :where_take?, <<~PATTERN
27
- (send
28
- $(send _ :where
27
+ (call
28
+ $(call _ :where
29
29
  (hash
30
30
  (pair (sym :id) $_))) :take!)
31
31
  PATTERN
32
32
 
33
33
  def_node_matcher :find_by?, <<~PATTERN
34
34
  {
35
- (send _ :find_by_id! $_)
36
- (send _ :find_by! (hash (pair (sym :id) $_)))
35
+ (call _ :find_by_id! $_)
36
+ (call _ :find_by! (hash (pair (sym :id) $_)))
37
37
  }
38
38
  PATTERN
39
39
 
40
40
  def on_send(node)
41
41
  where_take?(node) do |where, id_value|
42
42
  range = where_take_offense_range(node, where)
43
- bad_method = build_where_take_bad_method(id_value)
44
43
 
45
- register_offense(range, id_value, bad_method)
44
+ register_offense(range, id_value)
46
45
  end
47
46
 
48
47
  find_by?(node) do |id_value|
49
48
  range = find_by_offense_range(node)
50
- bad_method = build_find_by_bad_method(node, id_value)
51
49
 
52
- register_offense(range, id_value, bad_method)
50
+ register_offense(range, id_value)
53
51
  end
54
52
  end
53
+ alias on_csend on_send
55
54
 
56
55
  private
57
56
 
58
- def register_offense(range, id_value, bad_method)
57
+ def register_offense(range, id_value)
59
58
  good_method = build_good_method(id_value)
60
- message = format(MSG, good_method: good_method, bad_method: bad_method)
59
+ message = format(MSG, good_method: good_method, bad_method: range.source)
61
60
 
62
61
  add_offense(range, message: message) do |corrector|
63
62
  corrector.replace(range, good_method)
@@ -75,19 +74,6 @@ module RuboCop
75
74
  def build_good_method(id_value)
76
75
  "find(#{id_value.source})"
77
76
  end
78
-
79
- def build_where_take_bad_method(id_value)
80
- "where(id: #{id_value.source}).take!"
81
- end
82
-
83
- def build_find_by_bad_method(node, id_value)
84
- case node.method_name
85
- when :find_by_id!
86
- "find_by_id!(#{id_value.source})"
87
- when :find_by!
88
- "find_by!(id: #{id_value.source})"
89
- end
90
- end
91
77
  end
92
78
  end
93
79
  end
@@ -33,6 +33,7 @@ module RuboCop
33
33
 
34
34
  add_offense(node.loc.selector)
35
35
  end
36
+ alias on_csend on_send
36
37
  end
37
38
  end
38
39
  end
@@ -222,7 +222,7 @@ module RuboCop
222
222
 
223
223
  def with_options_arguments(recv, node)
224
224
  blocks = node.each_ancestor(:block).select do |block|
225
- block.send_node.command?(:with_options) && same_context_in_with_options?(block.arguments.first, recv)
225
+ block.send_node.command?(:with_options) && same_context_in_with_options?(block.first_argument, recv)
226
226
  end
227
227
  blocks.flat_map { |n| n.send_node.arguments }
228
228
  end
@@ -28,13 +28,13 @@ module RuboCop
28
28
  extend AutoCorrector
29
29
  extend TargetRailsVersion
30
30
 
31
- MSG = 'Prefer `pick(%<args>s)` over `pluck(%<args>s).first`.'
31
+ MSG = 'Prefer `pick(%<args>s)` over `%<current>s`.'
32
32
  RESTRICT_ON_SEND = %i[first].freeze
33
33
 
34
34
  minimum_target_rails_version 6.0
35
35
 
36
36
  def_node_matcher :pick_candidate?, <<~PATTERN
37
- (send (send _ :pluck ...) :first)
37
+ (call (call _ :pluck ...) :first)
38
38
  PATTERN
39
39
 
40
40
  def on_send(node)
@@ -44,7 +44,7 @@ module RuboCop
44
44
  node_selector = node.loc.selector
45
45
  range = receiver_selector.join(node_selector)
46
46
 
47
- add_offense(range, message: message(receiver)) do |corrector|
47
+ add_offense(range, message: message(receiver, range)) do |corrector|
48
48
  first_range = receiver.source_range.end.join(node_selector)
49
49
 
50
50
  corrector.remove(first_range)
@@ -52,11 +52,12 @@ module RuboCop
52
52
  end
53
53
  end
54
54
  end
55
+ alias on_csend on_send
55
56
 
56
57
  private
57
58
 
58
- def message(receiver)
59
- format(MSG, args: receiver.arguments.map(&:source).join(', '))
59
+ def message(receiver, current)
60
+ format(MSG, args: receiver.arguments.map(&:source).join(', '), current: current.source)
60
61
  end
61
62
  end
62
63
  end
@@ -38,7 +38,7 @@ module RuboCop
38
38
  minimum_target_rails_version 5.0
39
39
 
40
40
  def_node_matcher :pluck_candidate?, <<~PATTERN
41
- ({block numblock} (send _ {:map :collect}) $_argument (send lvar :[] $_key))
41
+ ({block numblock} (call _ {:map :collect}) $_argument (send lvar :[] $_key))
42
42
  PATTERN
43
43
 
44
44
  def on_block(node)
@@ -34,7 +34,7 @@ module RuboCop
34
34
  RESTRICT_ON_SEND = %i[pluck].freeze
35
35
 
36
36
  def_node_matcher :pluck_id_call?, <<~PATTERN
37
- (send _ :pluck {(sym :id) (send nil? :primary_key)})
37
+ (call _ :pluck {(sym :id) (send nil? :primary_key)})
38
38
  PATTERN
39
39
 
40
40
  def on_send(node)
@@ -47,6 +47,7 @@ module RuboCop
47
47
  corrector.replace(offense_range(node), 'ids')
48
48
  end
49
49
  end
50
+ alias on_csend on_send
50
51
 
51
52
  private
52
53
 
@@ -22,10 +22,13 @@ module RuboCop
22
22
  # @example
23
23
  # # bad
24
24
  # Post.where(user_id: User.active.pluck(:id))
25
+ # Post.where(user_id: User.active.ids)
26
+ # Post.where.not(user_id: User.active.pluck(:id))
25
27
  #
26
28
  # # good
27
29
  # Post.where(user_id: User.active.select(:id))
28
30
  # Post.where(user_id: active_users.select(:id))
31
+ # Post.where.not(user_id: active_users.select(:id))
29
32
  #
30
33
  # @example EnforcedStyle: conservative (default)
31
34
  # # good
@@ -40,8 +43,9 @@ module RuboCop
40
43
  include ConfigurableEnforcedStyle
41
44
  extend AutoCorrector
42
45
 
43
- MSG = 'Use `select` instead of `pluck` within `where` query method.'
44
- RESTRICT_ON_SEND = %i[pluck].freeze
46
+ MSG_SELECT = 'Use `select` instead of `pluck` within `where` query method.'
47
+ MSG_IDS = 'Use `select(:id)` instead of `ids` within `where` query method.'
48
+ RESTRICT_ON_SEND = %i[pluck ids].freeze
45
49
 
46
50
  def on_send(node)
47
51
  return unless in_where?(node)
@@ -49,17 +53,26 @@ module RuboCop
49
53
 
50
54
  range = node.loc.selector
51
55
 
52
- add_offense(range) do |corrector|
53
- corrector.replace(range, 'select')
56
+ if node.method?(:ids)
57
+ replacement = 'select(:id)'
58
+ message = MSG_IDS
59
+ else
60
+ replacement = 'select'
61
+ message = MSG_SELECT
62
+ end
63
+
64
+ add_offense(range, message: message) do |corrector|
65
+ corrector.replace(range, replacement)
54
66
  end
55
67
  end
68
+ alias on_csend on_send
56
69
 
57
70
  private
58
71
 
59
72
  def root_receiver(node)
60
73
  receiver = node.receiver
61
74
 
62
- if receiver&.send_type?
75
+ if receiver&.call_type?
63
76
  root_receiver(receiver)
64
77
  else
65
78
  receiver
@@ -72,7 +72,7 @@ module RuboCop
72
72
  end
73
73
 
74
74
  def task_name(node)
75
- first_arg = node.arguments[0]
75
+ first_arg = node.first_argument
76
76
  case first_arg&.type
77
77
  when :sym, :str
78
78
  first_arg.value.to_sym
@@ -97,7 +97,7 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def with_dependencies?(node)
100
- first_arg = node.arguments[0]
100
+ first_arg = node.first_argument
101
101
  return false unless first_arg
102
102
 
103
103
  if first_arg.hash_type?
@@ -3,8 +3,43 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
+ # TODO: In the future, please support only RuboCop 1.52+ and use `RuboCop::Cop::AllowedReceivers`:
7
+ # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cop/mixin/allowed_receivers.rb
8
+ # At that time, this duplicated module implementation can be removed.
9
+ module AllowedReceivers
10
+ def allowed_receiver?(receiver)
11
+ receiver_name = receiver_name(receiver)
12
+
13
+ allowed_receivers.include?(receiver_name)
14
+ end
15
+
16
+ def receiver_name(receiver)
17
+ return receiver_name(receiver.receiver) if receiver.receiver && !receiver.receiver.const_type?
18
+
19
+ if receiver.send_type?
20
+ if receiver.receiver
21
+ "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
22
+ else
23
+ receiver.method_name.to_s
24
+ end
25
+ else
26
+ receiver.source
27
+ end
28
+ end
29
+
30
+ def allowed_receivers
31
+ cop_config.fetch('AllowedReceivers', [])
32
+ end
33
+ end
34
+
6
35
  # Detect redundant `all` used as a receiver for Active Record query methods.
7
36
  #
37
+ # For the methods `delete_all` and `destroy_all`, this cop will only check cases where the receiver is a model.
38
+ # It will ignore cases where the receiver is an association (e.g., `user.articles.all.delete_all`).
39
+ # This is because omitting `all` from an association changes the methods
40
+ # from `ActiveRecord::Relation` to `ActiveRecord::Associations::CollectionProxy`,
41
+ # which can affect their behavior.
42
+ #
8
43
  # @safety
9
44
  # This cop is unsafe for autocorrection if the receiver for `all` is not an Active Record object.
10
45
  #
@@ -144,13 +179,15 @@ module RuboCop
144
179
  ].to_set.freeze
145
180
 
146
181
  POSSIBLE_ENUMERABLE_BLOCK_METHODS = %i[any? count find none? one? select sum].freeze
182
+ SENSITIVE_METHODS_ON_ASSOCIATION = %i[delete_all destroy_all].freeze
147
183
 
148
184
  def_node_matcher :followed_by_query_method?, <<~PATTERN
149
185
  (send (send _ :all) QUERYING_METHODS ...)
150
186
  PATTERN
151
187
 
152
188
  def on_send(node)
153
- return if !followed_by_query_method?(node.parent) || possible_enumerable_block_method?(node)
189
+ return unless followed_by_query_method?(node.parent)
190
+ return if possible_enumerable_block_method?(node) || sensitive_association_method?(node)
154
191
  return if node.receiver ? allowed_receiver?(node.receiver) : !inherit_active_record_base?(node)
155
192
 
156
193
  range_of_all_method = offense_range(node)
@@ -169,37 +206,12 @@ module RuboCop
169
206
  parent.parent&.block_type? || parent.parent&.numblock_type? || parent.first_argument&.block_pass_type?
170
207
  end
171
208
 
172
- def offense_range(node)
173
- range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
209
+ def sensitive_association_method?(node)
210
+ !node.receiver&.const_type? && SENSITIVE_METHODS_ON_ASSOCIATION.include?(node.parent.method_name)
174
211
  end
175
212
 
176
- # TODO: In the future, please support only RuboCop 1.52+ and use `RuboCop::Cop::AllowedReceivers`:
177
- # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cop/mixin/allowed_receivers.rb
178
- # At that time, this duplicated module implementation can be removed.
179
- module AllowedReceivers
180
- def allowed_receiver?(receiver)
181
- receiver_name = receiver_name(receiver)
182
-
183
- allowed_receivers.include?(receiver_name)
184
- end
185
-
186
- def receiver_name(receiver)
187
- return receiver_name(receiver.receiver) if receiver.receiver && !receiver.receiver.const_type?
188
-
189
- if receiver.send_type?
190
- if receiver.receiver
191
- "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
192
- else
193
- receiver.method_name.to_s
194
- end
195
- else
196
- receiver.source
197
- end
198
- end
199
-
200
- def allowed_receivers
201
- cop_config.fetch('AllowedReceivers', [])
202
- end
213
+ def offense_range(node)
214
+ range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
203
215
  end
204
216
  end
205
217
  end
@@ -100,7 +100,7 @@ module RuboCop
100
100
  else
101
101
  return false if node.arguments.empty?
102
102
 
103
- arg = node.arguments.first
103
+ arg = node.first_argument
104
104
  ->(n) { same_value?(arg, n.receiver) }
105
105
  end
106
106
 
@@ -3,25 +3,30 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # Prefer `response.parsed_body` to `JSON.parse(response.body)`.
6
+ # Prefer `response.parsed_body` to custom parsing logic for `response.body`.
7
7
  #
8
8
  # @safety
9
- # This cop is unsafe because Content-Type may not be `application/json`. For example, the proprietary
10
- # Content-Type provided by corporate entities such as `application/vnd.github+json` is not supported at
11
- # `response.parsed_body` by default, so you still have to use `JSON.parse(response.body)` there.
9
+ # This cop is unsafe because Content-Type may not be `application/json` or `text/html`.
10
+ # For example, the proprietary Content-Type provided by corporate entities such as
11
+ # `application/vnd.github+json` is not supported at `response.parsed_body` by default,
12
+ # so you still have to use `JSON.parse(response.body)` there.
12
13
  #
13
14
  # @example
14
15
  # # bad
15
16
  # JSON.parse(response.body)
16
17
  #
18
+ # # bad
19
+ # Nokogiri::HTML.parse(response.body)
20
+ #
21
+ # # bad
22
+ # Nokogiri::HTML5.parse(response.body)
23
+ #
17
24
  # # good
18
25
  # response.parsed_body
19
26
  class ResponseParsedBody < Base
20
27
  extend AutoCorrector
21
28
  extend TargetRailsVersion
22
29
 
23
- MSG = 'Prefer `response.parsed_body` to `JSON.parse(response.body)`.'
24
-
25
30
  RESTRICT_ON_SEND = %i[parse].freeze
26
31
 
27
32
  minimum_target_rails_version 5.0
@@ -38,12 +43,27 @@ module RuboCop
38
43
  )
39
44
  PATTERN
40
45
 
46
+ # @!method nokogiri_html_parse_response_body(node)
47
+ def_node_matcher :nokogiri_html_parse_response_body, <<~PATTERN
48
+ (send
49
+ (const
50
+ (const {nil? cbase} :Nokogiri)
51
+ ${:HTML :HTML5}
52
+ )
53
+ :parse
54
+ (send
55
+ (send nil? :response)
56
+ :body
57
+ )
58
+ )
59
+ PATTERN
60
+
41
61
  def on_send(node)
42
- return unless json_parse_response_body?(node)
62
+ check_json_parse_response_body(node)
43
63
 
44
- add_offense(node) do |corrector|
45
- autocorrect(corrector, node)
46
- end
64
+ return unless target_rails_version >= 7.1
65
+
66
+ check_nokogiri_html_parse_response_body(node)
47
67
  end
48
68
 
49
69
  private
@@ -51,6 +71,28 @@ module RuboCop
51
71
  def autocorrect(corrector, node)
52
72
  corrector.replace(node, 'response.parsed_body')
53
73
  end
74
+
75
+ def check_json_parse_response_body(node)
76
+ return unless json_parse_response_body?(node)
77
+
78
+ add_offense(
79
+ node,
80
+ message: 'Prefer `response.parsed_body` to `JSON.parse(response.body)`.'
81
+ ) do |corrector|
82
+ autocorrect(corrector, node)
83
+ end
84
+ end
85
+
86
+ def check_nokogiri_html_parse_response_body(node)
87
+ return unless (const = nokogiri_html_parse_response_body(node))
88
+
89
+ add_offense(
90
+ node,
91
+ message: "Prefer `response.parsed_body` to `Nokogiri::#{const}.parse(response.body)`."
92
+ ) do |corrector|
93
+ autocorrect(corrector, node)
94
+ end
95
+ end
54
96
  end
55
97
  end
56
98
  end
@@ -17,7 +17,7 @@ module RuboCop
17
17
  # # good
18
18
  # def change
19
19
  # change_table :users do |t|
20
- # t.remove :name, :string
20
+ # t.remove :name, type: :string
21
21
  # end
22
22
  # end
23
23
  #
@@ -290,10 +290,10 @@ module RuboCop
290
290
  when :change
291
291
  false
292
292
  when :remove
293
- target_rails_version >= 6.1 && all_hash_key?(node.arguments.last, :type)
293
+ target_rails_version >= 6.1 && all_hash_key?(node.last_argument, :type)
294
294
  when :change_default, :change_column_default, :change_table_comment,
295
295
  :change_column_comment
296
- all_hash_key?(node.arguments.last, :from, :to)
296
+ all_hash_key?(node.last_argument, :from, :to)
297
297
  else
298
298
  true
299
299
  end
@@ -196,6 +196,8 @@ module RuboCop
196
196
  end
197
197
 
198
198
  def call_to_persisted?(node)
199
+ node = node.parent.condition if node.parenthesized_call? && node.parent.if_type?
200
+
199
201
  node.send_type? && node.method?(:persisted?)
200
202
  end
201
203
 
@@ -336,10 +338,10 @@ module RuboCop
336
338
 
337
339
  # Check argument signature as no arguments or one hash
338
340
  def expected_signature?(node)
339
- !node.arguments? ||
340
- (node.arguments.one? &&
341
- node.method_name != :destroy &&
342
- (node.first_argument.hash_type? || !node.first_argument.literal?))
341
+ return true unless node.arguments?
342
+ return false if !node.arguments.one? || node.method?(:destroy)
343
+
344
+ node.first_argument.hash_type? || !node.first_argument.literal?
343
345
  end
344
346
  end
345
347
  end
@@ -69,9 +69,10 @@ module RuboCop
69
69
  return if !node.receiver&.str_type? || !node.method?(:to_time)
70
70
 
71
71
  add_offense(node.loc.selector, message: MSG_STRING_TO_TIME) do |corrector|
72
- corrector.replace(node, "Time.zone.parse(#{node.receiver.source})")
72
+ corrector.replace(node, "Time.zone.parse(#{node.receiver.source})") unless node.csend_type?
73
73
  end
74
74
  end
75
+ alias on_csend on_send
75
76
 
76
77
  private
77
78
 
@@ -68,15 +68,23 @@ module RuboCop
68
68
  return unless uniq
69
69
 
70
70
  add_offense(node.loc.selector) do |corrector|
71
- method = node.method_name
72
-
73
- corrector.remove(dot_method_with_whitespace(method, node))
74
- corrector.insert_before(node.receiver.loc.dot.begin, '.distinct')
71
+ autocorrect(corrector, node)
75
72
  end
76
73
  end
77
74
 
78
75
  private
79
76
 
77
+ def autocorrect(corrector, node)
78
+ method = node.method_name
79
+
80
+ corrector.remove(dot_method_with_whitespace(method, node))
81
+ if (dot = node.receiver.loc.dot)
82
+ corrector.insert_before(dot.begin, '.distinct')
83
+ else
84
+ corrector.insert_before(node.receiver, 'distinct.')
85
+ end
86
+ end
87
+
80
88
  def dot_method_with_whitespace(method, node)
81
89
  range_between(dot_method_begin_pos(method, node), node.loc.selector.end_pos)
82
90
  end
@@ -124,7 +124,7 @@ module RuboCop
124
124
  end
125
125
 
126
126
  def uniqueness_part(node)
127
- pairs = node.arguments.last
127
+ pairs = node.last_argument
128
128
  return unless pairs&.hash_type?
129
129
 
130
130
  pairs.each_pair.find do |pair|
@@ -87,9 +87,9 @@ module RuboCop
87
87
 
88
88
  def environments
89
89
  @environments ||= begin
90
- e = cop_config['Environments']
91
- e += ['local'] if target_rails_version >= 7.1
92
- e
90
+ environments = cop_config['Environments'] || []
91
+ environments << 'local' if target_rails_version >= 7.1
92
+ environments
93
93
  end
94
94
  end
95
95
  end
@@ -51,7 +51,7 @@ module RuboCop
51
51
  uniqueness
52
52
  ].freeze
53
53
 
54
- RESTRICT_ON_SEND = TYPES.map { |p| "validates_#{p}_of".to_sym }.freeze
54
+ RESTRICT_ON_SEND = TYPES.map { |p| :"validates_#{p}_of" }.freeze
55
55
  ALLOWLIST = TYPES.map { |p| "validates :column, #{p}: value" }.freeze
56
56
 
57
57
  def on_send(node)
@@ -60,7 +60,7 @@ module RuboCop
60
60
  range = node.loc.selector
61
61
 
62
62
  add_offense(range, message: message(node)) do |corrector|
63
- last_argument = node.arguments.last
63
+ last_argument = node.last_argument
64
64
  return if !last_argument.literal? && !last_argument.splat_type? && !frozen_array_argument?(last_argument)
65
65
 
66
66
  corrector.replace(range, 'validates')
@@ -33,8 +33,8 @@ module RuboCop
33
33
 
34
34
  def_node_matcher :where_method_call?, <<~PATTERN
35
35
  {
36
- (send _ :where (array $str_type? $_ ?))
37
- (send _ :where $str_type? $_ ?)
36
+ (call _ :where (array $str_type? $_ ?))
37
+ (call _ :where $str_type? $_ ?)
38
38
  }
39
39
  PATTERN
40
40
 
@@ -55,6 +55,7 @@ module RuboCop
55
55
  end
56
56
  end
57
57
  end
58
+ alias on_csend on_send
58
59
 
59
60
  EQ_ANONYMOUS_RE = /\A([\w.]+)\s+=\s+\?\z/.freeze # column = ?
60
61
  IN_ANONYMOUS_RE = /\A([\w.]+)\s+IN\s+\(\?\)\z/i.freeze # column IN (?)
@@ -55,11 +55,11 @@ module RuboCop
55
55
  RESTRICT_ON_SEND = %i[exists?].freeze
56
56
 
57
57
  def_node_matcher :where_exists_call?, <<~PATTERN
58
- (send (send _ :where $...) :exists?)
58
+ (call (call _ :where $...) :exists?)
59
59
  PATTERN
60
60
 
61
61
  def_node_matcher :exists_with_args?, <<~PATTERN
62
- (send _ :exists? $...)
62
+ (call _ :exists? $...)
63
63
  PATTERN
64
64
 
65
65
  def on_send(node)
@@ -67,7 +67,7 @@ module RuboCop
67
67
  return unless convertable_args?(args)
68
68
 
69
69
  range = correction_range(node)
70
- good_method = build_good_method(args)
70
+ good_method = build_good_method(args, dot: node.loc.dot)
71
71
  message = format(MSG, good_method: good_method, bad_method: range.source)
72
72
 
73
73
  add_offense(range, message: message) do |corrector|
@@ -75,6 +75,7 @@ module RuboCop
75
75
  end
76
76
  end
77
77
  end
78
+ alias on_csend on_send
78
79
 
79
80
  private
80
81
 
@@ -108,11 +109,11 @@ module RuboCop
108
109
  end
109
110
  end
110
111
 
111
- def build_good_method(args)
112
+ def build_good_method(args, dot:)
112
113
  if exists_style?
113
114
  build_good_method_exists(args)
114
115
  elsif where_style?
115
- build_good_method_where(args)
116
+ build_good_method_where(args, dot&.source || '.')
116
117
  end
117
118
  end
118
119
 
@@ -124,11 +125,11 @@ module RuboCop
124
125
  end
125
126
  end
126
127
 
127
- def build_good_method_where(args)
128
+ def build_good_method_where(args, dot_source)
128
129
  if args.size > 1
129
- "where(#{args.map(&:source).join(', ')}).exists?"
130
+ "where(#{args.map(&:source).join(', ')})#{dot_source}exists?"
130
131
  else
131
- "where(#{args[0].source}).exists?"
132
+ "where(#{args[0].source})#{dot_source}exists?"
132
133
  end
133
134
  end
134
135
  end
@@ -36,7 +36,7 @@ module RuboCop
36
36
  PATTERN
37
37
 
38
38
  def on_send(node)
39
- return unless node.first_argument.sym_type?
39
+ return unless node.first_argument&.sym_type?
40
40
 
41
41
  root_receiver = root_receiver(node)
42
42
  where_node_and_argument(root_receiver) do |where_node, where_argument|
@@ -89,16 +89,20 @@ module RuboCop
89
89
  end
90
90
  end
91
91
 
92
+ # rubocop:disable Metrics/AbcSize
92
93
  def remove_where_method(corrector, node, where_node)
93
94
  range = range_between(where_node.loc.selector.begin_pos, where_node.loc.end.end_pos)
94
95
  if node.multiline? && !same_line?(node, where_node)
95
96
  range = range_by_whole_lines(range, include_final_newline: true)
96
- else
97
+ elsif where_node.receiver
97
98
  corrector.remove(where_node.loc.dot)
99
+ else
100
+ corrector.remove(node.loc.dot)
98
101
  end
99
102
 
100
103
  corrector.remove(range)
101
104
  end
105
+ # rubocop:enable Metrics/AbcSize
102
106
 
103
107
  def same_line?(left_joins_node, where_node)
104
108
  left_joins_node.loc.selector.line == where_node.loc.selector.line
@@ -32,8 +32,8 @@ module RuboCop
32
32
 
33
33
  def_node_matcher :where_method_call?, <<~PATTERN
34
34
  {
35
- (send _ :where (array $str_type? $_ ?))
36
- (send _ :where $str_type? $_ ?)
35
+ (call _ :where (array $str_type? $_ ?))
36
+ (call _ :where $str_type? $_ ?)
37
37
  }
38
38
  PATTERN
39
39
 
@@ -46,7 +46,7 @@ module RuboCop
46
46
  column_and_value = extract_column_and_value(template_node, value_node)
47
47
  return unless column_and_value
48
48
 
49
- good_method = build_good_method(*column_and_value)
49
+ good_method = build_good_method(node.loc.dot&.source, *column_and_value)
50
50
  message = format(MSG, good_method: good_method)
51
51
 
52
52
  add_offense(range, message: message) do |corrector|
@@ -54,6 +54,7 @@ module RuboCop
54
54
  end
55
55
  end
56
56
  end
57
+ alias on_csend on_send
57
58
 
58
59
  NOT_EQ_ANONYMOUS_RE = /\A([\w.]+)\s+(?:!=|<>)\s+\?\z/.freeze # column != ?, column <> ?
59
60
  NOT_IN_ANONYMOUS_RE = /\A([\w.]+)\s+NOT\s+IN\s+\(\?\)\z/i.freeze # column NOT IN (?)
@@ -86,13 +87,14 @@ module RuboCop
86
87
  [Regexp.last_match(1), value]
87
88
  end
88
89
 
89
- def build_good_method(column, value)
90
+ def build_good_method(dot, column, value)
91
+ dot ||= '.'
90
92
  if column.include?('.')
91
93
  table, column = column.split('.')
92
94
 
93
- "where.not(#{table}: { #{column}: #{value} })"
95
+ "where#{dot}not(#{table}: { #{column}: #{value} })"
94
96
  else
95
- "where.not(#{column}: #{value})"
97
+ "where#{dot}not(#{column}: #{value})"
96
98
  end
97
99
  end
98
100
  end
@@ -30,6 +30,7 @@ module RuboCop
30
30
 
31
31
  def build!(ast)
32
32
  raise "Unexpected type: #{ast.type}" unless ast.block_type?
33
+ return unless ast.body
33
34
 
34
35
  each_table(ast) do |table_def|
35
36
  next unless table_def.method?(:create_table)
@@ -127,7 +128,7 @@ module RuboCop
127
128
  private
128
129
 
129
130
  def analyze_keywords!(node)
130
- pairs = node.arguments.last
131
+ pairs = node.last_argument
131
132
  return unless pairs.hash_type?
132
133
 
133
134
  pairs.each_pair do |k, v|
@@ -158,7 +159,7 @@ module RuboCop
158
159
  end
159
160
 
160
161
  def analyze_keywords!(node)
161
- pairs = node.arguments.last
162
+ pairs = node.last_argument
162
163
  return unless pairs.hash_type?
163
164
 
164
165
  pairs.each_pair do |k, v|
@@ -12,10 +12,10 @@ module RuboCop
12
12
  # So a cop that uses the loader should handle `nil` properly.
13
13
  #
14
14
  # @return [Schema, nil]
15
- def load(target_ruby_version)
15
+ def load(target_ruby_version, parser_engine)
16
16
  return @load if defined?(@load)
17
17
 
18
- @load = load!(target_ruby_version)
18
+ @load = load!(target_ruby_version, parser_engine)
19
19
  end
20
20
 
21
21
  def reset!
@@ -38,23 +38,13 @@ module RuboCop
38
38
 
39
39
  private
40
40
 
41
- def load!(target_ruby_version)
41
+ def load!(target_ruby_version, parser_engine)
42
42
  path = db_schema_path
43
43
  return unless path
44
44
 
45
- ast = parse(path, target_ruby_version)
46
- Schema.new(ast) if ast
47
- end
48
-
49
- def parse(path, target_ruby_version)
50
- klass_name = :"Ruby#{target_ruby_version.to_s.sub('.', '')}"
51
- klass = ::Parser.const_get(klass_name)
52
- parser = klass.new(RuboCop::AST::Builder.new)
45
+ ast = RuboCop::ProcessedSource.new(File.read(path), target_ruby_version, path, parser_engine: parser_engine).ast
53
46
 
54
- buffer = Parser::Source::Buffer.new(path, 1)
55
- buffer.source = path.read
56
-
57
- parser.parse(buffer)
47
+ Schema.new(ast) if ast
58
48
  end
59
49
  end
60
50
  end
@@ -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.22.1'
7
+ STRING = '2.24.1'
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.22.1
4
+ version: 2.24.1
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: 2023-10-28 00:00:00.000000000 Z
13
+ date: 2024-03-25 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -60,6 +60,26 @@ dependencies:
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
62
  version: '2.0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rubocop-ast
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 1.31.1
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '2.0'
73
+ type: :runtime
74
+ prerelease: false
75
+ version_requirements: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 1.31.1
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
63
83
  description: |
64
84
  Automatic Rails code style checking tool.
65
85
  A RuboCop extension focused on enforcing Rails best practices and coding conventions.
@@ -225,7 +245,7 @@ metadata:
225
245
  homepage_uri: https://docs.rubocop.org/rubocop-rails/
226
246
  changelog_uri: https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md
227
247
  source_code_uri: https://github.com/rubocop/rubocop-rails/
228
- documentation_uri: https://docs.rubocop.org/rubocop-rails/2.22/
248
+ documentation_uri: https://docs.rubocop.org/rubocop-rails/2.24/
229
249
  bug_tracker_uri: https://github.com/rubocop/rubocop-rails/issues
230
250
  rubygems_mfa_required: 'true'
231
251
  post_install_message:
@@ -243,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
263
  - !ruby/object:Gem::Version
244
264
  version: '0'
245
265
  requirements: []
246
- rubygems_version: 3.5.0.dev
266
+ rubygems_version: 3.3.26
247
267
  signing_key:
248
268
  specification_version: 4
249
269
  summary: Automatic Rails code style checking tool.