rubocop-rails 2.22.1 → 2.24.1

Sign up to get free protection for your applications and to get access to all the features.
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.