rubocop 0.92.0 → 0.93.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 +1 -1
- data/config/default.yml +30 -0
- data/lib/rubocop.rb +3 -1
- data/lib/rubocop/cached_data.rb +2 -1
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
- data/lib/rubocop/cop/layout/dot_position.rb +6 -9
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -7
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -11
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
- data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
- data/lib/rubocop/cop/metrics/block_length.rb +3 -1
- data/lib/rubocop/cop/metrics/class_length.rb +14 -6
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/offense.rb +15 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
- data/lib/rubocop/cop/style/case_like_if.rb +20 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +8 -1
- data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
- data/lib/rubocop/cop/style/for.rb +0 -4
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
- data/lib/rubocop/cop/style/raise_args.rb +0 -3
- data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +39 -24
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +0 -4
- data/lib/rubocop/ext/regexp_node.rb +20 -4
- data/lib/rubocop/result_cache.rb +8 -2
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/runner.rb +4 -4
- data/lib/rubocop/target_finder.rb +23 -25
- data/lib/rubocop/version.rb +1 -1
- metadata +11 -9
- data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
# content.
|
30
30
|
# HEREDOC
|
31
31
|
# end # 5 points
|
32
|
+
#
|
33
|
+
# NOTE: This cop does not apply for `Struct` definitions.
|
32
34
|
class BlockLength < Base
|
33
35
|
include CodeLength
|
34
36
|
|
@@ -36,7 +38,7 @@ module RuboCop
|
|
36
38
|
|
37
39
|
def on_block(node)
|
38
40
|
return if excluded_method?(node)
|
39
|
-
return if node.class_constructor?
|
41
|
+
return if node.class_constructor? || node.struct_constructor?
|
40
42
|
|
41
43
|
check_code_length(node)
|
42
44
|
end
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
# HEREDOC
|
30
30
|
# end # 5 points
|
31
31
|
#
|
32
|
+
#
|
33
|
+
# NOTE: This cop also applies for `Struct` definitions.
|
32
34
|
class ClassLength < Base
|
33
35
|
include CodeLength
|
34
36
|
|
@@ -37,17 +39,23 @@ module RuboCop
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def on_casgn(node)
|
40
|
-
|
41
|
-
|
42
|
+
parent = node.parent
|
43
|
+
|
44
|
+
if parent&.assignment?
|
45
|
+
block_node = parent.children[1]
|
46
|
+
elsif parent&.parent&.masgn_type?
|
47
|
+
block_node = parent.parent.children[1]
|
48
|
+
else
|
49
|
+
_scope, _name, block_node = *node
|
42
50
|
end
|
51
|
+
|
52
|
+
return unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
|
53
|
+
|
54
|
+
check_code_length(block_node)
|
43
55
|
end
|
44
56
|
|
45
57
|
private
|
46
58
|
|
47
|
-
def_node_matcher :class_definition?, <<~PATTERN
|
48
|
-
(casgn nil? _ (block (send (const {nil? cbase} :Class) :new) ...))
|
49
|
-
PATTERN
|
50
|
-
|
51
59
|
def message(length, max_length)
|
52
60
|
format('Class has too many lines. [%<length>d/%<max>d]',
|
53
61
|
length: length,
|
@@ -137,7 +137,7 @@ module RuboCop
|
|
137
137
|
end
|
138
138
|
|
139
139
|
# Internal helper class to hold autocorrect data
|
140
|
-
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
140
|
+
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
141
141
|
def self.from_each_with_object(node, match)
|
142
142
|
new(match, node, 0, 0)
|
143
143
|
end
|
data/lib/rubocop/cop/offense.rb
CHANGED
@@ -63,10 +63,23 @@ module RuboCop
|
|
63
63
|
attr_reader :corrector
|
64
64
|
|
65
65
|
PseudoSourceRange = Struct.new(:line, :column, :source_line, :begin_pos,
|
66
|
-
:end_pos)
|
66
|
+
:end_pos) do
|
67
|
+
alias_method :first_line, :line
|
68
|
+
alias_method :last_line, :line
|
69
|
+
alias_method :last_column, :column
|
70
|
+
|
71
|
+
def column_range
|
72
|
+
column...last_column
|
73
|
+
end
|
74
|
+
|
75
|
+
def size
|
76
|
+
end_pos - begin_pos
|
77
|
+
end
|
78
|
+
alias_method :length, :size
|
79
|
+
end
|
67
80
|
private_constant :PseudoSourceRange
|
68
81
|
|
69
|
-
NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0,
|
82
|
+
NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0, 0).freeze
|
70
83
|
|
71
84
|
# @api private
|
72
85
|
def initialize(severity, location, message, cop_name, # rubocop:disable Metrics/ParameterLists
|
@@ -83,8 +83,8 @@ module RuboCop
|
|
83
83
|
|
84
84
|
def on_send(node)
|
85
85
|
return unless node.access_modifier?
|
86
|
-
return if node.parent
|
87
|
-
return if
|
86
|
+
return if node.parent&.pair_type?
|
87
|
+
return if allow_modifiers_on_symbols?(node)
|
88
88
|
|
89
89
|
if offense?(node)
|
90
90
|
add_offense(node.loc.selector) if opposite_style_detected
|
@@ -95,6 +95,10 @@ module RuboCop
|
|
95
95
|
|
96
96
|
private
|
97
97
|
|
98
|
+
def allow_modifiers_on_symbols?(node)
|
99
|
+
cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
|
100
|
+
end
|
101
|
+
|
98
102
|
def offense?(node)
|
99
103
|
(group_style? && access_modifier_is_inlined?(node)) ||
|
100
104
|
(inline_style? && access_modifier_is_not_inlined?(node))
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
# By default it enforces accessors to be placed in grouped declarations,
|
8
8
|
# but it can be configured to enforce separating them in multiple declarations.
|
9
9
|
#
|
10
|
+
# Note: `Sorbet` is not compatible with "grouped" style. Consider "separated" style
|
11
|
+
# or disabling this cop.
|
12
|
+
#
|
10
13
|
# @example EnforcedStyle: grouped (default)
|
11
14
|
# # bad
|
12
15
|
# class Foo
|
@@ -42,6 +42,8 @@ module RuboCop
|
|
42
42
|
convertible = true
|
43
43
|
|
44
44
|
branch_conditions(node).each do |branch_condition|
|
45
|
+
return false if regexp_with_working_captures?(branch_condition)
|
46
|
+
|
45
47
|
conditions << []
|
46
48
|
convertible = collect_conditions(branch_condition, target, conditions.last)
|
47
49
|
break unless convertible
|
@@ -49,9 +51,7 @@ module RuboCop
|
|
49
51
|
|
50
52
|
return unless convertible
|
51
53
|
|
52
|
-
add_offense(node)
|
53
|
-
autocorrect(corrector, node)
|
54
|
-
end
|
54
|
+
add_offense(node) { |corrector| autocorrect(corrector, node) }
|
55
55
|
end
|
56
56
|
|
57
57
|
private
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
107
107
|
when :include?, :cover?
|
108
108
|
receiver = deparenthesize(node.receiver)
|
109
109
|
node.arguments.first if receiver.range_type?
|
110
|
-
when :match, :match
|
110
|
+
when :match, :match?, :=~
|
111
111
|
find_target_in_match_node(node)
|
112
112
|
end
|
113
113
|
end
|
@@ -230,6 +230,22 @@ module RuboCop
|
|
230
230
|
def indent(node)
|
231
231
|
' ' * node.loc.column
|
232
232
|
end
|
233
|
+
|
234
|
+
# Named captures work with `=~` (if regexp is on lhs) and with `match` (both sides)
|
235
|
+
def regexp_with_working_captures?(node)
|
236
|
+
case node.type
|
237
|
+
when :match_with_lvasgn
|
238
|
+
lhs, _rhs = *node
|
239
|
+
node.loc.selector.source == '=~' && regexp_with_named_captures?(lhs)
|
240
|
+
when :send
|
241
|
+
lhs, method, rhs = *node
|
242
|
+
method == :match && [lhs, rhs].any? { |n| regexp_with_named_captures?(n) }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def regexp_with_named_captures?(node)
|
247
|
+
node.regexp_type? && node.each_capture(named: true).count.positive?
|
248
|
+
end
|
233
249
|
end
|
234
250
|
end
|
235
251
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop enforces the use of `Object#instance_of?` instead of class comparison
|
7
|
+
# for equality.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# var.class == Date
|
12
|
+
# var.class.equal?(Date)
|
13
|
+
# var.class.eql?(Date)
|
14
|
+
# var.class.name == 'Date'
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# var.instance_of?(Date)
|
18
|
+
#
|
19
|
+
class ClassEqualityComparison < Base
|
20
|
+
include RangeHelp
|
21
|
+
include IgnoredMethods
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
MSG = 'Use `instance_of?(%<class_name>s)` instead of comparing classes.'
|
25
|
+
|
26
|
+
RESTRICT_ON_SEND = %i[== equal? eql?].freeze
|
27
|
+
|
28
|
+
def_node_matcher :class_comparison_candidate?, <<~PATTERN
|
29
|
+
(send
|
30
|
+
{$(send _ :class) (send $(send _ :class) :name)}
|
31
|
+
{:== :equal? :eql?} $_)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_send(node)
|
35
|
+
def_node = node.each_ancestor(:def, :defs).first
|
36
|
+
return if def_node && ignored_method?(def_node.method_name)
|
37
|
+
|
38
|
+
class_comparison_candidate?(node) do |receiver_node, class_node|
|
39
|
+
range = offense_range(receiver_node, node)
|
40
|
+
class_name = class_name(class_node, node)
|
41
|
+
|
42
|
+
add_offense(range, message: format(MSG, class_name: class_name)) do |corrector|
|
43
|
+
corrector.replace(range, "instance_of?(#{class_name})")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def class_name(class_node, node)
|
51
|
+
if node.children.first.method?(:name)
|
52
|
+
class_node.source.delete('"').delete("'")
|
53
|
+
else
|
54
|
+
class_node.source
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def offense_range(receiver_node, node)
|
59
|
+
range_between(receiver_node.loc.selector.begin_pos, node.source_range.end_pos)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -49,6 +49,12 @@ module RuboCop
|
|
49
49
|
# end
|
50
50
|
# end
|
51
51
|
#
|
52
|
+
# # good
|
53
|
+
# def method
|
54
|
+
# each_slice(2) { |slice| do_something(slice) }
|
55
|
+
# each_slice(3) { |slice| do_something(slice) }
|
56
|
+
# end
|
57
|
+
#
|
52
58
|
class CombinableLoops < Base
|
53
59
|
MSG = 'Combine this loop with the previous loop.'
|
54
60
|
|
@@ -76,7 +82,8 @@ module RuboCop
|
|
76
82
|
def same_collection_looping?(node, sibling)
|
77
83
|
sibling&.block_type? &&
|
78
84
|
sibling.send_node.method?(node.method_name) &&
|
79
|
-
sibling.send_node.receiver == node.send_node.receiver
|
85
|
+
sibling.send_node.receiver == node.send_node.receiver &&
|
86
|
+
sibling.send_node.arguments == node.send_node.arguments
|
80
87
|
end
|
81
88
|
end
|
82
89
|
end
|
@@ -6,6 +6,12 @@ module RuboCop
|
|
6
6
|
# This cop checks that comment annotation keywords are written according
|
7
7
|
# to guidelines.
|
8
8
|
#
|
9
|
+
# NOTE: With a multiline comment block (where each line is only a
|
10
|
+
# comment), only the first line will be able to register an offense, even
|
11
|
+
# if an annotation keyword starts another line. This is done to prevent
|
12
|
+
# incorrect registering of keywords (eg. `review`) inside a paragraph as an
|
13
|
+
# annotation.
|
14
|
+
#
|
9
15
|
# @example
|
10
16
|
# # bad
|
11
17
|
# # TODO make better
|
@@ -57,12 +57,16 @@ module RuboCop
|
|
57
57
|
yielding_block?(block_node) do |send_node, block_args, yield_args|
|
58
58
|
return unless yielding_arguments?(block_args, yield_args)
|
59
59
|
|
60
|
+
def_node = block_node.each_ancestor(:def, :defs).first
|
61
|
+
# if `yield` is being called outside of a method context, ignore
|
62
|
+
# this is not a valid ruby pattern, but can happen in haml or erb,
|
63
|
+
# so this can cause crashes in haml_lint
|
64
|
+
return unless def_node
|
65
|
+
|
60
66
|
add_offense(block_node) do |corrector|
|
61
67
|
corrector.remove(block_body_range(block_node, send_node))
|
62
68
|
|
63
69
|
add_block_argument(send_node, corrector)
|
64
|
-
|
65
|
-
def_node = block_node.each_ancestor(:def, :defs).first
|
66
70
|
add_block_argument(def_node, corrector) if @def_nodes.add?(def_node)
|
67
71
|
end
|
68
72
|
end
|
@@ -49,8 +49,6 @@ module RuboCop
|
|
49
49
|
|
50
50
|
def on_for(node)
|
51
51
|
if style == :each
|
52
|
-
return unless opposite_style_detected
|
53
|
-
|
54
52
|
add_offense(node, message: PREFER_EACH) do |corrector|
|
55
53
|
ForToEachCorrector.new(node).call(corrector)
|
56
54
|
end
|
@@ -63,8 +61,6 @@ module RuboCop
|
|
63
61
|
return unless suspect_enumerable?(node)
|
64
62
|
|
65
63
|
if style == :for
|
66
|
-
return unless opposite_style_detected
|
67
|
-
|
68
64
|
add_offense(node, message: PREFER_FOR) do |corrector|
|
69
65
|
EachToForCorrector.new(node).call(corrector)
|
70
66
|
end
|
@@ -140,16 +140,12 @@ module RuboCop
|
|
140
140
|
def missing_parentheses(node)
|
141
141
|
location = node.arguments.source_range
|
142
142
|
|
143
|
-
return unless unexpected_style_detected(:require_no_parentheses)
|
144
|
-
|
145
143
|
add_offense(location, message: MSG_MISSING) do |corrector|
|
146
144
|
correct_definition(node, corrector)
|
147
145
|
end
|
148
146
|
end
|
149
147
|
|
150
148
|
def unwanted_parentheses(args)
|
151
|
-
return unless unexpected_style_detected(:require_parentheses)
|
152
|
-
|
153
149
|
add_offense(args, message: MSG_PRESENT) do |corrector|
|
154
150
|
# offense is registered on args node when parentheses are unwanted
|
155
151
|
correct_arguments(args, corrector)
|
@@ -84,8 +84,6 @@ module RuboCop
|
|
84
84
|
|
85
85
|
def check_compact(node)
|
86
86
|
if node.arguments.size > 1
|
87
|
-
return unless opposite_style_detected
|
88
|
-
|
89
87
|
add_offense(node, message: format(COMPACT_MSG, method: node.method_name)) do |corrector|
|
90
88
|
replacement = correction_exploded_to_compact(node)
|
91
89
|
|
@@ -103,7 +101,6 @@ module RuboCop
|
|
103
101
|
|
104
102
|
return unless first_arg.send_type? && first_arg.method?(:new)
|
105
103
|
return if acceptable_exploded_args?(first_arg.arguments)
|
106
|
-
return unless opposite_style_detected
|
107
104
|
|
108
105
|
add_offense(node, message: format(EXPLODED_MSG, method: node.method_name)) do |corrector|
|
109
106
|
replacement = correction_compact_to_exploded(node)
|
@@ -28,6 +28,14 @@ module RuboCop
|
|
28
28
|
# end
|
29
29
|
#
|
30
30
|
# # bad
|
31
|
+
# begin
|
32
|
+
# do_something
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# do_something
|
37
|
+
#
|
38
|
+
# # bad
|
31
39
|
# # When using Ruby 2.5 or later.
|
32
40
|
# do_something do
|
33
41
|
# begin
|
@@ -60,7 +68,9 @@ module RuboCop
|
|
60
68
|
MSG = 'Redundant `begin` block detected.'
|
61
69
|
|
62
70
|
def on_def(node)
|
63
|
-
|
71
|
+
return unless node.body&.kwbegin_type?
|
72
|
+
|
73
|
+
register_offense(node.body)
|
64
74
|
end
|
65
75
|
alias on_defs on_def
|
66
76
|
|
@@ -69,20 +79,38 @@ module RuboCop
|
|
69
79
|
|
70
80
|
return if node.send_node.lambda_literal?
|
71
81
|
return if node.braces?
|
82
|
+
return unless node.body&.kwbegin_type?
|
72
83
|
|
73
|
-
|
84
|
+
register_offense(node.body)
|
74
85
|
end
|
75
86
|
|
76
|
-
|
87
|
+
def on_kwbegin(node)
|
88
|
+
return if contain_rescue_or_ensure?(node) || valid_context_using_only_begin?(node)
|
77
89
|
|
78
|
-
|
79
|
-
|
90
|
+
register_offense(node)
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
80
94
|
|
81
|
-
|
82
|
-
|
83
|
-
corrector.remove(node.
|
95
|
+
def register_offense(node)
|
96
|
+
add_offense(node.loc.begin) do |corrector|
|
97
|
+
corrector.remove(node.loc.begin)
|
98
|
+
corrector.remove(node.loc.end)
|
84
99
|
end
|
85
100
|
end
|
101
|
+
|
102
|
+
def contain_rescue_or_ensure?(node)
|
103
|
+
first_child = node.children.first
|
104
|
+
|
105
|
+
first_child.rescue_type? || first_child.ensure_type?
|
106
|
+
end
|
107
|
+
|
108
|
+
def valid_context_using_only_begin?(node)
|
109
|
+
parent = node.parent
|
110
|
+
|
111
|
+
node.each_ancestor.any?(&:assignment?) || parent&.post_condition_loop? ||
|
112
|
+
parent&.send_type? || parent&.operator_keyword?
|
113
|
+
end
|
86
114
|
end
|
87
115
|
end
|
88
116
|
end
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
75
75
|
def offense?(node)
|
76
76
|
condition, if_branch, else_branch = *node
|
77
77
|
|
78
|
-
return false if use_if_branch?(else_branch)
|
78
|
+
return false if use_if_branch?(else_branch) || use_hash_key_assignment?(else_branch)
|
79
79
|
|
80
80
|
condition == if_branch && !node.elsif? && (
|
81
81
|
node.ternary? ||
|
@@ -88,6 +88,10 @@ module RuboCop
|
|
88
88
|
else_branch&.if_type?
|
89
89
|
end
|
90
90
|
|
91
|
+
def use_hash_key_assignment?(else_branch)
|
92
|
+
else_branch&.send_type? && else_branch&.method?(:[]=)
|
93
|
+
end
|
94
|
+
|
91
95
|
def else_source(else_branch)
|
92
96
|
if require_parentheses?(else_branch)
|
93
97
|
"(#{else_branch.source})"
|