rubocop 0.65.0 → 0.66.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 +3 -3
- data/config/default.yml +53 -4
- data/lib/rubocop.rb +4 -5
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +3 -5
- data/lib/rubocop/cop/layout/class_structure.rb +59 -28
- data/lib/rubocop/cop/layout/extra_spacing.rb +18 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +25 -5
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +33 -17
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +30 -11
- data/lib/rubocop/cop/lint/else_layout.rb +1 -0
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +38 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +14 -1
- data/lib/rubocop/cop/lint/to_json.rb +38 -0
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/message_annotator.rb +4 -4
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -0
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +31 -9
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/integer_node.rb +1 -1
- data/lib/rubocop/cop/mixin/method_preference.rb +2 -1
- data/lib/rubocop/cop/naming/constant_name.rb +6 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +6 -0
- data/lib/rubocop/cop/rails/link_to_blank.rb +1 -1
- data/lib/rubocop/cop/rails/output.rb +18 -1
- data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +10 -0
- data/lib/rubocop/cop/rails/validation.rb +3 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +30 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
- data/lib/rubocop/cop/style/constant_visibility.rb +66 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +8 -12
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -4
- data/lib/rubocop/cop/style/numeric_literals.rb +16 -7
- data/lib/rubocop/cop/style/option_hash.rb +5 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +13 -1
- data/lib/rubocop/cop/style/redundant_self.rb +3 -1
- data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
- data/lib/rubocop/cop/style/symbol_array.rb +9 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +5 -0
- data/lib/rubocop/cop/style/word_array.rb +0 -4
- data/lib/rubocop/cop/util.rb +4 -0
- data/lib/rubocop/core_ext/string.rb +47 -0
- data/lib/rubocop/node_pattern.rb +76 -55
- data/lib/rubocop/processed_source.rb +2 -2
- data/lib/rubocop/result_cache.rb +4 -4
- data/lib/rubocop/rspec/cop_helper.rb +5 -0
- data/lib/rubocop/rspec/expect_offense.rb +5 -5
- data/lib/rubocop/runner.rb +6 -13
- data/lib/rubocop/version.rb +1 -1
- metadata +15 -19
@@ -36,11 +36,19 @@ module RuboCop
|
|
36
36
|
check_each_arg(arguments)
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
# @param target [RuboCop::AST::Node,Parser::Source::Range]
|
40
|
+
def autocorrect(target)
|
40
41
|
lambda do |corrector|
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
if target.is_a?(RuboCop::AST::Node)
|
43
|
+
if target.parent.children.first == target
|
44
|
+
corrector.insert_before(target.source_range, ' ')
|
45
|
+
else
|
46
|
+
corrector.insert_after(target.source_range, ' ')
|
47
|
+
end
|
48
|
+
elsif target.source =~ /^\s+$/
|
49
|
+
corrector.remove(target)
|
50
|
+
else
|
51
|
+
corrector.insert_after(target, ' ')
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
@@ -97,11 +105,12 @@ module RuboCop
|
|
97
105
|
end
|
98
106
|
|
99
107
|
def check_opening_pipe_space(args, opening_pipe)
|
100
|
-
|
108
|
+
first_arg = args.first
|
109
|
+
range = first_arg.source_range
|
101
110
|
|
102
|
-
check_space(opening_pipe.end_pos,
|
103
|
-
'before first block parameter')
|
104
|
-
check_no_space(opening_pipe.end_pos,
|
111
|
+
check_space(opening_pipe.end_pos, range.begin_pos, range,
|
112
|
+
'before first block parameter', first_arg)
|
113
|
+
check_no_space(opening_pipe.end_pos, range.begin_pos - 1,
|
105
114
|
'Extra space before first')
|
106
115
|
end
|
107
116
|
|
@@ -120,20 +129,27 @@ module RuboCop
|
|
120
129
|
end
|
121
130
|
|
122
131
|
def check_each_arg(args)
|
123
|
-
args.children.
|
124
|
-
|
125
|
-
check_no_space(
|
126
|
-
range_with_surrounding_space(range: expr, side: :left).begin_pos,
|
127
|
-
expr.begin_pos - 1,
|
128
|
-
'Extra space before'
|
129
|
-
)
|
132
|
+
args.children.each do |arg|
|
133
|
+
check_arg(arg)
|
130
134
|
end
|
131
135
|
end
|
132
136
|
|
133
|
-
def
|
137
|
+
def check_arg(arg)
|
138
|
+
arg.children.each { |a| check_arg(a) } if arg.mlhs_type?
|
139
|
+
|
140
|
+
expr = arg.source_range
|
141
|
+
check_no_space(
|
142
|
+
range_with_surrounding_space(range: expr, side: :left).begin_pos,
|
143
|
+
expr.begin_pos - 1,
|
144
|
+
'Extra space before'
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
def check_space(space_begin_pos, space_end_pos, range, msg, node = nil)
|
134
149
|
return if space_begin_pos != space_end_pos
|
135
150
|
|
136
|
-
|
151
|
+
target = node || range
|
152
|
+
add_offense(target, location: range, message: "Space #{msg} missing.")
|
137
153
|
end
|
138
154
|
|
139
155
|
def check_no_space(space_begin_pos, space_end_pos, msg)
|
@@ -10,12 +10,16 @@ module RuboCop
|
|
10
10
|
# # bad
|
11
11
|
#
|
12
12
|
# File.exists?(some_path)
|
13
|
+
# Dir.exists?(some_path)
|
14
|
+
# iterator?
|
13
15
|
#
|
14
16
|
# @example
|
15
17
|
#
|
16
18
|
# # good
|
17
19
|
#
|
18
20
|
# File.exist?(some_path)
|
21
|
+
# Dir.exist?(some_path)
|
22
|
+
# block_given?
|
19
23
|
class DeprecatedClassMethods < Cop
|
20
24
|
# Inner class to DeprecatedClassMethods.
|
21
25
|
# This class exists to add abstraction and clean naming to the
|
@@ -25,24 +29,35 @@ module RuboCop
|
|
25
29
|
|
26
30
|
attr_reader :class_constant, :deprecated_method, :replacement_method
|
27
31
|
|
28
|
-
def initialize(class_constant
|
32
|
+
def initialize(deprecated:, replacement:, class_constant: nil)
|
33
|
+
@deprecated_method = deprecated
|
34
|
+
@replacement_method = replacement
|
29
35
|
@class_constant = class_constant
|
30
|
-
@deprecated_method = deprecated_method
|
31
|
-
@replacement_method = replacement_method
|
32
36
|
end
|
33
37
|
|
34
38
|
def class_nodes
|
35
|
-
@class_nodes ||=
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
+
@class_nodes ||=
|
40
|
+
if class_constant
|
41
|
+
[
|
42
|
+
s(:const, nil, class_constant),
|
43
|
+
s(:const, s(:cbase), class_constant)
|
44
|
+
]
|
45
|
+
else
|
46
|
+
[nil]
|
47
|
+
end
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
51
|
MSG = '`%<current>s` is deprecated in favor of `%<prefer>s`.'.freeze
|
43
52
|
DEPRECATED_METHODS_OBJECT = [
|
44
|
-
DeprecatedClassMethod.new(:
|
45
|
-
|
53
|
+
DeprecatedClassMethod.new(deprecated: :exists?,
|
54
|
+
replacement: :exist?,
|
55
|
+
class_constant: :File),
|
56
|
+
DeprecatedClassMethod.new(deprecated: :exists?,
|
57
|
+
replacement: :exist?,
|
58
|
+
class_constant: :Dir),
|
59
|
+
DeprecatedClassMethod.new(deprecated: :iterator?,
|
60
|
+
replacement: :block_given?)
|
46
61
|
].freeze
|
47
62
|
|
48
63
|
def on_send(node)
|
@@ -83,8 +98,12 @@ module RuboCop
|
|
83
98
|
end
|
84
99
|
|
85
100
|
def method_call(class_constant, method)
|
86
|
-
|
87
|
-
|
101
|
+
if class_constant
|
102
|
+
format('%<constant>s.%<method>s', constant: class_constant,
|
103
|
+
method: method)
|
104
|
+
else
|
105
|
+
format('%<method>s', method: method)
|
106
|
+
end
|
88
107
|
end
|
89
108
|
end
|
90
109
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks to make sure safe navigation isn't used with `empty?` in
|
7
|
+
# a conditional.
|
8
|
+
#
|
9
|
+
# While the safe navigation operator is generally a good idea, when
|
10
|
+
# checking `foo&.empty?` in a conditional, `foo` being `nil` will actually
|
11
|
+
# do the opposite of what the author intends.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # bad
|
15
|
+
# return if foo&.empty?
|
16
|
+
# return unless foo&.empty?
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# return if foo && foo.empty?
|
20
|
+
# return unless foo && foo.empty?
|
21
|
+
#
|
22
|
+
class SafeNavigationWithEmpty < Cop
|
23
|
+
MSG = 'Avoid calling `empty?` with the safe navigation operator ' \
|
24
|
+
'in conditionals.'.freeze
|
25
|
+
|
26
|
+
def_node_matcher :safe_navigation_empty_in_conditional?, <<-PATTERN
|
27
|
+
(if (csend (send ...) :empty?) ...)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def on_if(node)
|
31
|
+
return unless safe_navigation_empty_in_conditional?(node)
|
32
|
+
|
33
|
+
add_offense(node)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -107,12 +107,25 @@ module RuboCop
|
|
107
107
|
error && error.ancestors[1] == SystemCallError
|
108
108
|
end
|
109
109
|
|
110
|
+
def silence_warnings
|
111
|
+
# Replaces Kernel::silence_warnings since it hides any warnings,
|
112
|
+
# including the RuboCop ones
|
113
|
+
old_verbose = $VERBOSE
|
114
|
+
$VERBOSE = nil
|
115
|
+
yield
|
116
|
+
ensure
|
117
|
+
$VERBOSE = old_verbose
|
118
|
+
end
|
119
|
+
|
110
120
|
def evaluate_exceptions(rescue_group)
|
111
121
|
if rescue_group
|
112
122
|
rescued_exceptions = rescued_exceptions(rescue_group)
|
113
123
|
rescued_exceptions.each_with_object([]) do |exception, converted|
|
114
124
|
begin
|
115
|
-
|
125
|
+
silence_warnings do
|
126
|
+
# Avoid printing deprecation warnings about constants
|
127
|
+
converted << Kernel.const_get(exception)
|
128
|
+
end
|
116
129
|
rescue NameError
|
117
130
|
converted << nil
|
118
131
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks to make sure `#to_json` includes an optional argument.
|
7
|
+
# When overriding `#to_json`, callers may invoke JSON
|
8
|
+
# generation via `JSON.generate(your_obj)`. Since `JSON#generate` allows
|
9
|
+
# for an optional argument, your method should too.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# def to_json
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# def to_json(_opts)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class ToJSON < Cop
|
21
|
+
MSG = ' `#to_json` requires an optional argument to be parsable ' \
|
22
|
+
'via JSON.generate(obj).'.freeze
|
23
|
+
|
24
|
+
def on_def(node)
|
25
|
+
return unless node.method?(:to_json) && node.arguments.empty?
|
26
|
+
|
27
|
+
add_offense(node)
|
28
|
+
end
|
29
|
+
|
30
|
+
def autocorrect(node)
|
31
|
+
lambda do |corrector|
|
32
|
+
corrector.insert_after(node.loc.name, '(_opts)')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def urls
|
67
|
-
[style_guide_url,
|
67
|
+
[style_guide_url, *reference_urls].compact
|
68
68
|
end
|
69
69
|
|
70
70
|
private
|
@@ -89,9 +89,9 @@ module RuboCop
|
|
89
89
|
!urls.empty?
|
90
90
|
end
|
91
91
|
|
92
|
-
def
|
93
|
-
|
94
|
-
|
92
|
+
def reference_urls
|
93
|
+
urls = Array(cop_config['Reference'])
|
94
|
+
urls.nil? || urls.empty? ? nil : urls.reject(&:empty?)
|
95
95
|
end
|
96
96
|
|
97
97
|
def extra_details?
|
@@ -6,6 +6,7 @@ module RuboCop
|
|
6
6
|
# This cop checks that the ABC size of methods is not higher than the
|
7
7
|
# configured maximum. The ABC size is based on assignments, branches
|
8
8
|
# (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric
|
9
|
+
# and https://en.wikipedia.org/wiki/ABC_Software_Metric.
|
9
10
|
class AbcSize < Cop
|
10
11
|
include MethodComplexity
|
11
12
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# We separate the *calculator* from the *cop* so that the calculation,
|
12
12
|
# the formula itself, is easier to test.
|
13
|
-
|
13
|
+
class AbcSizeCalculator
|
14
14
|
# > Branch -- an explicit forward program branch out of scope -- a
|
15
15
|
# > function call, class method call ..
|
16
16
|
# > http://c2.com/cgi/wiki?AbcMetric
|
@@ -22,21 +22,43 @@ module RuboCop
|
|
22
22
|
CONDITION_NODES = CyclomaticComplexity::COUNTED_NODES.freeze
|
23
23
|
|
24
24
|
def self.calculate(node)
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
new(node).calculate
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(node)
|
29
|
+
@assignment = 0
|
30
|
+
@branch = 0
|
31
|
+
@condition = 0
|
32
|
+
@node = node
|
33
|
+
end
|
28
34
|
|
29
|
-
|
35
|
+
def calculate
|
36
|
+
@node.each_node do |child|
|
30
37
|
if child.assignment?
|
31
|
-
assignment += 1
|
38
|
+
@assignment += 1
|
32
39
|
elsif BRANCH_NODES.include?(child.type)
|
33
|
-
|
40
|
+
evaluate_branch_nodes(child)
|
34
41
|
elsif CONDITION_NODES.include?(child.type)
|
35
|
-
condition += 1
|
42
|
+
@condition += 1 if node_has_else_branch?(child)
|
43
|
+
@condition += 1
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
39
|
-
Math.sqrt(assignment**2 + branch**2 + condition**2).round(2)
|
47
|
+
Math.sqrt(@assignment**2 + @branch**2 + @condition**2).round(2)
|
48
|
+
end
|
49
|
+
|
50
|
+
def evaluate_branch_nodes(node)
|
51
|
+
if node.comparison_method?
|
52
|
+
@condition += 1
|
53
|
+
else
|
54
|
+
@branch += 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def node_has_else_branch?(node)
|
59
|
+
%i[case if].include?(node.type) &&
|
60
|
+
node.else? &&
|
61
|
+
node.loc.else.is?('else')
|
40
62
|
end
|
41
63
|
end
|
42
64
|
end
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
30
30
|
#
|
31
31
|
# return true if ruby_version >= 3.1
|
32
32
|
#
|
33
|
-
# And the above `ruby_version >= 3.1` is
|
33
|
+
# And the above `ruby_version >= 3.1` is undecided whether it will be
|
34
34
|
# Ruby 3.1, 3.2, 4.0 or others.
|
35
35
|
# See https://bugs.ruby-lang.org/issues/8976#note-41 for details.
|
36
36
|
return false unless ruby_version >= 2.3
|
@@ -18,7 +18,8 @@ module RuboCop
|
|
18
18
|
default = default_cop_config['PreferredMethods']
|
19
19
|
merged = cop_config['PreferredMethods']
|
20
20
|
overrides = merged.values - default.values
|
21
|
-
merged.reject { |key, _| overrides.include?(key) }
|
21
|
+
merged.reject { |key, _| overrides.include?(key) }
|
22
|
+
.map { |k, v| [k.to_sym, v] }.to_h
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
@@ -60,9 +60,14 @@ module RuboCop
|
|
60
60
|
|
61
61
|
def allowed_method_call_on_rhs?(node)
|
62
62
|
node && node.send_type? &&
|
63
|
-
(node.receiver.nil? || !node
|
63
|
+
(node.receiver.nil? || !literal_receiver?(node))
|
64
64
|
end
|
65
65
|
|
66
|
+
def_node_matcher :literal_receiver?, <<-PATTERN
|
67
|
+
{(send literal? ...)
|
68
|
+
(send (begin literal?) ...)}
|
69
|
+
PATTERN
|
70
|
+
|
66
71
|
def allowed_conditional_expression_on_rhs?(node)
|
67
72
|
node && node.if_type? && contains_contant?(node)
|
68
73
|
end
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # bad
|
10
|
+
# def is_even(value)
|
11
|
+
# end
|
12
|
+
#
|
10
13
|
# def is_even?(value)
|
11
14
|
# end
|
12
15
|
#
|
@@ -15,6 +18,9 @@ module RuboCop
|
|
15
18
|
# end
|
16
19
|
#
|
17
20
|
# # bad
|
21
|
+
# def has_value
|
22
|
+
# end
|
23
|
+
#
|
18
24
|
# def has_value?
|
19
25
|
# end
|
20
26
|
#
|