rubocop-rails 2.15.2 → 2.17.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +120 -0
  3. data/config/obsoletion.yml +10 -0
  4. data/lib/rubocop/cop/mixin/active_record_helper.rb +1 -4
  5. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
  6. data/lib/rubocop/cop/mixin/index_method.rb +5 -15
  7. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +99 -0
  8. data/lib/rubocop/cop/rails/action_controller_test_case.rb +1 -1
  9. data/lib/rubocop/cop/rails/action_filter.rb +1 -1
  10. data/lib/rubocop/cop/rails/action_order.rb +81 -0
  11. data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
  12. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  13. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  14. data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
  15. data/lib/rubocop/cop/rails/blank.rb +1 -2
  16. data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
  17. data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
  18. data/lib/rubocop/cop/rails/content_tag.rb +3 -4
  19. data/lib/rubocop/cop/rails/date.rb +4 -9
  20. data/lib/rubocop/cop/rails/delegate.rb +2 -5
  21. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
  22. data/lib/rubocop/cop/rails/dot_separated_keys.rb +1 -1
  23. data/lib/rubocop/cop/rails/dynamic_find_by.rb +8 -6
  24. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +4 -0
  25. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
  26. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
  27. data/lib/rubocop/cop/rails/file_path.rb +2 -4
  28. data/lib/rubocop/cop/rails/find_each.rb +8 -2
  29. data/lib/rubocop/cop/rails/freeze_time.rb +74 -0
  30. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -3
  31. data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
  32. data/lib/rubocop/cop/rails/http_status.rb +11 -11
  33. data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
  34. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
  35. data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
  36. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
  37. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
  38. data/lib/rubocop/cop/rails/output.rb +2 -5
  39. data/lib/rubocop/cop/rails/pluck.rb +8 -7
  40. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
  41. data/lib/rubocop/cop/rails/presence.rb +21 -12
  42. data/lib/rubocop/cop/rails/present.rb +3 -6
  43. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  44. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
  45. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  46. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
  47. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +30 -26
  48. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
  49. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  50. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
  51. data/lib/rubocop/cop/rails/request_referer.rb +1 -2
  52. data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
  53. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
  54. data/lib/rubocop/cop/rails/root_pathname_methods.rb +214 -0
  55. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
  56. data/lib/rubocop/cop/rails/save_bang.rb +10 -22
  57. data/lib/rubocop/cop/rails/short_i18n.rb +1 -4
  58. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -2
  59. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
  60. data/lib/rubocop/cop/rails/time_zone.rb +10 -21
  61. data/lib/rubocop/cop/rails/to_s_with_argument.rb +41 -0
  62. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  63. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  64. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
  65. data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
  66. data/lib/rubocop/cop/rails/validation.rb +4 -12
  67. data/lib/rubocop/cop/rails/where_missing.rb +111 -0
  68. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
  69. data/lib/rubocop/cop/rails_cops.rb +10 -0
  70. data/lib/rubocop/rails/version.rb +1 -1
  71. data/lib/rubocop-rails.rb +10 -0
  72. metadata +16 -8
  73. data/bin/console +0 -11
  74. data/bin/setup +0 -7
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Use `where.missing(...)` to find missing relationship records.
7
+ #
8
+ # This cop is enabled in Rails 6.1 or higher.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # Post.left_joins(:author).where(authors: { id: nil })
13
+ #
14
+ # # good
15
+ # Post.where.missing(:author)
16
+ #
17
+ class WhereMissing < Base
18
+ include RangeHelp
19
+ extend AutoCorrector
20
+ extend TargetRailsVersion
21
+
22
+ MSG = 'Use `where.missing(:%<left_joins_association>s)` instead of ' \
23
+ '`%<left_joins_method>s(:%<left_joins_association>s).where(%<where_association>s: { id: nil })`.'
24
+ RESTRICT_ON_SEND = %i[left_joins left_outer_joins].freeze
25
+
26
+ minimum_target_rails_version 6.1
27
+
28
+ # @!method where_node_and_argument(node)
29
+ def_node_search :where_node_and_argument, <<~PATTERN
30
+ $(send ... :where (hash <(pair $(sym _) (hash (pair (sym :id) (nil))))...> ))
31
+ PATTERN
32
+
33
+ # @!method missing_relationship(node)
34
+ def_node_search :missing_relationship, <<~PATTERN
35
+ (pair (sym _) (hash (pair (sym :id) (nil))))
36
+ PATTERN
37
+
38
+ def on_send(node)
39
+ return unless node.first_argument.sym_type?
40
+
41
+ where_node_and_argument(root_receiver(node)) do |where_node, where_argument|
42
+ next unless same_relationship?(where_argument, node.first_argument)
43
+
44
+ range = range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
45
+ register_offense(node, where_node, where_argument, range)
46
+ break
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def root_receiver(node)
53
+ node&.parent&.send_type? ? root_receiver(node.parent) : node
54
+ end
55
+
56
+ def same_relationship?(where, left_joins)
57
+ where.value.to_s.match?(/^#{left_joins.value}s?$/)
58
+ end
59
+
60
+ def register_offense(node, where_node, where_argument, range)
61
+ add_offense(range, message: message(node, where_argument)) do |corrector|
62
+ corrector.replace(node.loc.selector, 'where.missing')
63
+ if multi_condition?(where_node.first_argument)
64
+ replace_where_method(corrector, where_node)
65
+ else
66
+ remove_where_method(corrector, node, where_node)
67
+ end
68
+ end
69
+ end
70
+
71
+ def replace_where_method(corrector, where_node)
72
+ missing_relationship(where_node) do |where_clause|
73
+ corrector.remove(replace_range(where_clause))
74
+ end
75
+ end
76
+
77
+ def replace_range(child)
78
+ if (right_sibling = child.right_sibling)
79
+ range_between(child.loc.expression.begin_pos, right_sibling.loc.expression.begin_pos)
80
+ else
81
+ range_between(child.left_sibling.loc.expression.end_pos, child.loc.expression.end_pos)
82
+ end
83
+ end
84
+
85
+ def remove_where_method(corrector, node, where_node)
86
+ range = range_between(where_node.loc.selector.begin_pos, where_node.loc.end.end_pos)
87
+ if node.multiline? && !same_line?(node, where_node)
88
+ range = range_by_whole_lines(range, include_final_newline: true)
89
+ else
90
+ corrector.remove(where_node.loc.dot)
91
+ end
92
+
93
+ corrector.remove(range)
94
+ end
95
+
96
+ def same_line?(left_joins_node, where_node)
97
+ left_joins_node.loc.selector.line == where_node.loc.selector.line
98
+ end
99
+
100
+ def multi_condition?(where_arg)
101
+ where_arg.children.count > 1
102
+ end
103
+
104
+ def message(node, where_argument)
105
+ format(MSG, left_joins_association: node.first_argument.value, left_joins_method: node.method_name,
106
+ where_association: where_argument.value)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Identifies calls to `where.not` with multiple hash arguments.
7
+ #
8
+ # The behavior of `where.not` changed in Rails 6.1. Prior to the change,
9
+ # `.where.not(trashed: true, role: 'admin')` evaluated to
10
+ # `WHERE trashed != TRUE AND role != 'admin'`.
11
+ # From Rails 6.1 onwards, this executes the query
12
+ # `WHERE NOT (trashed == TRUE AND roles == 'admin')`.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # User.where.not(trashed: true, role: 'admin')
17
+ # User.where.not(trashed: true, role: ['moderator', 'admin'])
18
+ # User.joins(:posts).where.not(posts: { trashed: true, title: 'Rails' })
19
+ #
20
+ # # good
21
+ # User.where.not(trashed: true)
22
+ # User.where.not(role: ['moderator', 'admin'])
23
+ # User.where.not(trashed: true).where.not(role: ['moderator', 'admin'])
24
+ # User.where.not('trashed = ? OR role = ?', true, 'admin')
25
+ class WhereNotWithMultipleConditions < Base
26
+ MSG = 'Use a SQL statement instead of `where.not` with multiple conditions.'
27
+ RESTRICT_ON_SEND = %i[not].freeze
28
+
29
+ def_node_matcher :where_not_call?, <<~PATTERN
30
+ (send (send _ :where) :not $...)
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ where_not_call?(node) do |args|
35
+ next unless args[0].hash_type?
36
+ next unless multiple_arguments_hash? args[0]
37
+
38
+ range = node.receiver.loc.selector.with(end_pos: node.loc.expression.end_pos)
39
+
40
+ add_offense(range)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def multiple_arguments_hash?(hash)
47
+ return true if hash.pairs.size >= 2
48
+ return false unless hash.values[0].hash_type?
49
+
50
+ multiple_arguments_hash?(hash.values[0])
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -8,12 +8,15 @@ require_relative 'mixin/index_method'
8
8
  require_relative 'mixin/migrations_helper'
9
9
  require_relative 'mixin/target_rails_version'
10
10
 
11
+ require_relative 'rails/action_controller_flash_before_render'
11
12
  require_relative 'rails/action_controller_test_case'
12
13
  require_relative 'rails/action_filter'
14
+ require_relative 'rails/action_order'
13
15
  require_relative 'rails/active_record_aliases'
14
16
  require_relative 'rails/active_record_callbacks_order'
15
17
  require_relative 'rails/active_record_override'
16
18
  require_relative 'rails/active_support_aliases'
19
+ require_relative 'rails/active_support_on_load'
17
20
  require_relative 'rails/add_column_index'
18
21
  require_relative 'rails/after_commit_override'
19
22
  require_relative 'rails/application_controller'
@@ -50,6 +53,7 @@ require_relative 'rails/file_path'
50
53
  require_relative 'rails/find_by'
51
54
  require_relative 'rails/find_by_id'
52
55
  require_relative 'rails/find_each'
56
+ require_relative 'rails/freeze_time'
53
57
  require_relative 'rails/has_and_belongs_to_many'
54
58
  require_relative 'rails/has_many_or_has_one_dependent'
55
59
  require_relative 'rails/helper_instance_variable'
@@ -58,6 +62,7 @@ require_relative 'rails/http_status'
58
62
  require_relative 'rails/i18n_lazy_lookup'
59
63
  require_relative 'rails/i18n_locale_assignment'
60
64
  require_relative 'rails/i18n_locale_texts'
65
+ require_relative 'rails/ignored_columns_assignment'
61
66
  require_relative 'rails/ignored_skip_action_filter_option'
62
67
  require_relative 'rails/index_by'
63
68
  require_relative 'rails/index_with'
@@ -97,6 +102,7 @@ require_relative 'rails/require_dependency'
97
102
  require_relative 'rails/reversible_migration'
98
103
  require_relative 'rails/reversible_migration_method_definition'
99
104
  require_relative 'rails/root_join_chain'
105
+ require_relative 'rails/root_pathname_methods'
100
106
  require_relative 'rails/root_public_path'
101
107
  require_relative 'rails/safe_navigation'
102
108
  require_relative 'rails/safe_navigation_with_blank'
@@ -111,6 +117,8 @@ require_relative 'rails/table_name_assignment'
111
117
  require_relative 'rails/time_zone'
112
118
  require_relative 'rails/time_zone_assignment'
113
119
  require_relative 'rails/to_formatted_s'
120
+ require_relative 'rails/to_s_with_argument'
121
+ require_relative 'rails/top_level_hash_with_indifferent_access'
114
122
  require_relative 'rails/transaction_exit_statement'
115
123
  require_relative 'rails/uniq_before_pluck'
116
124
  require_relative 'rails/unique_validation_without_index'
@@ -119,4 +127,6 @@ require_relative 'rails/unused_ignored_columns'
119
127
  require_relative 'rails/validation'
120
128
  require_relative 'rails/where_equals'
121
129
  require_relative 'rails/where_exists'
130
+ require_relative 'rails/where_missing'
122
131
  require_relative 'rails/where_not'
132
+ require_relative 'rails/where_not_with_multiple_conditions'
@@ -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.15.2'
7
+ STRING = '2.17.0'
8
8
 
9
9
  def self.document_version
10
10
  STRING.match('\d+\.\d+').to_s
data/lib/rubocop-rails.rb CHANGED
@@ -14,6 +14,16 @@ RuboCop::Rails::Inject.defaults!
14
14
 
15
15
  require_relative 'rubocop/cop/rails_cops'
16
16
 
17
+ RuboCop::Cop::Style::HashExcept.minimum_target_ruby_version(2.0)
18
+
19
+ RuboCop::Cop::Style::MethodCallWithArgsParentheses.singleton_class.prepend(
20
+ Module.new do
21
+ def autocorrect_incompatible_with
22
+ super.push(RuboCop::Cop::Rails::EagerEvaluationLogMessage)
23
+ end
24
+ end
25
+ )
26
+
17
27
  RuboCop::Cop::Style::RedundantSelf.singleton_class.prepend(
18
28
  Module.new do
19
29
  def autocorrect_incompatible_with
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.15.2
4
+ version: 2.17.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: 2022-07-07 00:00:00.000000000 Z
13
+ date: 2022-10-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -46,7 +46,7 @@ dependencies:
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 1.7.0
49
+ version: 1.33.0
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '2.0'
@@ -56,7 +56,7 @@ dependencies:
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 1.7.0
59
+ version: 1.33.0
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
62
  version: '2.0'
@@ -72,8 +72,6 @@ extra_rdoc_files:
72
72
  files:
73
73
  - LICENSE.txt
74
74
  - README.md
75
- - bin/console
76
- - bin/setup
77
75
  - config/default.yml
78
76
  - config/obsoletion.yml
79
77
  - lib/rubocop-rails.rb
@@ -84,12 +82,15 @@ files:
84
82
  - lib/rubocop/cop/mixin/index_method.rb
85
83
  - lib/rubocop/cop/mixin/migrations_helper.rb
86
84
  - lib/rubocop/cop/mixin/target_rails_version.rb
85
+ - lib/rubocop/cop/rails/action_controller_flash_before_render.rb
87
86
  - lib/rubocop/cop/rails/action_controller_test_case.rb
88
87
  - lib/rubocop/cop/rails/action_filter.rb
88
+ - lib/rubocop/cop/rails/action_order.rb
89
89
  - lib/rubocop/cop/rails/active_record_aliases.rb
90
90
  - lib/rubocop/cop/rails/active_record_callbacks_order.rb
91
91
  - lib/rubocop/cop/rails/active_record_override.rb
92
92
  - lib/rubocop/cop/rails/active_support_aliases.rb
93
+ - lib/rubocop/cop/rails/active_support_on_load.rb
93
94
  - lib/rubocop/cop/rails/add_column_index.rb
94
95
  - lib/rubocop/cop/rails/after_commit_override.rb
95
96
  - lib/rubocop/cop/rails/application_controller.rb
@@ -126,6 +127,7 @@ files:
126
127
  - lib/rubocop/cop/rails/find_by.rb
127
128
  - lib/rubocop/cop/rails/find_by_id.rb
128
129
  - lib/rubocop/cop/rails/find_each.rb
130
+ - lib/rubocop/cop/rails/freeze_time.rb
129
131
  - lib/rubocop/cop/rails/has_and_belongs_to_many.rb
130
132
  - lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb
131
133
  - lib/rubocop/cop/rails/helper_instance_variable.rb
@@ -134,6 +136,7 @@ files:
134
136
  - lib/rubocop/cop/rails/i18n_lazy_lookup.rb
135
137
  - lib/rubocop/cop/rails/i18n_locale_assignment.rb
136
138
  - lib/rubocop/cop/rails/i18n_locale_texts.rb
139
+ - lib/rubocop/cop/rails/ignored_columns_assignment.rb
137
140
  - lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb
138
141
  - lib/rubocop/cop/rails/index_by.rb
139
142
  - lib/rubocop/cop/rails/index_with.rb
@@ -173,6 +176,7 @@ files:
173
176
  - lib/rubocop/cop/rails/reversible_migration.rb
174
177
  - lib/rubocop/cop/rails/reversible_migration_method_definition.rb
175
178
  - lib/rubocop/cop/rails/root_join_chain.rb
179
+ - lib/rubocop/cop/rails/root_pathname_methods.rb
176
180
  - lib/rubocop/cop/rails/root_public_path.rb
177
181
  - lib/rubocop/cop/rails/safe_navigation.rb
178
182
  - lib/rubocop/cop/rails/safe_navigation_with_blank.rb
@@ -187,6 +191,8 @@ files:
187
191
  - lib/rubocop/cop/rails/time_zone.rb
188
192
  - lib/rubocop/cop/rails/time_zone_assignment.rb
189
193
  - lib/rubocop/cop/rails/to_formatted_s.rb
194
+ - lib/rubocop/cop/rails/to_s_with_argument.rb
195
+ - lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb
190
196
  - lib/rubocop/cop/rails/transaction_exit_statement.rb
191
197
  - lib/rubocop/cop/rails/uniq_before_pluck.rb
192
198
  - lib/rubocop/cop/rails/unique_validation_without_index.rb
@@ -195,7 +201,9 @@ files:
195
201
  - lib/rubocop/cop/rails/validation.rb
196
202
  - lib/rubocop/cop/rails/where_equals.rb
197
203
  - lib/rubocop/cop/rails/where_exists.rb
204
+ - lib/rubocop/cop/rails/where_missing.rb
198
205
  - lib/rubocop/cop/rails/where_not.rb
206
+ - lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb
199
207
  - lib/rubocop/cop/rails_cops.rb
200
208
  - lib/rubocop/rails.rb
201
209
  - lib/rubocop/rails/inject.rb
@@ -209,7 +217,7 @@ metadata:
209
217
  homepage_uri: https://docs.rubocop.org/rubocop-rails/
210
218
  changelog_uri: https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md
211
219
  source_code_uri: https://github.com/rubocop/rubocop-rails/
212
- documentation_uri: https://docs.rubocop.org/rubocop-rails/2.15/
220
+ documentation_uri: https://docs.rubocop.org/rubocop-rails/2.17/
213
221
  bug_tracker_uri: https://github.com/rubocop/rubocop-rails/issues
214
222
  rubygems_mfa_required: 'true'
215
223
  post_install_message:
@@ -227,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
235
  - !ruby/object:Gem::Version
228
236
  version: '0'
229
237
  requirements: []
230
- rubygems_version: 3.1.6
238
+ rubygems_version: 3.2.22
231
239
  signing_key:
232
240
  specification_version: 4
233
241
  summary: Automatic Rails code style checking tool.
data/bin/console DELETED
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'bundler/setup'
5
- require 'irb'
6
- require 'rubocop'
7
- require 'rubocop-rails'
8
-
9
- ARGV.clear
10
-
11
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- set -euo pipefail
4
- IFS=$'\n\t'
5
- set -vx
6
-
7
- bundle install