rubocop 1.47.0 → 1.48.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/README.md +1 -1
- data/config/default.yml +17 -0
- data/lib/rubocop/cop/lint/missing_super.rb +3 -3
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +9 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +3 -2
- data/lib/rubocop/cop/mixin/min_branches_count.rb +40 -0
- data/lib/rubocop/cop/registry.rb +3 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +9 -0
- data/lib/rubocop/cop/style/case_like_if.rb +19 -2
- data/lib/rubocop/cop/style/dir_empty.rb +60 -0
- data/lib/rubocop/cop/style/documentation.rb +9 -3
- data/lib/rubocop/cop/style/file_empty.rb +71 -0
- data/lib/rubocop/cop/style/hash_like_case.rb +3 -9
- data/lib/rubocop/cop/style/if_unless_modifier.rb +42 -9
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -0
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +11 -6
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/formatter/junit_formatter.rb +4 -1
- data/lib/rubocop/server/core.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb25d50ecbd2f942993d245b3302d53cf3605fa362e0addf1ee088caaa22bfff
|
4
|
+
data.tar.gz: 62df82b33ce3ae669b7fd23ca69f1a53f9dbbcd480d44cfff763df3c84c39585
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 563e301ae73973fd6ccb3679ce82fe15a02d6634c7993bfab9f0c15ae29687982ac63ec07f656be22273e6b5c63cd2686b678cdc3319536b51d086103ec60fcd
|
7
|
+
data.tar.gz: eb24bb4636f91c76715a81896852d6620306ac45e52755cc5c2148ff0f85d1012ebe7b043076a802259bf1d130fc4296d55b70f4d99816aba39056fa05205b16
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
53
53
|
in your `Gemfile`:
|
54
54
|
|
55
55
|
```rb
|
56
|
-
gem 'rubocop', '~> 1.
|
56
|
+
gem 'rubocop', '~> 1.48', require: false
|
57
57
|
```
|
58
58
|
|
59
59
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -3261,6 +3261,9 @@ Style/CaseLikeIf:
|
|
3261
3261
|
Enabled: true
|
3262
3262
|
Safe: false
|
3263
3263
|
VersionAdded: '0.88'
|
3264
|
+
VersionChanged: '1.48'
|
3265
|
+
# `MinBranchesCount` defines the number of branches `if` needs to have to trigger this cop.
|
3266
|
+
MinBranchesCount: 3
|
3264
3267
|
|
3265
3268
|
Style/CharacterLiteral:
|
3266
3269
|
Description: 'Checks for uses of character literals.'
|
@@ -3527,6 +3530,12 @@ Style/Dir:
|
|
3527
3530
|
Enabled: true
|
3528
3531
|
VersionAdded: '0.50'
|
3529
3532
|
|
3533
|
+
Style/DirEmpty:
|
3534
|
+
Description: >-
|
3535
|
+
Prefer to use `Dir.empty?('path/to/dir')` when checking if a directory is empty.
|
3536
|
+
Enabled: pending
|
3537
|
+
VersionAdded: '1.48'
|
3538
|
+
|
3530
3539
|
Style/DisableCopsWithinSourceCodeDirective:
|
3531
3540
|
Description: >-
|
3532
3541
|
Forbids disabling/enabling cops within source code.
|
@@ -3722,6 +3731,14 @@ Style/FetchEnvVar:
|
|
3722
3731
|
# Environment variables to be excluded from the inspection.
|
3723
3732
|
AllowedVars: []
|
3724
3733
|
|
3734
|
+
Style/FileEmpty:
|
3735
|
+
Description: >-
|
3736
|
+
Prefer to use `File.empty?('path/to/file')` when checking if a file is empty.
|
3737
|
+
Enabled: pending
|
3738
|
+
Safe: false
|
3739
|
+
SafeAutoCorrect: false
|
3740
|
+
VersionAdded: '1.48'
|
3741
|
+
|
3725
3742
|
Style/FileRead:
|
3726
3743
|
Description: 'Favor `File.(bin)read` convenience methods.'
|
3727
3744
|
StyleGuide: '#file-read'
|
@@ -110,12 +110,12 @@ module RuboCop
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def inside_class_with_stateful_parent?(node)
|
113
|
-
if (
|
114
|
-
class_node.parent_class && !stateless_class?(class_node.parent_class)
|
115
|
-
elsif (block_node = node.each_ancestor(:block, :numblock).first)
|
113
|
+
if (block_node = node.each_ancestor(:block, :numblock).first)
|
116
114
|
return false unless (super_class = class_new_block(block_node))
|
117
115
|
|
118
116
|
!stateless_class?(super_class)
|
117
|
+
elsif (class_node = node.each_ancestor(:class).first)
|
118
|
+
class_node.parent_class && !stateless_class?(class_node.parent_class)
|
119
119
|
else
|
120
120
|
false
|
121
121
|
end
|
@@ -137,7 +137,7 @@ module RuboCop
|
|
137
137
|
alias on_sclass on_class
|
138
138
|
|
139
139
|
def on_block(node)
|
140
|
-
return unless eval_call?(node)
|
140
|
+
return unless eval_call?(node) || included_block?(node)
|
141
141
|
|
142
142
|
check_node(node.body)
|
143
143
|
end
|
@@ -192,10 +192,13 @@ module RuboCop
|
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
195
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
195
196
|
def check_child_nodes(node, unused, cur_vis)
|
196
197
|
node.child_nodes.each do |child|
|
197
198
|
if child.send_type? && access_modifier?(child)
|
198
199
|
cur_vis, unused = check_send_node(child, cur_vis, unused)
|
200
|
+
elsif child.block_type? && included_block?(child)
|
201
|
+
next
|
199
202
|
elsif method_definition?(child)
|
200
203
|
unused = nil
|
201
204
|
elsif start_of_new_scope?(child)
|
@@ -207,6 +210,7 @@ module RuboCop
|
|
207
210
|
|
208
211
|
[cur_vis, unused]
|
209
212
|
end
|
213
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
210
214
|
|
211
215
|
def check_send_node(node, cur_vis, unused)
|
212
216
|
if node.bare_access_modifier?
|
@@ -240,6 +244,10 @@ module RuboCop
|
|
240
244
|
[new_vis, unused]
|
241
245
|
end
|
242
246
|
|
247
|
+
def included_block?(block_node)
|
248
|
+
active_support_extensions_enabled? && block_node.method?(:included)
|
249
|
+
end
|
250
|
+
|
243
251
|
def method_definition?(child)
|
244
252
|
static_method_definition?(child) ||
|
245
253
|
dynamic_method_definition?(child) ||
|
@@ -95,19 +95,20 @@ module RuboCop
|
|
95
95
|
use_modifier_form_without_parenthesized_method_call?(method_dispatch_node)
|
96
96
|
end
|
97
97
|
|
98
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
98
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
99
99
|
def def_node_that_require_parentheses(node)
|
100
100
|
last_pair = node.parent.pairs.last
|
101
101
|
return unless last_pair.key.source == last_pair.value.source
|
102
102
|
return unless (dispatch_node = find_ancestor_method_dispatch_node(node))
|
103
103
|
return if dispatch_node.parenthesized?
|
104
|
+
return if dispatch_node.parent && parentheses?(dispatch_node.parent)
|
104
105
|
return if last_expression?(dispatch_node) && !method_dispatch_as_argument?(dispatch_node)
|
105
106
|
|
106
107
|
def_node = node.each_ancestor(:send, :csend, :super, :yield).first
|
107
108
|
|
108
109
|
DefNode.new(def_node) unless def_node && def_node.arguments.empty?
|
109
110
|
end
|
110
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
111
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
111
112
|
|
112
113
|
def find_ancestor_method_dispatch_node(node)
|
113
114
|
return unless (ancestor = node.parent.parent)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for checking minimum branches count.
|
6
|
+
module MinBranchesCount
|
7
|
+
private
|
8
|
+
|
9
|
+
def min_branches_count?(node)
|
10
|
+
branches =
|
11
|
+
if node.case_type?
|
12
|
+
node.when_branches
|
13
|
+
elsif node.if_type?
|
14
|
+
if_conditional_branches(node)
|
15
|
+
else
|
16
|
+
raise ArgumentError, "Unsupported #{node.type.inspect} node type"
|
17
|
+
end
|
18
|
+
|
19
|
+
branches.size >= min_branches_count
|
20
|
+
end
|
21
|
+
|
22
|
+
def min_branches_count
|
23
|
+
length = cop_config['MinBranchesCount'] || 3
|
24
|
+
return length if length.is_a?(Integer) && length.positive?
|
25
|
+
|
26
|
+
raise 'MinBranchesCount needs to be a positive integer!'
|
27
|
+
end
|
28
|
+
|
29
|
+
def if_conditional_branches(node, branches = [])
|
30
|
+
return [] if node.nil? || !node.if_type?
|
31
|
+
|
32
|
+
branches << node.if_branch
|
33
|
+
|
34
|
+
else_branch = node.else_branch
|
35
|
+
if_conditional_branches(else_branch, branches) if else_branch&.if_type?
|
36
|
+
branches
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -197,7 +197,9 @@ module RuboCop
|
|
197
197
|
def enabled?(cop, config)
|
198
198
|
return true if options[:only]&.include?(cop.cop_name)
|
199
199
|
|
200
|
-
|
200
|
+
# We need to use `cop_name` in this case, because `for_cop` uses caching
|
201
|
+
# which expects cop names or cop classes as keys.
|
202
|
+
cfg = config.for_cop(cop.cop_name)
|
201
203
|
|
202
204
|
cop_enabled = cfg.fetch('Enabled') == true || enabled_pending_cop?(cfg, config)
|
203
205
|
|
@@ -14,12 +14,13 @@ module RuboCop
|
|
14
14
|
# # bad
|
15
15
|
# class Foo
|
16
16
|
# attr_reader :bar
|
17
|
+
# attr_reader :bax
|
17
18
|
# attr_reader :baz
|
18
19
|
# end
|
19
20
|
#
|
20
21
|
# # good
|
21
22
|
# class Foo
|
22
|
-
# attr_reader :bar, :baz
|
23
|
+
# attr_reader :bar, :bax, :baz
|
23
24
|
# end
|
24
25
|
#
|
25
26
|
# # good
|
@@ -27,6 +28,9 @@ module RuboCop
|
|
27
28
|
# # may be intended comment for bar.
|
28
29
|
# attr_reader :bar
|
29
30
|
#
|
31
|
+
# sig { returns(String) }
|
32
|
+
# attr_reader :bax
|
33
|
+
#
|
30
34
|
# may_be_intended_annotation :baz
|
31
35
|
# attr_reader :baz
|
32
36
|
# end
|
@@ -90,6 +94,14 @@ module RuboCop
|
|
90
94
|
|
91
95
|
def groupable_accessor?(node)
|
92
96
|
return true unless (previous_expression = node.left_siblings.last)
|
97
|
+
|
98
|
+
# Accessors with Sorbet `sig { ... }` blocks shouldn't be groupable.
|
99
|
+
if previous_expression.block_type?
|
100
|
+
previous_expression.child_nodes.each do |child_node|
|
101
|
+
break previous_expression = child_node if child_node.send_type?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
93
105
|
return true unless previous_expression.send_type?
|
94
106
|
|
95
107
|
previous_expression.attribute_accessor? || previous_expression.access_modifier?
|
@@ -342,6 +342,7 @@ module RuboCop
|
|
342
342
|
end
|
343
343
|
|
344
344
|
def proper_block_style?(node)
|
345
|
+
return true if require_braces?(node)
|
345
346
|
return special_method_proper_block_style?(node) if special_method?(node.method_name)
|
346
347
|
|
347
348
|
case style
|
@@ -352,6 +353,14 @@ module RuboCop
|
|
352
353
|
end
|
353
354
|
end
|
354
355
|
|
356
|
+
def require_braces?(node)
|
357
|
+
return false unless node.braces?
|
358
|
+
|
359
|
+
node.each_ancestor(:send).any? do |send|
|
360
|
+
send.arithmetic_operation? && node.source_range.end_pos < send.loc.selector.begin_pos
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
355
364
|
def special_method?(method_name)
|
356
365
|
allowed_method?(method_name) ||
|
357
366
|
matches_allowed_pattern?(method_name) ||
|
@@ -11,12 +11,14 @@ module RuboCop
|
|
11
11
|
# so if the original conditional used a different equality operator, the
|
12
12
|
# behavior may be different.
|
13
13
|
#
|
14
|
-
# @example
|
14
|
+
# @example MinBranchesCount: 3 (default)
|
15
15
|
# # bad
|
16
16
|
# if status == :active
|
17
17
|
# perform_action
|
18
18
|
# elsif status == :inactive || status == :hibernating
|
19
19
|
# check_timeout
|
20
|
+
# elsif status == :invalid
|
21
|
+
# report_invalid
|
20
22
|
# else
|
21
23
|
# final_action
|
22
24
|
# end
|
@@ -27,12 +29,27 @@ module RuboCop
|
|
27
29
|
# perform_action
|
28
30
|
# when :inactive, :hibernating
|
29
31
|
# check_timeout
|
32
|
+
# when :invalid
|
33
|
+
# report_invalid
|
34
|
+
# else
|
35
|
+
# final_action
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @example MinBranchesCount: 4
|
39
|
+
# # good
|
40
|
+
# if status == :active
|
41
|
+
# perform_action
|
42
|
+
# elsif status == :inactive || status == :hibernating
|
43
|
+
# check_timeout
|
44
|
+
# elsif status == :invalid
|
45
|
+
# report_invalid
|
30
46
|
# else
|
31
47
|
# final_action
|
32
48
|
# end
|
33
49
|
#
|
34
50
|
class CaseLikeIf < Base
|
35
51
|
include RangeHelp
|
52
|
+
include MinBranchesCount
|
36
53
|
extend AutoCorrector
|
37
54
|
|
38
55
|
MSG = 'Convert `if-elsif` to `case-when`.'
|
@@ -78,7 +95,7 @@ module RuboCop
|
|
78
95
|
|
79
96
|
def should_check?(node)
|
80
97
|
!node.unless? && !node.elsif? && !node.modifier_form? && !node.ternary? &&
|
81
|
-
node.elsif_conditional?
|
98
|
+
node.elsif_conditional? && min_branches_count?(node)
|
82
99
|
end
|
83
100
|
|
84
101
|
# rubocop:disable Metrics/MethodLength
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Prefer to use `Dir.empty?('path/to/dir')` when checking if a directory is empty.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# Dir.entries('path/to/dir').size == 2
|
11
|
+
# Dir.children('path/to/dir').empty?
|
12
|
+
# Dir.children('path/to/dir').size == 0
|
13
|
+
# Dir.each_child('path/to/dir').none?
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# Dir.empty?('path/to/dir')
|
17
|
+
#
|
18
|
+
class DirEmpty < Base
|
19
|
+
extend AutoCorrector
|
20
|
+
extend TargetRubyVersion
|
21
|
+
|
22
|
+
MSG = 'Use `Dir.empty?(%<arg>s)` instead.'
|
23
|
+
RESTRICT_ON_SEND = %i[== > empty? none?].freeze
|
24
|
+
|
25
|
+
minimum_target_ruby_version 2.4
|
26
|
+
|
27
|
+
# @!method offensive?(node)
|
28
|
+
def_node_matcher :offensive?, <<~PATTERN
|
29
|
+
{
|
30
|
+
(send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :>} (int 2))
|
31
|
+
(send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :>} (int 0))
|
32
|
+
(send (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) :!) {:== :>} (int 2))
|
33
|
+
(send (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) :!) {:== :>} (int 0))
|
34
|
+
(send (send $(const {nil? cbase} :Dir) :children $_) :empty?)
|
35
|
+
(send (send $(const {nil? cbase} :Dir) :each_child $_) :none?)
|
36
|
+
}
|
37
|
+
PATTERN
|
38
|
+
|
39
|
+
def on_send(node)
|
40
|
+
offensive?(node) do |const_node, arg_node|
|
41
|
+
add_offense(node, message: format(MSG, arg: arg_node.source)) do |corrector|
|
42
|
+
bang(node)
|
43
|
+
corrector.replace(node,
|
44
|
+
"#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def bang(node)
|
52
|
+
if (node.method?(:==) && node.child_nodes.first.method?(:!)) ||
|
53
|
+
(node.method?(:>) && !node.child_nodes.first.method?(:!))
|
54
|
+
'!'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -178,13 +178,19 @@ module RuboCop
|
|
178
178
|
def identifier(node)
|
179
179
|
# Get the fully qualified identifier for a class/module
|
180
180
|
nodes = [node, *node.each_ancestor(:class, :module)]
|
181
|
-
nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
|
181
|
+
identifier = nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
|
182
|
+
|
183
|
+
identifier.sub('::::', '::')
|
182
184
|
end
|
183
185
|
|
184
186
|
def qualify_const(node)
|
185
|
-
return if node.nil?
|
187
|
+
return if node.nil?
|
186
188
|
|
187
|
-
|
189
|
+
if node.cbase_type? || node.self_type? || node.call_type? || node.variable?
|
190
|
+
node.source
|
191
|
+
else
|
192
|
+
[qualify_const(node.namespace), node.short_name].compact
|
193
|
+
end
|
188
194
|
end
|
189
195
|
end
|
190
196
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Prefer to use `File.empty?('path/to/file')` when checking if a file is empty.
|
7
|
+
#
|
8
|
+
# @safety
|
9
|
+
# This cop's autocorrection is unsafe it because `File.size`, `File.read`,
|
10
|
+
# and `File.binread` raise `ENOENT` exception when there is no file
|
11
|
+
# corresponding to the path, while `File.empty?` does not raise an exception.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # bad
|
15
|
+
# File.zero?('path/to/file')
|
16
|
+
# File.size('path/to/file') == 0
|
17
|
+
# File.size('path/to/file') >= 0
|
18
|
+
# File.size('path/to/file').zero?
|
19
|
+
# File.read('path/to/file').empty?
|
20
|
+
# File.binread('path/to/file') == ''
|
21
|
+
# FileTest.zero?('path/to/file')
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# File.empty?('path/to/file')
|
25
|
+
# FileTest.empty?('path/to/file')
|
26
|
+
#
|
27
|
+
class FileEmpty < Base
|
28
|
+
extend AutoCorrector
|
29
|
+
extend TargetRubyVersion
|
30
|
+
|
31
|
+
MSG = 'Use `%<file_class>s.empty?(%<arg>s)` instead.'
|
32
|
+
RESTRICT_ON_SEND = %i[>= != == zero? empty?].freeze
|
33
|
+
|
34
|
+
minimum_target_ruby_version 2.4
|
35
|
+
|
36
|
+
# @!method offensive?(node)
|
37
|
+
def_node_matcher :offensive?, <<~PATTERN
|
38
|
+
{
|
39
|
+
(send $(const {nil? cbase} {:File :FileTest}) :zero? $_)
|
40
|
+
(send (send $(const {nil? cbase} {:File :FileTest}) :size $_) {:== :>=} (int 0))
|
41
|
+
(send (send (send $(const {nil? cbase} {:File :FileTest}) :size $_) :!) {:== :>=} (int 0))
|
42
|
+
(send (send $(const {nil? cbase} {:File :FileTest}) :size $_) :zero?)
|
43
|
+
(send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) {:!= :==} (str empty?))
|
44
|
+
(send (send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) :!) {:!= :==} (str empty?))
|
45
|
+
(send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) :empty?)
|
46
|
+
}
|
47
|
+
PATTERN
|
48
|
+
|
49
|
+
def on_send(node)
|
50
|
+
offensive?(node) do |const_node, arg_node|
|
51
|
+
add_offense(node,
|
52
|
+
message: format(MSG, file_class: const_node.source,
|
53
|
+
arg: arg_node.source)) do |corrector|
|
54
|
+
corrector.replace(node,
|
55
|
+
"#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def bang(node)
|
63
|
+
if (node.method?(:==) && node.child_nodes.first.method?(:!)) ||
|
64
|
+
(%i[>= !=].include?(node.method_name) && !node.child_nodes.first.method?(:!))
|
65
|
+
'!'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -37,6 +37,8 @@ module RuboCop
|
|
37
37
|
# end
|
38
38
|
#
|
39
39
|
class HashLikeCase < Base
|
40
|
+
include MinBranchesCount
|
41
|
+
|
40
42
|
MSG = 'Consider replacing `case-when` with a hash lookup.'
|
41
43
|
|
42
44
|
# @!method hash_like_case?(node)
|
@@ -49,7 +51,7 @@ module RuboCop
|
|
49
51
|
PATTERN
|
50
52
|
|
51
53
|
def on_case(node)
|
52
|
-
return
|
54
|
+
return unless min_branches_count?(node)
|
53
55
|
|
54
56
|
hash_like_case?(node) do |condition_nodes, body_nodes|
|
55
57
|
if nodes_of_same_type?(condition_nodes) && nodes_of_same_type?(body_nodes)
|
@@ -63,14 +65,6 @@ module RuboCop
|
|
63
65
|
def nodes_of_same_type?(nodes)
|
64
66
|
nodes.all? { |node| node.type == nodes.first.type }
|
65
67
|
end
|
66
|
-
|
67
|
-
def min_branches_count
|
68
|
-
length = cop_config['MinBranchesCount'] || 3
|
69
|
-
return length if length.is_a?(Integer) && length.positive?
|
70
|
-
|
71
|
-
warn Rainbow('`MinBranchesCount` needs to be a positive integer!').red
|
72
|
-
exit!
|
73
|
-
end
|
74
68
|
end
|
75
69
|
end
|
76
70
|
end
|
@@ -53,6 +53,7 @@ module RuboCop
|
|
53
53
|
include LineLengthHelp
|
54
54
|
include AllowedPattern
|
55
55
|
include RangeHelp
|
56
|
+
include CommentsHelp
|
56
57
|
extend AutoCorrector
|
57
58
|
|
58
59
|
MSG_USE_MODIFIER = 'Favor modifier `%<keyword>s` usage when having a ' \
|
@@ -101,26 +102,43 @@ module RuboCop
|
|
101
102
|
|
102
103
|
def autocorrect(corrector, node)
|
103
104
|
replacement = if node.modifier_form?
|
104
|
-
|
105
|
-
|
106
|
-
if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
|
107
|
-
heredoc = extract_heredoc_from(last_argument)
|
108
|
-
remove_heredoc(corrector, heredoc)
|
109
|
-
to_normal_form_with_heredoc(node, indent(node), heredoc)
|
110
|
-
else
|
111
|
-
to_normal_form(node, indent(node))
|
112
|
-
end
|
105
|
+
replacement_for_modifier_form(corrector, node)
|
113
106
|
else
|
114
107
|
to_modifier_form(node)
|
115
108
|
end
|
116
109
|
corrector.replace(node, replacement)
|
117
110
|
end
|
118
111
|
|
112
|
+
def replacement_for_modifier_form(corrector, node) # rubocop:disable Metrics/AbcSize
|
113
|
+
comment = comment_on_node_line(node)
|
114
|
+
if comment && too_long_due_to_comment_after_modifier?(node, comment)
|
115
|
+
remove_comment(corrector, node, comment)
|
116
|
+
|
117
|
+
return to_modifier_form_with_move_comment(node, indent(node), comment)
|
118
|
+
end
|
119
|
+
|
120
|
+
last_argument = node.if_branch.last_argument if node.if_branch.send_type?
|
121
|
+
if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
|
122
|
+
heredoc = extract_heredoc_from(last_argument)
|
123
|
+
remove_heredoc(corrector, heredoc)
|
124
|
+
|
125
|
+
return to_normal_form_with_heredoc(node, indent(node), heredoc)
|
126
|
+
end
|
127
|
+
|
128
|
+
to_normal_form(node, indent(node))
|
129
|
+
end
|
130
|
+
|
119
131
|
def too_long_due_to_modifier?(node)
|
120
132
|
node.modifier_form? && too_long_single_line?(node) &&
|
121
133
|
!another_statement_on_same_line?(node)
|
122
134
|
end
|
123
135
|
|
136
|
+
def too_long_due_to_comment_after_modifier?(node, comment)
|
137
|
+
source_length = processed_source.lines[node.first_line - 1].length
|
138
|
+
source_length >= max_line_length &&
|
139
|
+
source_length - comment.source_range.length <= max_line_length
|
140
|
+
end
|
141
|
+
|
124
142
|
def allowed_patterns
|
125
143
|
line_length_config = config.for_cop('Layout/LineLength')
|
126
144
|
line_length_config['AllowedPatterns'] || line_length_config['IgnoredPatterns'] || []
|
@@ -215,6 +233,13 @@ module RuboCop
|
|
215
233
|
RUBY
|
216
234
|
end
|
217
235
|
|
236
|
+
def to_modifier_form_with_move_comment(node, indentation, comment)
|
237
|
+
<<~RUBY.chomp
|
238
|
+
#{comment.source}
|
239
|
+
#{indentation}#{node.body.source} #{node.keyword} #{node.condition.source}
|
240
|
+
RUBY
|
241
|
+
end
|
242
|
+
|
218
243
|
def extract_heredoc_from(last_argument)
|
219
244
|
heredoc_body = last_argument.loc.heredoc_body
|
220
245
|
heredoc_end = last_argument.loc.heredoc_end
|
@@ -227,6 +252,14 @@ module RuboCop
|
|
227
252
|
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
228
253
|
end
|
229
254
|
end
|
255
|
+
|
256
|
+
def comment_on_node_line(node)
|
257
|
+
processed_source.comments.find { |c| same_line?(c, node) }
|
258
|
+
end
|
259
|
+
|
260
|
+
def remove_comment(corrector, _node, comment)
|
261
|
+
corrector.remove(range_with_surrounding_space(range: comment.source_range, side: :left))
|
262
|
+
end
|
230
263
|
end
|
231
264
|
end
|
232
265
|
end
|
@@ -48,13 +48,11 @@ module RuboCop
|
|
48
48
|
|
49
49
|
def on_if(node)
|
50
50
|
return unless if_else?(node)
|
51
|
-
|
52
|
-
condition = unwrap_begin_nodes(node.condition)
|
53
|
-
|
51
|
+
return unless (condition = unwrap_begin_nodes(node.condition))
|
54
52
|
return if double_negation?(condition) || !negated_condition?(condition)
|
55
53
|
|
56
|
-
|
57
|
-
add_offense(node, message:
|
54
|
+
message = message(node)
|
55
|
+
add_offense(node, message: message) do |corrector|
|
58
56
|
unless corrected_ancestor?(node)
|
59
57
|
correct_negated_condition(corrector, condition)
|
60
58
|
swap_branches(corrector, node)
|
@@ -73,7 +71,8 @@ module RuboCop
|
|
73
71
|
end
|
74
72
|
|
75
73
|
def unwrap_begin_nodes(node)
|
76
|
-
node = node.children.first while node.begin_type? || node.kwbegin_type?
|
74
|
+
node = node.children.first while node && (node.begin_type? || node.kwbegin_type?)
|
75
|
+
|
77
76
|
node
|
78
77
|
end
|
79
78
|
|
@@ -82,6 +81,12 @@ module RuboCop
|
|
82
81
|
(node.negation_method? || NEGATED_EQUALITY_METHODS.include?(node.method_name))
|
83
82
|
end
|
84
83
|
|
84
|
+
def message(node)
|
85
|
+
type = node.ternary? ? 'ternary' : 'if-else'
|
86
|
+
|
87
|
+
format(MSG, type: type)
|
88
|
+
end
|
89
|
+
|
85
90
|
def corrected_ancestor?(node)
|
86
91
|
node.each_ancestor(:if).any? { |ancestor| @corrected_nodes&.include?(ancestor) }
|
87
92
|
end
|
data/lib/rubocop/cop/team.rb
CHANGED
@@ -160,8 +160,8 @@ module RuboCop
|
|
160
160
|
def roundup_relevant_cops(processed_source)
|
161
161
|
cops.select do |cop|
|
162
162
|
next true if processed_source.comment_config.cop_opted_in?(cop)
|
163
|
-
next false unless @registry.enabled?(cop, @config)
|
164
163
|
next false if cop.excluded_file?(processed_source.file_path)
|
164
|
+
next false unless @registry.enabled?(cop, @config)
|
165
165
|
|
166
166
|
support_target_ruby_version?(cop) && support_target_rails_version?(cop)
|
167
167
|
end
|
@@ -62,7 +62,10 @@ module RuboCop
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def classname_attribute_value(file)
|
65
|
-
|
65
|
+
@classname_attribute_value_cache ||= Hash.new do |hash, key|
|
66
|
+
hash[key] = key.gsub(/\.rb\Z/, '').gsub("#{Dir.pwd}/", '').tr('/', '.')
|
67
|
+
end
|
68
|
+
@classname_attribute_value_cache[file]
|
66
69
|
end
|
67
70
|
|
68
71
|
def finished(_inspected_files)
|
data/lib/rubocop/server/core.rb
CHANGED
@@ -100,7 +100,7 @@ module RuboCop
|
|
100
100
|
|
101
101
|
def use_json_format?
|
102
102
|
return true if ARGV.include?('--format=json') || ARGV.include?('--format=j')
|
103
|
-
return false unless (index = ARGV.index('--format'))
|
103
|
+
return false unless (index = ARGV.index('--format') || ARGV.index('-f'))
|
104
104
|
|
105
105
|
format = ARGV[index + 1]
|
106
106
|
|
data/lib/rubocop/version.rb
CHANGED
data/lib/rubocop.rb
CHANGED
@@ -102,6 +102,7 @@ require_relative 'rubocop/cop/mixin/hash_shorthand_syntax'
|
|
102
102
|
require_relative 'rubocop/cop/mixin/method_complexity'
|
103
103
|
require_relative 'rubocop/cop/mixin/method_preference'
|
104
104
|
require_relative 'rubocop/cop/mixin/min_body_length'
|
105
|
+
require_relative 'rubocop/cop/mixin/min_branches_count'
|
105
106
|
require_relative 'rubocop/cop/mixin/multiline_element_indentation'
|
106
107
|
require_relative 'rubocop/cop/mixin/multiline_element_line_breaks'
|
107
108
|
require_relative 'rubocop/cop/mixin/multiline_expression_indentation'
|
@@ -482,6 +483,7 @@ require_relative 'rubocop/cop/style/copyright'
|
|
482
483
|
require_relative 'rubocop/cop/style/date_time'
|
483
484
|
require_relative 'rubocop/cop/style/def_with_parentheses'
|
484
485
|
require_relative 'rubocop/cop/style/dir'
|
486
|
+
require_relative 'rubocop/cop/style/dir_empty'
|
485
487
|
require_relative 'rubocop/cop/style/disable_cops_within_source_code_directive'
|
486
488
|
require_relative 'rubocop/cop/style/documentation_method'
|
487
489
|
require_relative 'rubocop/cop/style/documentation'
|
@@ -507,6 +509,7 @@ require_relative 'rubocop/cop/style/expand_path_arguments'
|
|
507
509
|
require_relative 'rubocop/cop/style/explicit_block_argument'
|
508
510
|
require_relative 'rubocop/cop/style/exponential_notation'
|
509
511
|
require_relative 'rubocop/cop/style/fetch_env_var'
|
512
|
+
require_relative 'rubocop/cop/style/file_empty'
|
510
513
|
require_relative 'rubocop/cop/style/file_read'
|
511
514
|
require_relative 'rubocop/cop/style/file_write'
|
512
515
|
require_relative 'rubocop/cop/style/float_division'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.48.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-03-
|
13
|
+
date: 2023-03-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
@@ -584,6 +584,7 @@ files:
|
|
584
584
|
- lib/rubocop/cop/mixin/method_complexity.rb
|
585
585
|
- lib/rubocop/cop/mixin/method_preference.rb
|
586
586
|
- lib/rubocop/cop/mixin/min_body_length.rb
|
587
|
+
- lib/rubocop/cop/mixin/min_branches_count.rb
|
587
588
|
- lib/rubocop/cop/mixin/multiline_element_indentation.rb
|
588
589
|
- lib/rubocop/cop/mixin/multiline_element_line_breaks.rb
|
589
590
|
- lib/rubocop/cop/mixin/multiline_expression_indentation.rb
|
@@ -685,6 +686,7 @@ files:
|
|
685
686
|
- lib/rubocop/cop/style/date_time.rb
|
686
687
|
- lib/rubocop/cop/style/def_with_parentheses.rb
|
687
688
|
- lib/rubocop/cop/style/dir.rb
|
689
|
+
- lib/rubocop/cop/style/dir_empty.rb
|
688
690
|
- lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb
|
689
691
|
- lib/rubocop/cop/style/document_dynamic_eval_definition.rb
|
690
692
|
- lib/rubocop/cop/style/documentation.rb
|
@@ -710,6 +712,7 @@ files:
|
|
710
712
|
- lib/rubocop/cop/style/explicit_block_argument.rb
|
711
713
|
- lib/rubocop/cop/style/exponential_notation.rb
|
712
714
|
- lib/rubocop/cop/style/fetch_env_var.rb
|
715
|
+
- lib/rubocop/cop/style/file_empty.rb
|
713
716
|
- lib/rubocop/cop/style/file_read.rb
|
714
717
|
- lib/rubocop/cop/style/file_write.rb
|
715
718
|
- lib/rubocop/cop/style/float_division.rb
|
@@ -985,7 +988,7 @@ metadata:
|
|
985
988
|
homepage_uri: https://rubocop.org/
|
986
989
|
changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md
|
987
990
|
source_code_uri: https://github.com/rubocop/rubocop/
|
988
|
-
documentation_uri: https://docs.rubocop.org/rubocop/1.
|
991
|
+
documentation_uri: https://docs.rubocop.org/rubocop/1.48/
|
989
992
|
bug_tracker_uri: https://github.com/rubocop/rubocop/issues
|
990
993
|
rubygems_mfa_required: 'true'
|
991
994
|
post_install_message:
|