rubocop-rails 2.5.2 → 2.6.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +36 -6
- data/lib/rubocop/cop/mixin/active_record_helper.rb +1 -3
- data/lib/rubocop/cop/mixin/index_method.rb +8 -1
- data/lib/rubocop/cop/rails/content_tag.rb +82 -0
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +1 -3
- data/lib/rubocop/cop/rails/delegate.rb +1 -3
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +40 -15
- data/lib/rubocop/cop/rails/exit.rb +2 -2
- data/lib/rubocop/cop/rails/file_path.rb +1 -0
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +1 -1
- data/lib/rubocop/cop/rails/http_status.rb +2 -0
- data/lib/rubocop/cop/rails/inverse_of.rb +0 -4
- data/lib/rubocop/cop/rails/link_to_blank.rb +1 -3
- data/lib/rubocop/cop/rails/pick.rb +51 -0
- data/lib/rubocop/cop/rails/presence.rb +2 -6
- data/lib/rubocop/cop/rails/rake_environment.rb +17 -0
- data/lib/rubocop/cop/rails/redundant_foreign_key.rb +80 -0
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +0 -3
- data/lib/rubocop/cop/rails/save_bang.rb +6 -7
- data/lib/rubocop/cop/rails/skips_model_validations.rb +4 -1
- data/lib/rubocop/cop/rails/time_zone.rb +1 -3
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +16 -16
- data/lib/rubocop/cop/rails/unknown_env.rb +7 -6
- data/lib/rubocop/cop/rails_cops.rb +3 -0
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6b55ee8df864d6eaee4a491f4324343ee2274eafcb352952a81ff045832aa22
|
4
|
+
data.tar.gz: 344ea324a589dc25ce3e87366c4af33bde4e392acf6acaccf9b9296066680824
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bdccc2a5e2a45533cb5bb33b2df26872f806dd590c13d640d7449315e56ec6250aebdb876fb37812bb3dd47cdaeda61c6049bc5cf98b01b473a616e9061491b
|
7
|
+
data.tar.gz: 6f8673f2e8d0068bcdbe1599936793461bab38f4b333a4ac6e22e03e7162851d6fc20543ec58e3f2fabdf404764b09f8ff47e6a5c23d492f0c8bb28acd012296
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -78,13 +78,13 @@ Rails/FindBy:
|
|
78
78
|
|
79
79
|
## Documentation
|
80
80
|
|
81
|
-
You can read a lot more about RuboCop Rails in its [official docs](https://docs.rubocop.org/
|
81
|
+
You can read a lot more about RuboCop Rails in its [official docs](https://docs.rubocop.org/rubocop-rails/).
|
82
82
|
|
83
83
|
## Compatibility
|
84
84
|
|
85
85
|
Rails cops support the following versions:
|
86
86
|
|
87
|
-
- Rails 4.
|
87
|
+
- Rails 4.2+
|
88
88
|
|
89
89
|
## Contributing
|
90
90
|
|
data/config/default.yml
CHANGED
@@ -92,7 +92,7 @@ Rails/AssertNot:
|
|
92
92
|
Rails/BelongsTo:
|
93
93
|
Description: >-
|
94
94
|
Use `optional: true` instead of `required: false` for
|
95
|
-
`belongs_to` relations
|
95
|
+
`belongs_to` relations.
|
96
96
|
Enabled: true
|
97
97
|
VersionAdded: '0.62'
|
98
98
|
|
@@ -119,6 +119,14 @@ Rails/BulkChangeTable:
|
|
119
119
|
Include:
|
120
120
|
- db/migrate/*.rb
|
121
121
|
|
122
|
+
Rails/ContentTag:
|
123
|
+
Description: 'Use `tag` instead of `content_tag`.'
|
124
|
+
Reference:
|
125
|
+
- 'https://github.com/rails/rails/issues/25195'
|
126
|
+
- 'https://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag'
|
127
|
+
Enabled: true
|
128
|
+
VersionAdded: '2.6'
|
129
|
+
|
122
130
|
Rails/CreateTableWithTimestamps:
|
123
131
|
Description: >-
|
124
132
|
Checks the migration for which timestamps are not included
|
@@ -165,8 +173,14 @@ Rails/DynamicFindBy:
|
|
165
173
|
StyleGuide: 'https://rails.rubystyle.guide#find_by'
|
166
174
|
Enabled: true
|
167
175
|
VersionAdded: '0.44'
|
176
|
+
VersionChanged: '2.6'
|
177
|
+
# The `Whitelist` has been deprecated, Please use `AllowedMethods` instead.
|
168
178
|
Whitelist:
|
169
179
|
- find_by_sql
|
180
|
+
AllowedMethods:
|
181
|
+
- find_by_sql
|
182
|
+
AllowedReceivers:
|
183
|
+
- Gem::Specification
|
170
184
|
|
171
185
|
Rails/EnumHash:
|
172
186
|
Description: 'Prefer hash syntax over array syntax when defining enums.'
|
@@ -184,7 +198,7 @@ Rails/EnumUniqueness:
|
|
184
198
|
- app/models/**/*.rb
|
185
199
|
|
186
200
|
Rails/EnvironmentComparison:
|
187
|
-
Description: "Favor `Rails.env.production?` over `Rails.env == 'production'
|
201
|
+
Description: "Favor `Rails.env.production?` over `Rails.env == 'production'`."
|
188
202
|
Enabled: true
|
189
203
|
VersionAdded: '0.52'
|
190
204
|
|
@@ -245,7 +259,7 @@ Rails/HasManyOrHasOneDependent:
|
|
245
259
|
- app/models/**/*.rb
|
246
260
|
|
247
261
|
Rails/HelperInstanceVariable:
|
248
|
-
Description: 'Do not use instance variables in helpers'
|
262
|
+
Description: 'Do not use instance variables in helpers.'
|
249
263
|
Enabled: true
|
250
264
|
VersionAdded: '2.0'
|
251
265
|
Include:
|
@@ -312,7 +326,7 @@ Rails/LinkToBlank:
|
|
312
326
|
VersionAdded: '0.62'
|
313
327
|
|
314
328
|
Rails/NotNullColumn:
|
315
|
-
Description: 'Do not add a NOT NULL column without a default value'
|
329
|
+
Description: 'Do not add a NOT NULL column without a default value.'
|
316
330
|
Enabled: true
|
317
331
|
VersionAdded: '0.43'
|
318
332
|
Include:
|
@@ -334,6 +348,12 @@ Rails/OutputSafety:
|
|
334
348
|
Enabled: true
|
335
349
|
VersionAdded: '0.41'
|
336
350
|
|
351
|
+
Rails/Pick:
|
352
|
+
Description: 'Prefer `pick` over `pluck(...).first`.'
|
353
|
+
Enabled: true
|
354
|
+
Safe: false
|
355
|
+
VersionAdded: '2.6'
|
356
|
+
|
337
357
|
Rails/PluralizationGrammar:
|
338
358
|
Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.'
|
339
359
|
Enabled: true
|
@@ -361,6 +381,7 @@ Rails/RakeEnvironment:
|
|
361
381
|
Enabled: true
|
362
382
|
Safe: false
|
363
383
|
VersionAdded: '2.4'
|
384
|
+
VersionChanged: '2.6'
|
364
385
|
Include:
|
365
386
|
- '**/Rakefile'
|
366
387
|
- '**/*.rake'
|
@@ -387,6 +408,11 @@ Rails/RedundantAllowNil:
|
|
387
408
|
Include:
|
388
409
|
- app/models/**/*.rb
|
389
410
|
|
411
|
+
Rails/RedundantForeignKey:
|
412
|
+
Description: 'Checks for associations where the `:foreign_key` option is redundant.'
|
413
|
+
Enabled: true
|
414
|
+
VersionAdded: '2.6'
|
415
|
+
|
390
416
|
Rails/RedundantReceiverInWithOptions:
|
391
417
|
Description: 'Checks for redundant receiver in `with_options`.'
|
392
418
|
Enabled: true
|
@@ -434,7 +460,7 @@ Rails/ReversibleMigration:
|
|
434
460
|
- db/migrate/*.rb
|
435
461
|
|
436
462
|
Rails/SafeNavigation:
|
437
|
-
Description: "Use Ruby's safe navigation operator (`&.`) instead of `try
|
463
|
+
Description: "Use Ruby's safe navigation operator (`&.`) instead of `try!`."
|
438
464
|
Enabled: true
|
439
465
|
VersionAdded: '0.43'
|
440
466
|
# This will convert usages of `try` to use safe navigation as well as `try!`.
|
@@ -513,7 +539,7 @@ Rails/UniqBeforePluck:
|
|
513
539
|
Description: 'Prefer the use of uniq or distinct before pluck.'
|
514
540
|
Enabled: true
|
515
541
|
VersionAdded: '0.40'
|
516
|
-
VersionChanged: '
|
542
|
+
VersionChanged: '2.6'
|
517
543
|
EnforcedStyle: conservative
|
518
544
|
SupportedStyles:
|
519
545
|
- conservative
|
@@ -543,3 +569,7 @@ Rails/Validation:
|
|
543
569
|
VersionChanged: '0.41'
|
544
570
|
Include:
|
545
571
|
- app/models/**/*.rb
|
572
|
+
|
573
|
+
# Accept `redirect_to(...) and return` and similar cases.
|
574
|
+
Style/AndOr:
|
575
|
+
EnforcedStyle: conditionals
|
@@ -15,9 +15,7 @@ module RuboCop
|
|
15
15
|
PATTERN
|
16
16
|
|
17
17
|
def external_dependency_checksum
|
18
|
-
if defined?(@external_dependency_checksum)
|
19
|
-
return @external_dependency_checksum
|
20
|
-
end
|
18
|
+
return @external_dependency_checksum if defined?(@external_dependency_checksum)
|
21
19
|
|
22
20
|
schema_path = RuboCop::Rails::SchemaLoader.db_schema_path
|
23
21
|
return nil if schema_path.nil?
|
@@ -112,7 +112,14 @@ module RuboCop
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def self.from_map_to_h(node, match)
|
115
|
-
strip_trailing_chars =
|
115
|
+
strip_trailing_chars = 0
|
116
|
+
|
117
|
+
unless node.parent&.block_type?
|
118
|
+
map_range = node.children.first.source_range
|
119
|
+
node_range = node.source_range
|
120
|
+
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
121
|
+
end
|
122
|
+
|
116
123
|
new(match, node.children.first, 0, strip_trailing_chars)
|
117
124
|
end
|
118
125
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks that `tag` is used instead of `content_tag`
|
7
|
+
# because `content_tag` is legacy syntax.
|
8
|
+
#
|
9
|
+
# NOTE: Allow `content_tag` when the first argument is a variable because
|
10
|
+
# `content_tag(name)` is simpler rather than `tag.public_send(name)`.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# content_tag(:p, 'Hello world!')
|
15
|
+
# content_tag(:br)
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# tag.p('Hello world!')
|
19
|
+
# tag.br
|
20
|
+
# content_tag(name, 'Hello world!')
|
21
|
+
class ContentTag < Cop
|
22
|
+
include RangeHelp
|
23
|
+
extend TargetRailsVersion
|
24
|
+
|
25
|
+
minimum_target_rails_version 5.1
|
26
|
+
|
27
|
+
MSG = 'Use `tag` instead of `content_tag`.'
|
28
|
+
|
29
|
+
def on_send(node)
|
30
|
+
return unless node.method?(:content_tag)
|
31
|
+
|
32
|
+
first_argument = node.first_argument
|
33
|
+
return unless first_argument
|
34
|
+
|
35
|
+
return if first_argument.variable? || first_argument.send_type? || first_argument.const_type?
|
36
|
+
|
37
|
+
add_offense(node)
|
38
|
+
end
|
39
|
+
|
40
|
+
def autocorrect(node)
|
41
|
+
lambda do |corrector|
|
42
|
+
if method_name?(node.first_argument)
|
43
|
+
replace_method_with_tag_method(corrector, node)
|
44
|
+
remove_first_argument(corrector, node)
|
45
|
+
else
|
46
|
+
corrector.replace(node.loc.selector, 'tag')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def method_name?(node)
|
54
|
+
return false unless node.str_type? || node.sym_type?
|
55
|
+
|
56
|
+
/^[a-zA-Z_][a-zA-Z_0-9]*$/.match?(node.value)
|
57
|
+
end
|
58
|
+
|
59
|
+
def replace_method_with_tag_method(corrector, node)
|
60
|
+
corrector.replace(
|
61
|
+
node.loc.selector,
|
62
|
+
"tag.#{node.first_argument.value}"
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def remove_first_argument(corrector, node)
|
67
|
+
if node.arguments.length > 1
|
68
|
+
corrector.remove(
|
69
|
+
range_between(child_node_beg(node, 0), child_node_beg(node, 1))
|
70
|
+
)
|
71
|
+
elsif node.arguments.length == 1
|
72
|
+
corrector.remove(node.arguments[0].loc.expression)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def child_node_beg(node, index)
|
77
|
+
node.arguments[index].loc.expression.begin_pos
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -70,9 +70,7 @@ module RuboCop
|
|
70
70
|
parent = node.parent
|
71
71
|
|
72
72
|
if create_table_with_block?(parent)
|
73
|
-
if parent.body.nil? || !time_columns_included?(parent.body)
|
74
|
-
add_offense(parent)
|
75
|
-
end
|
73
|
+
add_offense(parent) if parent.body.nil? || !time_columns_included?(parent.body)
|
76
74
|
elsif create_table_with_timestamps_proc?(node)
|
77
75
|
# nothing to do
|
78
76
|
else
|
@@ -71,9 +71,7 @@ module RuboCop
|
|
71
71
|
delegation = ["delegate :#{node.body.method_name}",
|
72
72
|
"to: :#{node.body.receiver.method_name}"]
|
73
73
|
|
74
|
-
if node.method?(prefixed_method_name(node.body))
|
75
|
-
delegation << ['prefix: true']
|
76
|
-
end
|
74
|
+
delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
|
77
75
|
|
78
76
|
lambda do |corrector|
|
79
77
|
corrector.replace(node.source_range, delegation.join(', '))
|
@@ -10,37 +10,41 @@ module RuboCop
|
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
12
|
# User.find_by_name(name)
|
13
|
-
#
|
14
|
-
# # bad
|
15
13
|
# User.find_by_name_and_email(name)
|
16
|
-
#
|
17
|
-
# # bad
|
18
14
|
# User.find_by_email!(name)
|
19
15
|
#
|
20
16
|
# # good
|
21
17
|
# User.find_by(name: name)
|
18
|
+
# User.find_by(name: name, email: email)
|
19
|
+
# User.find_by!(email: email)
|
20
|
+
#
|
21
|
+
# @example AllowedMethods: find_by_sql
|
22
|
+
# # bad
|
23
|
+
# User.find_by_query(users_query)
|
22
24
|
#
|
23
25
|
# # good
|
24
|
-
# User.
|
26
|
+
# User.find_by_sql(users_sql)
|
27
|
+
#
|
28
|
+
# @example AllowedReceivers: Gem::Specification
|
29
|
+
# # bad
|
30
|
+
# Specification.find_by_name('backend').gem_dir
|
25
31
|
#
|
26
32
|
# # good
|
27
|
-
#
|
33
|
+
# Gem::Specification.find_by_name('backend').gem_dir
|
28
34
|
class DynamicFindBy < Cop
|
29
35
|
MSG = 'Use `%<static_name>s` instead of dynamic `%<method>s`.'
|
30
36
|
METHOD_PATTERN = /^find_by_(.+?)(!)?$/.freeze
|
31
37
|
|
32
38
|
def on_send(node)
|
33
|
-
|
34
|
-
|
35
|
-
return if whitelist.include?(method_name)
|
39
|
+
return if allowed_invocation?(node)
|
36
40
|
|
41
|
+
method_name = node.method_name
|
37
42
|
static_name = static_method_name(method_name)
|
38
|
-
|
39
43
|
return unless static_name
|
40
44
|
|
41
45
|
add_offense(node,
|
42
46
|
message: format(MSG, static_name: static_name,
|
43
|
-
method:
|
47
|
+
method: method_name))
|
44
48
|
end
|
45
49
|
alias on_csend on_send
|
46
50
|
|
@@ -57,6 +61,31 @@ module RuboCop
|
|
57
61
|
|
58
62
|
private
|
59
63
|
|
64
|
+
def allowed_invocation?(node)
|
65
|
+
allowed_method?(node) || allowed_receiver?(node) ||
|
66
|
+
whitelisted?(node)
|
67
|
+
end
|
68
|
+
|
69
|
+
def allowed_method?(node)
|
70
|
+
return unless cop_config['AllowedMethods']
|
71
|
+
|
72
|
+
cop_config['AllowedMethods'].include?(node.method_name.to_s)
|
73
|
+
end
|
74
|
+
|
75
|
+
def allowed_receiver?(node)
|
76
|
+
return unless cop_config['AllowedReceivers'] && node.receiver
|
77
|
+
|
78
|
+
cop_config['AllowedReceivers'].include?(node.receiver.source)
|
79
|
+
end
|
80
|
+
|
81
|
+
# config option `WhiteList` will be deprecated soon
|
82
|
+
def whitelisted?(node)
|
83
|
+
whitelist_config = cop_config['Whitelist']
|
84
|
+
return unless whitelist_config
|
85
|
+
|
86
|
+
whitelist_config.include?(node.method_name.to_s)
|
87
|
+
end
|
88
|
+
|
60
89
|
def autocorrect_method_name(corrector, node)
|
61
90
|
corrector.replace(node.loc.selector,
|
62
91
|
static_method_name(node.method_name.to_s))
|
@@ -68,10 +97,6 @@ module RuboCop
|
|
68
97
|
end
|
69
98
|
end
|
70
99
|
|
71
|
-
def whitelist
|
72
|
-
cop_config['Whitelist']
|
73
|
-
end
|
74
|
-
|
75
100
|
def column_keywords(method)
|
76
101
|
keyword_string = method.to_s[METHOD_PATTERN, 1]
|
77
102
|
keyword_string.split('_and_').map { |keyword| "#{keyword}: " }
|
@@ -9,11 +9,11 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# There are two obvious cases where `exit` is particularly harmful:
|
11
11
|
#
|
12
|
-
#
|
12
|
+
# * Usage in library code for your application. Even though Rails will
|
13
13
|
# rescue from a `SystemExit` and continue on, unit testing that library
|
14
14
|
# code will result in specs exiting (potentially silently if `exit(0)`
|
15
15
|
# is used.)
|
16
|
-
#
|
16
|
+
# * Usage in application code outside of the web process could result in
|
17
17
|
# the program exiting, which could result in the code failing to run and
|
18
18
|
# do its job.
|
19
19
|
#
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
# change them to use keyword args. This cop only applies to Rails >= 5.
|
9
9
|
# If you are running Rails < 5 you should disable the
|
10
10
|
# Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your
|
11
|
-
# .rubocop.yml file to 4.
|
11
|
+
# .rubocop.yml file to 4.2.
|
12
12
|
#
|
13
13
|
# @example
|
14
14
|
# # bad
|
@@ -83,6 +83,7 @@ module RuboCop
|
|
83
83
|
'to define HTTP status code.'
|
84
84
|
|
85
85
|
attr_reader :node
|
86
|
+
|
86
87
|
def initialize(node)
|
87
88
|
@node = node
|
88
89
|
end
|
@@ -124,6 +125,7 @@ module RuboCop
|
|
124
125
|
PERMITTED_STATUS = %i[error success missing redirect].freeze
|
125
126
|
|
126
127
|
attr_reader :node
|
128
|
+
|
127
129
|
def initialize(node)
|
128
130
|
@node = node
|
129
131
|
end
|
@@ -129,10 +129,6 @@ module RuboCop
|
|
129
129
|
# @see https://guides.rubyonrails.org/association_basics.html#bi-directional-associations
|
130
130
|
# @see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses
|
131
131
|
class InverseOf < Cop
|
132
|
-
extend TargetRailsVersion
|
133
|
-
|
134
|
-
minimum_target_rails_version 4.1
|
135
|
-
|
136
132
|
SPECIFY_MSG = 'Specify an `:inverse_of` option.'
|
137
133
|
NIL_MSG = 'You specified `inverse_of: nil`, you probably meant to ' \
|
138
134
|
'use `inverse_of: false`.'
|
@@ -42,9 +42,7 @@ module RuboCop
|
|
42
42
|
|
43
43
|
option_nodes.map(&:children).each do |options|
|
44
44
|
blank = options.find { |o| blank_target?(o) }
|
45
|
-
if blank && options.none? { |o| includes_noopener?(o) }
|
46
|
-
add_offense(blank)
|
47
|
-
end
|
45
|
+
add_offense(blank) if blank && options.none? { |o| includes_noopener?(o) }
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop enforces the use `pick` over `pluck(...).first`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# Model.pluck(:a).first
|
11
|
+
# Model.pluck(:a, :b).first
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# Model.pick(:a)
|
15
|
+
# Model.pick(:a, :b)
|
16
|
+
class Pick < Cop
|
17
|
+
extend TargetRailsVersion
|
18
|
+
|
19
|
+
MSG = 'Prefer `pick(%<args>s)` over `pluck(%<args>s).first`.'
|
20
|
+
|
21
|
+
minimum_target_rails_version 6.0
|
22
|
+
|
23
|
+
def_node_matcher :pick_candidate?, <<~PATTERN
|
24
|
+
(send (send _ :pluck ...) :first)
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
pick_candidate?(node) do
|
29
|
+
range = node.receiver.loc.selector.join(node.loc.selector)
|
30
|
+
add_offense(node, location: range)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def autocorrect(node)
|
35
|
+
first_range = node.receiver.source_range.end.join(node.loc.selector)
|
36
|
+
|
37
|
+
lambda do |corrector|
|
38
|
+
corrector.remove(first_range)
|
39
|
+
corrector.replace(node.receiver.loc.selector, 'pick')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def message(node)
|
46
|
+
format(MSG, args: node.receiver.arguments.map(&:source).join(', '))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -76,15 +76,11 @@ module RuboCop
|
|
76
76
|
return if ignore_if_node?(node)
|
77
77
|
|
78
78
|
redundant_receiver_and_other(node) do |receiver, other|
|
79
|
-
unless ignore_other_node?(other) || receiver.nil?
|
80
|
-
add_offense(node, message: message(node, receiver, other))
|
81
|
-
end
|
79
|
+
add_offense(node, message: message(node, receiver, other)) unless ignore_other_node?(other) || receiver.nil?
|
82
80
|
end
|
83
81
|
|
84
82
|
redundant_negative_receiver_and_other(node) do |receiver, other|
|
85
|
-
unless ignore_other_node?(other) || receiver.nil?
|
86
|
-
add_offense(node, message: message(node, receiver, other))
|
87
|
-
end
|
83
|
+
add_offense(node, message: message(node, receiver, other)) unless ignore_other_node?(other) || receiver.nil?
|
88
84
|
end
|
89
85
|
end
|
90
86
|
|
@@ -41,8 +41,25 @@ module RuboCop
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def autocorrect(node)
|
45
|
+
lambda do |corrector|
|
46
|
+
task_name = node.arguments[0]
|
47
|
+
task_dependency = correct_task_dependency(task_name)
|
48
|
+
|
49
|
+
corrector.replace(task_name.loc.expression, task_dependency)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
44
53
|
private
|
45
54
|
|
55
|
+
def correct_task_dependency(task_name)
|
56
|
+
if task_name.sym_type?
|
57
|
+
task_name.source.delete(':|\'|"') + ': :environment'
|
58
|
+
else
|
59
|
+
"#{task_name.source} => :environment"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
46
63
|
def task_name(node)
|
47
64
|
first_arg = node.arguments[0]
|
48
65
|
case first_arg&.type
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop detects cases where the `:foreign_key` option on associations
|
7
|
+
# is redundant.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# class Post
|
12
|
+
# has_many :comments, foreign_key: 'post_id'
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# class Comment
|
16
|
+
# belongs_to :post, foreign_key: 'post_id'
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# class Post
|
21
|
+
# has_many :comments
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# class Comment
|
25
|
+
# belongs_to :author, foreign_key: 'user_id'
|
26
|
+
# end
|
27
|
+
class RedundantForeignKey < Cop
|
28
|
+
include RangeHelp
|
29
|
+
|
30
|
+
MSG = 'Specifying the default value for `foreign_key` is redundant.'
|
31
|
+
|
32
|
+
def_node_matcher :association_with_foreign_key, <<~PATTERN
|
33
|
+
(send nil? ${:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_)
|
34
|
+
$(hash <$(pair (sym :foreign_key) ({sym str} $_)) ...>)
|
35
|
+
)
|
36
|
+
PATTERN
|
37
|
+
|
38
|
+
def on_send(node)
|
39
|
+
association_with_foreign_key(node) do |type, name, options, foreign_key_pair, foreign_key|
|
40
|
+
if redundant?(node, type, name, options, foreign_key)
|
41
|
+
add_offense(node, location: foreign_key_pair.loc.expression)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def autocorrect(node)
|
47
|
+
_type, _name, _options, foreign_key_pair, _foreign_key = association_with_foreign_key(node)
|
48
|
+
range = range_with_surrounding_space(range: foreign_key_pair.source_range, side: :left)
|
49
|
+
range = range_with_surrounding_comma(range, :left)
|
50
|
+
|
51
|
+
lambda do |corrector|
|
52
|
+
corrector.remove(range)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def redundant?(node, association_type, association_name, options, foreign_key)
|
59
|
+
foreign_key.to_s == default_foreign_key(node, association_type, association_name, options)
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_foreign_key(node, association_type, association_name, options)
|
63
|
+
if association_type == :belongs_to
|
64
|
+
"#{association_name}_id"
|
65
|
+
elsif (as = find_as_option(options))
|
66
|
+
"#{as}_id"
|
67
|
+
else
|
68
|
+
node.parent_module_name&.foreign_key
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_as_option(options)
|
73
|
+
options.pairs.find do |pair|
|
74
|
+
pair.key.sym_type? && pair.key.value == :as
|
75
|
+
end&.value&.value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -55,11 +55,8 @@ module RuboCop
|
|
55
55
|
# end
|
56
56
|
# end
|
57
57
|
class RedundantReceiverInWithOptions < Cop
|
58
|
-
extend TargetRailsVersion
|
59
58
|
include RangeHelp
|
60
59
|
|
61
|
-
minimum_target_rails_version 4.2
|
62
|
-
|
63
60
|
MSG = 'Redundant receiver in `with_options`.'
|
64
61
|
|
65
62
|
def_node_matcher :with_options?, <<~PATTERN
|
@@ -9,14 +9,14 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# This will allow:
|
11
11
|
#
|
12
|
-
#
|
12
|
+
# * update or save calls, assigned to a variable,
|
13
13
|
# or used as a condition in an if/unless/case statement.
|
14
|
-
#
|
14
|
+
# * create calls, assigned to a variable that then has a
|
15
15
|
# call to `persisted?`, or whose return value is checked by
|
16
16
|
# `persisted?` immediately
|
17
|
-
#
|
17
|
+
# * calls if the result is explicitly returned from methods and blocks,
|
18
18
|
# or provided as arguments.
|
19
|
-
#
|
19
|
+
# * calls whose signature doesn't look like an ActiveRecord
|
20
20
|
# persistence method.
|
21
21
|
#
|
22
22
|
# By default it will also allow implicit returns from methods and blocks.
|
@@ -218,9 +218,7 @@ module RuboCop
|
|
218
218
|
def check_used_in_condition_or_compound_boolean(node)
|
219
219
|
return false unless in_condition_or_compound_boolean?(node)
|
220
220
|
|
221
|
-
unless MODIFY_PERSIST_METHODS.include?(node.method_name)
|
222
|
-
add_offense_for_node(node, CREATE_CONDITIONAL_MSG)
|
223
|
-
end
|
221
|
+
add_offense_for_node(node, CREATE_CONDITIONAL_MSG) unless MODIFY_PERSIST_METHODS.include?(node.method_name)
|
224
222
|
|
225
223
|
true
|
226
224
|
end
|
@@ -248,6 +246,7 @@ module RuboCop
|
|
248
246
|
|
249
247
|
def allowed_receiver?(node)
|
250
248
|
return false unless node.receiver
|
249
|
+
return true if node.receiver.const_name == 'ENV'
|
251
250
|
return false unless cop_config['AllowedReceivers']
|
252
251
|
|
253
252
|
cop_config['AllowedReceivers'].any? do |allowed_receiver|
|
@@ -50,7 +50,10 @@ module RuboCop
|
|
50
50
|
update_counters].freeze
|
51
51
|
|
52
52
|
def_node_matcher :good_touch?, <<~PATTERN
|
53
|
-
|
53
|
+
{
|
54
|
+
(send (const nil? :FileUtils) :touch ...)
|
55
|
+
(send _ :touch {true false})
|
56
|
+
}
|
54
57
|
PATTERN
|
55
58
|
|
56
59
|
def on_send(node)
|
@@ -85,9 +85,7 @@ module RuboCop
|
|
85
85
|
end
|
86
86
|
|
87
87
|
# prefer `Time` over `DateTime` class
|
88
|
-
if strict?
|
89
|
-
corrector.replace(node.children.first.source_range, 'Time')
|
90
|
-
end
|
88
|
+
corrector.replace(node.children.first.source_range, 'Time') if strict?
|
91
89
|
remove_redundant_in_time_zone(corrector, node)
|
92
90
|
end
|
93
91
|
end
|
@@ -3,50 +3,51 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
# Prefer the use of
|
6
|
+
# Prefer the use of distinct, before pluck instead of after.
|
7
7
|
#
|
8
|
-
# The use of
|
8
|
+
# The use of distinct before pluck is preferred because it executes within
|
9
9
|
# the database.
|
10
10
|
#
|
11
11
|
# This cop has two different enforcement modes. When the EnforcedStyle
|
12
12
|
# is conservative (the default) then only calls to pluck on a constant
|
13
|
-
# (i.e. a model class) before
|
13
|
+
# (i.e. a model class) before distinct are added as offenses.
|
14
14
|
#
|
15
15
|
# When the EnforcedStyle is aggressive then all calls to pluck before
|
16
|
-
#
|
17
|
-
# cannot distinguish between calls to pluck on an
|
18
|
-
# vs a call to pluck on an
|
16
|
+
# distinct are added as offenses. This may lead to false positives
|
17
|
+
# as the cop cannot distinguish between calls to pluck on an
|
18
|
+
# ActiveRecord::Relation vs a call to pluck on an
|
19
|
+
# ActiveRecord::Associations::CollectionProxy.
|
19
20
|
#
|
20
21
|
# Autocorrect is disabled by default for this cop since it may generate
|
21
22
|
# false positives.
|
22
23
|
#
|
23
24
|
# @example EnforcedStyle: conservative (default)
|
24
25
|
# # bad
|
25
|
-
# Model.pluck(:id).
|
26
|
+
# Model.pluck(:id).distinct
|
26
27
|
#
|
27
28
|
# # good
|
28
|
-
# Model.
|
29
|
+
# Model.distinct.pluck(:id)
|
29
30
|
#
|
30
31
|
# @example EnforcedStyle: aggressive
|
31
32
|
# # bad
|
32
33
|
# # this will return a Relation that pluck is called on
|
33
|
-
# Model.where(cond: true).pluck(:id).
|
34
|
+
# Model.where(cond: true).pluck(:id).distinct
|
34
35
|
#
|
35
36
|
# # bad
|
36
37
|
# # an association on an instance will return a CollectionProxy
|
37
|
-
# instance.assoc.pluck(:id).
|
38
|
+
# instance.assoc.pluck(:id).distinct
|
38
39
|
#
|
39
40
|
# # bad
|
40
|
-
# Model.pluck(:id).
|
41
|
+
# Model.pluck(:id).distinct
|
41
42
|
#
|
42
43
|
# # good
|
43
|
-
# Model.
|
44
|
+
# Model.distinct.pluck(:id)
|
44
45
|
#
|
45
46
|
class UniqBeforePluck < RuboCop::Cop::Cop
|
46
47
|
include ConfigurableEnforcedStyle
|
47
48
|
include RangeHelp
|
48
49
|
|
49
|
-
MSG = 'Use
|
50
|
+
MSG = 'Use `distinct` before `pluck`.'
|
50
51
|
NEWLINE = "\n"
|
51
52
|
PATTERN = '[!^block (send (send %<type>s :pluck ...) ' \
|
52
53
|
'${:uniq :distinct} ...)]'
|
@@ -66,8 +67,7 @@ module RuboCop
|
|
66
67
|
|
67
68
|
return unless method
|
68
69
|
|
69
|
-
add_offense(node, location: :selector
|
70
|
-
message: format(MSG, method: method))
|
70
|
+
add_offense(node, location: :selector)
|
71
71
|
end
|
72
72
|
|
73
73
|
def autocorrect(node)
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
75
75
|
method = node.method_name
|
76
76
|
|
77
77
|
corrector.remove(dot_method_with_whitespace(method, node))
|
78
|
-
corrector.insert_before(node.receiver.loc.dot.begin,
|
78
|
+
corrector.insert_before(node.receiver.loc.dot.begin, '.distinct')
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -15,8 +15,6 @@ module RuboCop
|
|
15
15
|
# Rails.env.production?
|
16
16
|
# Rails.env == 'production'
|
17
17
|
class UnknownEnv < Cop
|
18
|
-
include NameSimilarity
|
19
|
-
|
20
18
|
MSG = 'Unknown environment `%<name>s`.'
|
21
19
|
MSG_SIMILAR = 'Unknown environment `%<name>s`. ' \
|
22
20
|
'Did you mean `%<similar>s`?'
|
@@ -57,11 +55,14 @@ module RuboCop
|
|
57
55
|
|
58
56
|
def message(name)
|
59
57
|
name = name.to_s.chomp('?')
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
|
59
|
+
spell_checker = DidYouMean::SpellChecker.new(dictionary: environments)
|
60
|
+
similar_names = spell_checker.correct(name)
|
61
|
+
|
62
|
+
if similar_names.empty?
|
64
63
|
format(MSG, name: name)
|
64
|
+
else
|
65
|
+
format(MSG_SIMILAR, name: name, similar: similar_names.join(', '))
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
@@ -16,6 +16,7 @@ require_relative 'rails/assert_not'
|
|
16
16
|
require_relative 'rails/belongs_to'
|
17
17
|
require_relative 'rails/blank'
|
18
18
|
require_relative 'rails/bulk_change_table'
|
19
|
+
require_relative 'rails/content_tag'
|
19
20
|
require_relative 'rails/create_table_with_timestamps'
|
20
21
|
require_relative 'rails/date'
|
21
22
|
require_relative 'rails/delegate'
|
@@ -42,12 +43,14 @@ require_relative 'rails/link_to_blank'
|
|
42
43
|
require_relative 'rails/not_null_column'
|
43
44
|
require_relative 'rails/output'
|
44
45
|
require_relative 'rails/output_safety'
|
46
|
+
require_relative 'rails/pick'
|
45
47
|
require_relative 'rails/pluralization_grammar'
|
46
48
|
require_relative 'rails/presence'
|
47
49
|
require_relative 'rails/present'
|
48
50
|
require_relative 'rails/rake_environment'
|
49
51
|
require_relative 'rails/read_write_attribute'
|
50
52
|
require_relative 'rails/redundant_allow_nil'
|
53
|
+
require_relative 'rails/redundant_foreign_key'
|
51
54
|
require_relative 'rails/redundant_receiver_in_with_options'
|
52
55
|
require_relative 'rails/reflection_class_name'
|
53
56
|
require_relative 'rails/refute_methods'
|
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.
|
4
|
+
version: 2.6.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: 2020-
|
13
|
+
date: 2020-06-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -18,14 +18,14 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 4.2.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version:
|
28
|
+
version: 4.2.0
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: rack
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -46,14 +46,14 @@ dependencies:
|
|
46
46
|
requirements:
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: 0.
|
49
|
+
version: 0.82.0
|
50
50
|
type: :runtime
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
54
|
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: 0.
|
56
|
+
version: 0.82.0
|
57
57
|
description: |
|
58
58
|
Automatic Rails code style checking tool.
|
59
59
|
A RuboCop extension focused on enforcing Rails best practices and coding conventions.
|
@@ -84,6 +84,7 @@ files:
|
|
84
84
|
- lib/rubocop/cop/rails/belongs_to.rb
|
85
85
|
- lib/rubocop/cop/rails/blank.rb
|
86
86
|
- lib/rubocop/cop/rails/bulk_change_table.rb
|
87
|
+
- lib/rubocop/cop/rails/content_tag.rb
|
87
88
|
- lib/rubocop/cop/rails/create_table_with_timestamps.rb
|
88
89
|
- lib/rubocop/cop/rails/date.rb
|
89
90
|
- lib/rubocop/cop/rails/delegate.rb
|
@@ -110,12 +111,14 @@ files:
|
|
110
111
|
- lib/rubocop/cop/rails/not_null_column.rb
|
111
112
|
- lib/rubocop/cop/rails/output.rb
|
112
113
|
- lib/rubocop/cop/rails/output_safety.rb
|
114
|
+
- lib/rubocop/cop/rails/pick.rb
|
113
115
|
- lib/rubocop/cop/rails/pluralization_grammar.rb
|
114
116
|
- lib/rubocop/cop/rails/presence.rb
|
115
117
|
- lib/rubocop/cop/rails/present.rb
|
116
118
|
- lib/rubocop/cop/rails/rake_environment.rb
|
117
119
|
- lib/rubocop/cop/rails/read_write_attribute.rb
|
118
120
|
- lib/rubocop/cop/rails/redundant_allow_nil.rb
|
121
|
+
- lib/rubocop/cop/rails/redundant_foreign_key.rb
|
119
122
|
- lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb
|
120
123
|
- lib/rubocop/cop/rails/reflection_class_name.rb
|
121
124
|
- lib/rubocop/cop/rails/refute_methods.rb
|
@@ -142,10 +145,10 @@ homepage: https://github.com/rubocop-hq/rubocop-rails
|
|
142
145
|
licenses:
|
143
146
|
- MIT
|
144
147
|
metadata:
|
145
|
-
homepage_uri: https://docs.rubocop.org/
|
148
|
+
homepage_uri: https://docs.rubocop.org/rubocop-rails/
|
146
149
|
changelog_uri: https://github.com/rubocop-hq/rubocop-rails/blob/master/CHANGELOG.md
|
147
150
|
source_code_uri: https://github.com/rubocop-hq/rubocop-rails/
|
148
|
-
documentation_uri: https://docs.rubocop.org/
|
151
|
+
documentation_uri: https://docs.rubocop.org/rubocop-rails/
|
149
152
|
bug_tracker_uri: https://github.com/rubocop-hq/rubocop-rails/issues
|
150
153
|
post_install_message:
|
151
154
|
rdoc_options: []
|
@@ -155,14 +158,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
158
|
requirements:
|
156
159
|
- - ">="
|
157
160
|
- !ruby/object:Gem::Version
|
158
|
-
version: 2.
|
161
|
+
version: 2.4.0
|
159
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
163
|
requirements:
|
161
164
|
- - ">="
|
162
165
|
- !ruby/object:Gem::Version
|
163
166
|
version: '0'
|
164
167
|
requirements: []
|
165
|
-
rubygems_version: 3.1.
|
168
|
+
rubygems_version: 3.1.3
|
166
169
|
signing_key:
|
167
170
|
specification_version: 4
|
168
171
|
summary: Automatic Rails code style checking tool.
|