rubocop-rails 2.21.2 → 2.23.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.
- checksums.yaml +4 -4
- data/README.md +10 -10
- data/config/default.yml +11 -3
- data/lib/rubocop/cop/mixin/active_record_helper.rb +9 -2
- data/lib/rubocop/cop/mixin/database_type_resolvable.rb +66 -0
- data/lib/rubocop/cop/rails/action_filter.rb +3 -0
- data/lib/rubocop/cop/rails/active_record_aliases.rb +2 -2
- data/lib/rubocop/cop/rails/active_support_aliases.rb +6 -5
- data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
- data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -56
- data/lib/rubocop/cop/rails/content_tag.rb +1 -1
- data/lib/rubocop/cop/rails/dangerous_column_names.rb +10 -2
- data/lib/rubocop/cop/rails/duplicate_association.rb +66 -12
- data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +2 -2
- data/lib/rubocop/cop/rails/env_local.rb +46 -0
- data/lib/rubocop/cop/rails/file_path.rb +5 -5
- data/lib/rubocop/cop/rails/find_by.rb +2 -2
- data/lib/rubocop/cop/rails/find_by_id.rb +9 -23
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -1
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +1 -1
- data/lib/rubocop/cop/rails/inquiry.rb +1 -0
- data/lib/rubocop/cop/rails/inverse_of.rb +1 -1
- data/lib/rubocop/cop/rails/not_null_column.rb +13 -3
- data/lib/rubocop/cop/rails/output.rb +3 -2
- data/lib/rubocop/cop/rails/pick.rb +6 -5
- data/lib/rubocop/cop/rails/pluck.rb +1 -1
- data/lib/rubocop/cop/rails/pluck_id.rb +2 -1
- data/lib/rubocop/cop/rails/pluck_in_where.rb +18 -5
- data/lib/rubocop/cop/rails/rake_environment.rb +2 -2
- data/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +53 -2
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +7 -0
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -1
- data/lib/rubocop/cop/rails/response_parsed_body.rb +52 -10
- data/lib/rubocop/cop/rails/reversible_migration.rb +2 -2
- data/lib/rubocop/cop/rails/save_bang.rb +11 -6
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -1
- data/lib/rubocop/cop/rails/unknown_env.rb +5 -1
- data/lib/rubocop/cop/rails/validation.rb +2 -2
- data/lib/rubocop/cop/rails/where_equals.rb +3 -2
- data/lib/rubocop/cop/rails/where_exists.rb +9 -8
- data/lib/rubocop/cop/rails/where_missing.rb +1 -1
- data/lib/rubocop/cop/rails/where_not.rb +8 -6
- data/lib/rubocop/cop/rails_cops.rb +2 -0
- data/lib/rubocop/rails/schema_loader/schema.rb +2 -2
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +26 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f90e14aba3397c0edacdc63f7dd9d5b83ed7d79382041f5f37e3201dea96c3db
|
4
|
+
data.tar.gz: 31ebefe705b4148901128b2b5feb5948b737acdd5fae210f8da6cec845f17023
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b90a96dae0688c93975260b480c2add1449c5ca21503a071453464f63ba030713501e1d20e2ea4fdf3385a58d1cf71003e2ede718ec9b6aa80e86e4a82be00a7
|
7
|
+
data.tar.gz: ad4ed3bbe86f2d1179766c512f347aaa21ea6e18e8af5a00f07eb20098c6c3c0103955ba4366bf952528773b7b2ff6a21af52369969227fd05233138a1060708
|
data/README.md
CHANGED
@@ -56,6 +56,8 @@ Note: `--rails` option is required while `rubocop` command supports `--rails` op
|
|
56
56
|
### Rake task
|
57
57
|
|
58
58
|
```ruby
|
59
|
+
require 'rubocop/rake_task'
|
60
|
+
|
59
61
|
RuboCop::RakeTask.new do |task|
|
60
62
|
task.requires << 'rubocop-rails'
|
61
63
|
end
|
@@ -64,23 +66,21 @@ end
|
|
64
66
|
## Rails configuration tip
|
65
67
|
|
66
68
|
If you are using Rails 6.1 or newer, add the following `config.generators.after_generate` setting to
|
67
|
-
your config/
|
69
|
+
your `config/environments/development.rb` to apply RuboCop autocorrection to code generated by `bin/rails g`.
|
68
70
|
|
69
71
|
```ruby
|
70
|
-
# config/
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true)
|
77
|
-
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)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
81
81
|
```
|
82
82
|
|
83
|
-
It uses `rubocop -A` to apply `Style/FrozenStringLiteralComment` and other unsafe
|
83
|
+
It uses `rubocop -A` to apply `Style/FrozenStringLiteralComment` and other unsafe autocorrection cops.
|
84
84
|
`rubocop -A` is unsafe autocorrection, but code generated by default is simple and less likely to
|
85
85
|
be incompatible with `rubocop -A`. If you have problems you can replace it with `rubocop -a` instead.
|
86
86
|
|
data/config/default.yml
CHANGED
@@ -95,8 +95,9 @@ Rails/ActionControllerTestCase:
|
|
95
95
|
|
96
96
|
Rails/ActionFilter:
|
97
97
|
Description: 'Enforces consistent use of action filter methods.'
|
98
|
-
Enabled:
|
98
|
+
Enabled: false
|
99
99
|
VersionAdded: '0.19'
|
100
|
+
VersionChanged: '2.22'
|
100
101
|
EnforcedStyle: action
|
101
102
|
SupportedStyles:
|
102
103
|
- action
|
@@ -338,7 +339,6 @@ Rails/Date:
|
|
338
339
|
|
339
340
|
Rails/DefaultScope:
|
340
341
|
Description: 'Avoid use of `default_scope`.'
|
341
|
-
StyleGuide: 'https://rails.rubystyle.guide#avoid-default-scope'
|
342
342
|
Enabled: false
|
343
343
|
VersionAdded: '2.7'
|
344
344
|
|
@@ -430,6 +430,11 @@ Rails/EnumUniqueness:
|
|
430
430
|
Include:
|
431
431
|
- app/models/**/*.rb
|
432
432
|
|
433
|
+
Rails/EnvLocal:
|
434
|
+
Description: 'Use `Rails.env.local?` instead of `Rails.env.development? || Rails.env.test?`.'
|
435
|
+
Enabled: pending
|
436
|
+
VersionAdded: '2.22'
|
437
|
+
|
433
438
|
Rails/EnvironmentComparison:
|
434
439
|
Description: "Favor `Rails.env.production?` over `Rails.env == 'production'`."
|
435
440
|
Enabled: true
|
@@ -690,6 +695,9 @@ Rails/NotNullColumn:
|
|
690
695
|
Enabled: true
|
691
696
|
VersionAdded: '0.43'
|
692
697
|
VersionChanged: '2.20'
|
698
|
+
Database: null
|
699
|
+
SupportedDatabases:
|
700
|
+
- mysql
|
693
701
|
Include:
|
694
702
|
- db/**/*.rb
|
695
703
|
|
@@ -894,7 +902,7 @@ Rails/RequireDependency:
|
|
894
902
|
VersionAdded: '2.10'
|
895
903
|
|
896
904
|
Rails/ResponseParsedBody:
|
897
|
-
Description: Prefer `response.parsed_body` to `
|
905
|
+
Description: Prefer `response.parsed_body` to custom parsing logic for `response.body`.
|
898
906
|
Enabled: pending
|
899
907
|
Safe: false
|
900
908
|
VersionAdded: '2.18'
|
@@ -98,8 +98,15 @@ module RuboCop
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def in_where?(node)
|
101
|
-
send_node = node.each_ancestor(:send).first
|
102
|
-
|
101
|
+
send_node = node.each_ancestor(:send, :csend).first
|
102
|
+
return false unless send_node
|
103
|
+
|
104
|
+
return true if WHERE_METHODS.include?(send_node.method_name)
|
105
|
+
|
106
|
+
receiver = send_node.receiver
|
107
|
+
return false unless receiver&.send_type?
|
108
|
+
|
109
|
+
send_node.method?(:not) && WHERE_METHODS.include?(receiver.method_name)
|
103
110
|
end
|
104
111
|
end
|
105
112
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# A mixin to extend cops in order to determine the database type.
|
6
|
+
#
|
7
|
+
# This module automatically detect an adapter from `development` environment
|
8
|
+
# in `config/database.yml` or the environment variable `DATABASE_URL`
|
9
|
+
# when the `Database` option is not set.
|
10
|
+
module DatabaseTypeResolvable
|
11
|
+
MYSQL = 'mysql'
|
12
|
+
POSTGRESQL = 'postgresql'
|
13
|
+
|
14
|
+
def database
|
15
|
+
cop_config['Database'] || database_from_yaml || database_from_env
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def database_from_yaml
|
21
|
+
return unless database_yaml
|
22
|
+
|
23
|
+
case database_adapter
|
24
|
+
when 'mysql2', 'trilogy'
|
25
|
+
MYSQL
|
26
|
+
when 'postgresql', 'postgis'
|
27
|
+
POSTGRESQL
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def database_from_env
|
32
|
+
url = ENV['DATABASE_URL'].presence
|
33
|
+
return unless url
|
34
|
+
|
35
|
+
case url
|
36
|
+
when %r{\A(mysql2|trilogy)://}
|
37
|
+
MYSQL
|
38
|
+
when %r{\Apostgres(ql)?://}
|
39
|
+
POSTGRESQL
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def database_yaml
|
44
|
+
return unless File.exist?('config/database.yml')
|
45
|
+
|
46
|
+
yaml = if YAML.respond_to?(:unsafe_load_file)
|
47
|
+
YAML.unsafe_load_file('config/database.yml')
|
48
|
+
else
|
49
|
+
YAML.load_file('config/database.yml')
|
50
|
+
end
|
51
|
+
return unless yaml.is_a? Hash
|
52
|
+
|
53
|
+
config = yaml['development']
|
54
|
+
return unless config.is_a?(Hash)
|
55
|
+
|
56
|
+
config
|
57
|
+
rescue Psych::SyntaxError
|
58
|
+
# noop
|
59
|
+
end
|
60
|
+
|
61
|
+
def database_adapter
|
62
|
+
database_yaml['adapter'] || database_yaml.first.last['adapter']
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -8,6 +8,9 @@ module RuboCop
|
|
8
8
|
# The cop is configurable and can enforce the use of the older
|
9
9
|
# something_filter methods or the newer something_action methods.
|
10
10
|
#
|
11
|
+
# IMPORTANT: This cop is deprecated. Because the `*_filter` methods were removed in Rails 4.2,
|
12
|
+
# and that Rails version is no longer supported by RuboCop Rails. This cop will be removed in RuboCop Rails 3.0.
|
13
|
+
#
|
11
14
|
# @example EnforcedStyle: action (default)
|
12
15
|
# # bad
|
13
16
|
# after_filter :do_stuff
|
@@ -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: '(
|
30
|
+
original: :start_with?, matcher: '(call str :starts_with? _)'
|
31
31
|
},
|
32
32
|
ends_with?: {
|
33
|
-
original: :end_with?, matcher: '(
|
33
|
+
original: :end_with?, matcher: '(call str :ends_with? _)'
|
34
34
|
},
|
35
|
-
append: { original: :<<, matcher: '(
|
36
|
-
prepend: { original: :unshift, matcher: '(
|
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
|
@@ -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.
|
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` or `
|
17
|
+
# If the adapter is not `mysql2`, `trilogy`, `postgresql`, or `postgis`,
|
18
18
|
# this Cop ignores offenses.
|
19
19
|
#
|
20
20
|
# @example
|
@@ -64,6 +64,8 @@ module RuboCop
|
|
64
64
|
# end
|
65
65
|
# end
|
66
66
|
class BulkChangeTable < Base
|
67
|
+
include DatabaseTypeResolvable
|
68
|
+
|
67
69
|
MSG_FOR_CHANGE_TABLE = <<~MSG.chomp
|
68
70
|
You can combine alter queries using `bulk: true` options.
|
69
71
|
MSG
|
@@ -71,9 +73,6 @@ module RuboCop
|
|
71
73
|
You can use `change_table :%<table>s, bulk: true` to combine alter queries.
|
72
74
|
MSG
|
73
75
|
|
74
|
-
MYSQL = 'mysql'
|
75
|
-
POSTGRESQL = 'postgresql'
|
76
|
-
|
77
76
|
MIGRATION_METHODS = %i[change up down].freeze
|
78
77
|
|
79
78
|
COMBINABLE_TRANSFORMATIONS = %i[
|
@@ -175,55 +174,6 @@ module RuboCop
|
|
175
174
|
options.hash_type? && options.keys.any? { |key| key.sym_type? && key.value == :bulk }
|
176
175
|
end
|
177
176
|
|
178
|
-
def database
|
179
|
-
cop_config['Database'] || database_from_yaml || database_from_env
|
180
|
-
end
|
181
|
-
|
182
|
-
def database_from_yaml
|
183
|
-
return nil unless database_yaml
|
184
|
-
|
185
|
-
case database_adapter
|
186
|
-
when 'mysql2'
|
187
|
-
MYSQL
|
188
|
-
when 'postgresql'
|
189
|
-
POSTGRESQL
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def database_adapter
|
194
|
-
database_yaml['adapter'] || database_yaml.first.last['adapter']
|
195
|
-
end
|
196
|
-
|
197
|
-
def database_yaml
|
198
|
-
return nil unless File.exist?('config/database.yml')
|
199
|
-
|
200
|
-
yaml = if YAML.respond_to?(:unsafe_load_file)
|
201
|
-
YAML.unsafe_load_file('config/database.yml')
|
202
|
-
else
|
203
|
-
YAML.load_file('config/database.yml')
|
204
|
-
end
|
205
|
-
return nil unless yaml.is_a? Hash
|
206
|
-
|
207
|
-
config = yaml['development']
|
208
|
-
return nil unless config.is_a?(Hash)
|
209
|
-
|
210
|
-
config
|
211
|
-
rescue Psych::SyntaxError
|
212
|
-
nil
|
213
|
-
end
|
214
|
-
|
215
|
-
def database_from_env
|
216
|
-
url = ENV['DATABASE_URL'].presence
|
217
|
-
return nil unless url
|
218
|
-
|
219
|
-
case url
|
220
|
-
when %r{\Amysql2://}
|
221
|
-
MYSQL
|
222
|
-
when %r{\Apostgres(ql)?://}
|
223
|
-
POSTGRESQL
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
177
|
def support_bulk_alter?
|
228
178
|
case database
|
229
179
|
when MYSQL
|
@@ -262,7 +212,7 @@ module RuboCop
|
|
262
212
|
# @param node [RuboCop::AST::SendNode]
|
263
213
|
def add_offense_for_alter_methods(node)
|
264
214
|
# arguments: [{(sym :table)(str "table")} ...]
|
265
|
-
table_node = node.
|
215
|
+
table_node = node.first_argument
|
266
216
|
return unless table_node.is_a? RuboCop::AST::BasicLiteralNode
|
267
217
|
|
268
218
|
message = format(MSG_FOR_ALTER_METHODS, table: table_node.value)
|
@@ -284,10 +234,10 @@ module RuboCop
|
|
284
234
|
# @param new_node [RuboCop::AST::SendNode]
|
285
235
|
def process(new_node)
|
286
236
|
# arguments: [{(sym :table)(str "table")} ...]
|
287
|
-
table_node = new_node.
|
237
|
+
table_node = new_node.first_argument
|
288
238
|
if table_node.is_a? RuboCop::AST::BasicLiteralNode
|
289
239
|
flush unless @nodes.all? do |node|
|
290
|
-
node.
|
240
|
+
node.first_argument.value.to_s == table_node.value.to_s
|
291
241
|
end
|
292
242
|
@nodes << new_node
|
293
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
|
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,10 +31,11 @@ module RuboCop
|
|
31
31
|
time
|
32
32
|
].to_set.freeze
|
33
33
|
|
34
|
-
# Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.0.
|
34
|
+
# Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.1.0.
|
35
35
|
# rubocop:disable Metrics/CollectionLiteralLength
|
36
36
|
DANGEROUS_COLUMN_NAMES = %w[
|
37
37
|
__callbacks
|
38
|
+
__id__
|
38
39
|
_assign_attribute
|
39
40
|
_assign_attributes
|
40
41
|
_before_commit_callbacks
|
@@ -195,11 +196,13 @@ module RuboCop
|
|
195
196
|
changes_to_save
|
196
197
|
check_record_limit
|
197
198
|
ciphertext_for
|
199
|
+
class
|
198
200
|
clear_attribute_change
|
199
201
|
clear_attribute_changes
|
200
202
|
clear_changes_information
|
201
203
|
clear_timestamp_attributes
|
202
204
|
clear_transaction_record_state
|
205
|
+
clone
|
203
206
|
collection_cache_versioning
|
204
207
|
column_for_attribute
|
205
208
|
committed
|
@@ -227,6 +230,7 @@ module RuboCop
|
|
227
230
|
destroyed
|
228
231
|
destroyed_by_association
|
229
232
|
destroyed_by_association=
|
233
|
+
dup
|
230
234
|
each_counter_cached_associations
|
231
235
|
encode_with
|
232
236
|
encrypt
|
@@ -243,7 +247,9 @@ module RuboCop
|
|
243
247
|
find_parameter_position
|
244
248
|
forget_attribute_assignments
|
245
249
|
format_for_inspect
|
250
|
+
freeze
|
246
251
|
from_json
|
252
|
+
frozen?
|
247
253
|
halted_callback_hook
|
248
254
|
has_attribute
|
249
255
|
has_changes_to_save
|
@@ -252,6 +258,7 @@ module RuboCop
|
|
252
258
|
has_encrypted_attributes
|
253
259
|
has_encrypted_rich_texts
|
254
260
|
has_transactional_callbacks
|
261
|
+
hash
|
255
262
|
id
|
256
263
|
id_before_type_cast
|
257
264
|
id_for_database
|
@@ -283,6 +290,7 @@ module RuboCop
|
|
283
290
|
new_record
|
284
291
|
no_touching
|
285
292
|
normalize_reflection_attribute
|
293
|
+
object_id
|
286
294
|
partial_inserts
|
287
295
|
partial_updates
|
288
296
|
perform_validations
|
@@ -420,7 +428,7 @@ module RuboCop
|
|
420
428
|
when :rename_column
|
421
429
|
node.arguments[2]
|
422
430
|
when *COLUMN_TYPE_METHOD_NAMES
|
423
|
-
node.
|
431
|
+
node.first_argument
|
424
432
|
end
|
425
433
|
end
|
426
434
|
|
@@ -20,6 +20,15 @@ module RuboCop
|
|
20
20
|
# belongs_to :bar
|
21
21
|
# has_one :foo
|
22
22
|
#
|
23
|
+
# # bad
|
24
|
+
# has_many :foo, class_name: 'Foo'
|
25
|
+
# has_many :bar, class_name: 'Foo'
|
26
|
+
# has_one :baz
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# has_many :bar, class_name: 'Foo'
|
30
|
+
# has_one :foo
|
31
|
+
#
|
23
32
|
class DuplicateAssociation < Base
|
24
33
|
include RangeHelp
|
25
34
|
extend AutoCorrector
|
@@ -27,31 +36,76 @@ module RuboCop
|
|
27
36
|
include ActiveRecordHelper
|
28
37
|
|
29
38
|
MSG = "Association `%<name>s` is defined multiple times. Don't repeat associations."
|
39
|
+
MSG_CLASS_NAME = "Association `class_name: %<name>s` is defined multiple times. Don't repeat associations."
|
30
40
|
|
31
41
|
def_node_matcher :association, <<~PATTERN
|
32
|
-
(send nil? {:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_)
|
42
|
+
(send nil? {:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_) $...)
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def_node_matcher :class_name, <<~PATTERN
|
46
|
+
(hash (pair (sym :class_name) $_))
|
33
47
|
PATTERN
|
34
48
|
|
35
49
|
def on_class(class_node)
|
36
50
|
return unless active_record?(class_node.parent_class)
|
37
51
|
|
38
|
-
|
39
|
-
nodes.each do |node|
|
40
|
-
add_offense(node, message: format(MSG, name: name)) do |corrector|
|
41
|
-
next if same_line?(nodes.last, node)
|
52
|
+
association_nodes = association_nodes(class_node)
|
42
53
|
|
43
|
-
|
44
|
-
|
45
|
-
|
54
|
+
duplicated_association_name_nodes(association_nodes).each do |name, nodes|
|
55
|
+
register_offense(name, nodes, MSG)
|
56
|
+
end
|
57
|
+
|
58
|
+
duplicated_class_name_nodes(association_nodes).each do |class_name, nodes|
|
59
|
+
register_offense(class_name, nodes, MSG_CLASS_NAME)
|
46
60
|
end
|
47
61
|
end
|
48
62
|
|
49
63
|
private
|
50
64
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
65
|
+
def register_offense(name, nodes, message_template)
|
66
|
+
nodes.each do |node|
|
67
|
+
add_offense(node, message: format(message_template, name: name)) do |corrector|
|
68
|
+
next if same_line?(nodes.last, node)
|
69
|
+
|
70
|
+
corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def association_nodes(class_node)
|
76
|
+
class_send_nodes(class_node).select do |node|
|
77
|
+
association(node)&.first
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def duplicated_association_name_nodes(association_nodes)
|
82
|
+
grouped_associations = association_nodes.group_by do |node|
|
83
|
+
association(node).first.to_sym
|
84
|
+
end
|
85
|
+
|
86
|
+
leave_duplicated_association(grouped_associations)
|
87
|
+
end
|
88
|
+
|
89
|
+
def duplicated_class_name_nodes(association_nodes)
|
90
|
+
filtered_nodes = association_nodes.reject { |node| node.method?(:belongs_to) }
|
91
|
+
grouped_associations = filtered_nodes.group_by do |node|
|
92
|
+
arguments = association(node).last
|
93
|
+
next unless arguments.count == 1
|
94
|
+
|
95
|
+
if (class_name = class_name(arguments.first))
|
96
|
+
class_name.source
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
grouped_associations.delete(nil)
|
101
|
+
|
102
|
+
leave_duplicated_association(grouped_associations)
|
103
|
+
end
|
104
|
+
|
105
|
+
def leave_duplicated_association(grouped_associations)
|
106
|
+
grouped_associations.select do |_, nodes|
|
107
|
+
nodes.length > 1
|
108
|
+
end
|
55
109
|
end
|
56
110
|
end
|
57
111
|
end
|
@@ -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
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks for usage of `Rails.env.development? || Rails.env.test?` which
|
7
|
+
# can be replaced with `Rails.env.local?`, introduced in Rails 7.1.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# Rails.env.development? || Rails.env.test?
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# Rails.env.local?
|
16
|
+
#
|
17
|
+
class EnvLocal < Base
|
18
|
+
extend AutoCorrector
|
19
|
+
extend TargetRailsVersion
|
20
|
+
|
21
|
+
MSG = 'Use `Rails.env.local?` instead.'
|
22
|
+
LOCAL_ENVIRONMENTS = %i[development? test?].to_set.freeze
|
23
|
+
|
24
|
+
minimum_target_rails_version 7.1
|
25
|
+
|
26
|
+
# @!method rails_env_local_candidate?(node)
|
27
|
+
def_node_matcher :rails_env_local_candidate?, <<~PATTERN
|
28
|
+
(or
|
29
|
+
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
|
30
|
+
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
|
31
|
+
)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_or(node)
|
35
|
+
rails_env_local_candidate?(node) do |*environments|
|
36
|
+
next unless environments.to_set == LOCAL_ENVIRONMENTS
|
37
|
+
|
38
|
+
add_offense(node) do |corrector|
|
39
|
+
corrector.replace(node, 'Rails.env.local?')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -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.
|
166
|
+
return unless rails_root_node.last_argument.str_type?
|
167
167
|
|
168
|
-
corrector.insert_before(rails_root_node.
|
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.
|
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.
|
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.
|
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
|
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
|