rubocop 1.13.0 → 1.17.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 -1
- data/config/default.yml +68 -8
- data/lib/rubocop.rb +9 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +99 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +29 -11
- data/lib/rubocop/cop/layout/case_indentation.rb +57 -9
- data/lib/rubocop/cop/layout/dot_position.rb +7 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +12 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +34 -9
- data/lib/rubocop/cop/layout/indentation_width.rb +13 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +24 -10
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +53 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +28 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +6 -0
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +83 -39
- data/lib/rubocop/cop/lint/empty_block.rb +18 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +62 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +105 -74
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -12
- data/lib/rubocop/cop/lint/unreachable_loop.rb +12 -2
- data/lib/rubocop/cop/lint/unused_block_argument.rb +7 -1
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +3 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +19 -3
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
- data/lib/rubocop/cop/mixin/gem_declaration.rb +13 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +14 -3
- data/lib/rubocop/cop/mixin/string_literals_help.rb +3 -5
- data/lib/rubocop/cop/mixin/symbol_help.rb +13 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +17 -5
- data/lib/rubocop/cop/style/empty_literal.rb +8 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +18 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +58 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -4
- data/lib/rubocop/cop/style/in_pattern_then.rb +56 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +62 -0
- data/lib/rubocop/cop/style/multiline_when_then.rb +2 -11
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +17 -9
- data/lib/rubocop/cop/style/nil_lambda.rb +29 -12
- data/lib/rubocop/cop/style/quoted_symbols.rb +110 -0
- data/lib/rubocop/cop/style/raise_args.rb +2 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +24 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +9 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +8 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
- data/lib/rubocop/cop/style/string_literals.rb +1 -0
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +1 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +83 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +65 -0
- data/lib/rubocop/cop/style/when_then.rb +6 -2
- data/lib/rubocop/cop/variable_force/branch.rb +15 -0
- data/lib/rubocop/directive_comment.rb +58 -6
- data/lib/rubocop/formatter/junit_formatter.rb +21 -6
- data/lib/rubocop/options.rb +14 -20
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +10 -2
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/target_finder.rb +9 -2
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +18 -9
@@ -53,6 +53,10 @@ module RuboCop
|
|
53
53
|
check(node, %i[keyword else].freeze)
|
54
54
|
end
|
55
55
|
|
56
|
+
def on_case_match(node)
|
57
|
+
check(node, %i[keyword else].freeze)
|
58
|
+
end
|
59
|
+
|
56
60
|
def on_ensure(node)
|
57
61
|
check(node, [:keyword].freeze)
|
58
62
|
end
|
@@ -65,10 +69,30 @@ module RuboCop
|
|
65
69
|
check(node, %i[keyword else begin end].freeze, 'then')
|
66
70
|
end
|
67
71
|
|
72
|
+
def on_if_guard(node)
|
73
|
+
check(node, [:keyword].freeze)
|
74
|
+
end
|
75
|
+
|
76
|
+
def on_in_pattern(node)
|
77
|
+
check(node, [:keyword].freeze)
|
78
|
+
end
|
79
|
+
|
68
80
|
def on_kwbegin(node)
|
69
81
|
check(node, %i[begin end].freeze, nil)
|
70
82
|
end
|
71
83
|
|
84
|
+
# Handle one-line pattern matching syntax (`in`) with `Parser::Ruby27`.
|
85
|
+
def on_match_pattern(node)
|
86
|
+
return if target_ruby_version >= 3.0
|
87
|
+
|
88
|
+
check(node, [:operator].freeze)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Handle one-line pattern matching syntax (`in`) with `Parser::Ruby30`.
|
92
|
+
def on_match_pattern_p(node)
|
93
|
+
check(node, [:operator].freeze)
|
94
|
+
end
|
95
|
+
|
72
96
|
def on_next(node)
|
73
97
|
check(node, [:keyword].freeze)
|
74
98
|
end
|
@@ -109,6 +133,10 @@ module RuboCop
|
|
109
133
|
check(node, [:keyword].freeze)
|
110
134
|
end
|
111
135
|
|
136
|
+
def on_unless_guard(node)
|
137
|
+
check(node, [:keyword].freeze)
|
138
|
+
end
|
139
|
+
|
112
140
|
def on_until(node)
|
113
141
|
check(node, %i[begin end keyword].freeze)
|
114
142
|
end
|
@@ -120,6 +120,12 @@ module RuboCop
|
|
120
120
|
check_operator(:special_asgn, node.loc.operator, right.source_range)
|
121
121
|
end
|
122
122
|
|
123
|
+
def on_match_pattern(node)
|
124
|
+
return if target_ruby_version < 3.0
|
125
|
+
|
126
|
+
check_operator(:match_pattern, node.loc.operator, node.source_range)
|
127
|
+
end
|
128
|
+
|
123
129
|
alias on_or on_binary
|
124
130
|
alias on_and on_binary
|
125
131
|
alias on_lvasgn on_assignment
|
@@ -12,6 +12,8 @@ module RuboCop
|
|
12
12
|
# File.exists?(some_path)
|
13
13
|
# Dir.exists?(some_path)
|
14
14
|
# iterator?
|
15
|
+
# Socket.gethostbyname(host)
|
16
|
+
# Socket.gethostbyaddr(host)
|
15
17
|
#
|
16
18
|
# @example
|
17
19
|
#
|
@@ -20,21 +22,23 @@ module RuboCop
|
|
20
22
|
# File.exist?(some_path)
|
21
23
|
# Dir.exist?(some_path)
|
22
24
|
# block_given?
|
25
|
+
# Addrinfo.getaddrinfo(nodename, service)
|
26
|
+
# Addrinfo.tcp(host, port).getnameinfo
|
23
27
|
class DeprecatedClassMethods < Base
|
24
28
|
extend AutoCorrector
|
25
29
|
|
26
30
|
# Inner class to DeprecatedClassMethods.
|
27
|
-
# This class exists to add abstraction and clean naming
|
28
|
-
#
|
31
|
+
# This class exists to add abstraction and clean naming
|
32
|
+
# to the deprecated objects
|
29
33
|
class DeprecatedClassMethod
|
30
34
|
include RuboCop::AST::Sexp
|
31
35
|
|
32
|
-
attr_reader :
|
36
|
+
attr_reader :method, :class_constant
|
33
37
|
|
34
|
-
def initialize(
|
35
|
-
@
|
36
|
-
@replacement_method = replacement
|
38
|
+
def initialize(method, class_constant: nil, correctable: true)
|
39
|
+
@method = method
|
37
40
|
@class_constant = class_constant
|
41
|
+
@correctable = correctable
|
38
42
|
end
|
39
43
|
|
40
44
|
def class_nodes
|
@@ -48,28 +52,80 @@ module RuboCop
|
|
48
52
|
[nil]
|
49
53
|
end
|
50
54
|
end
|
55
|
+
|
56
|
+
def correctable?
|
57
|
+
@correctable
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
[class_constant, method].compact.join(delimeter)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def delimeter
|
67
|
+
CLASS_METHOD_DELIMETER
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Inner class to DeprecatedClassMethods.
|
72
|
+
# This class exists to add abstraction and clean naming
|
73
|
+
# to the replacements for deprecated objects
|
74
|
+
class Replacement
|
75
|
+
attr_reader :method, :class_constant
|
76
|
+
|
77
|
+
def initialize(method, class_constant: nil, instance_method: false)
|
78
|
+
@method = method
|
79
|
+
@class_constant = class_constant
|
80
|
+
@instance_method = instance_method
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_s
|
84
|
+
[class_constant, method].compact.join(delimeter)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def delimeter
|
90
|
+
instance_method? ? INSTANCE_METHOD_DELIMETER : CLASS_METHOD_DELIMETER
|
91
|
+
end
|
92
|
+
|
93
|
+
def instance_method?
|
94
|
+
@instance_method
|
95
|
+
end
|
51
96
|
end
|
52
97
|
|
53
98
|
MSG = '`%<current>s` is deprecated in favor of `%<prefer>s`.'
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
99
|
+
|
100
|
+
DEPRECATED_METHODS_OBJECT = {
|
101
|
+
DeprecatedClassMethod.new(:exists?, class_constant: :File) =>
|
102
|
+
Replacement.new(:exist?, class_constant: :File),
|
103
|
+
|
104
|
+
DeprecatedClassMethod.new(:exists?, class_constant: :Dir) =>
|
105
|
+
Replacement.new(:exist?, class_constant: :Dir),
|
106
|
+
|
107
|
+
DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?),
|
108
|
+
|
109
|
+
DeprecatedClassMethod.new(:gethostbyaddr, class_constant: :Socket, correctable: false) =>
|
110
|
+
Replacement.new(:getnameinfo, class_constant: :Addrinfo, instance_method: true),
|
111
|
+
|
112
|
+
DeprecatedClassMethod.new(:gethostbyname, class_constant: :Socket, correctable: false) =>
|
113
|
+
Replacement.new(:getaddrinfo, class_constant: :Addrinfo, instance_method: true)
|
114
|
+
}.freeze
|
115
|
+
|
116
|
+
RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze
|
117
|
+
|
118
|
+
CLASS_METHOD_DELIMETER = '.'
|
119
|
+
INSTANCE_METHOD_DELIMETER = '#'
|
65
120
|
|
66
121
|
def on_send(node)
|
67
|
-
check(node) do |
|
68
|
-
message = format(MSG, current:
|
69
|
-
prefer: replacement_method(data))
|
122
|
+
check(node) do |deprecated|
|
123
|
+
message = format(MSG, current: deprecated, prefer: replacement(deprecated))
|
70
124
|
|
71
125
|
add_offense(node.loc.selector, message: message) do |corrector|
|
72
|
-
|
126
|
+
if deprecated.correctable?
|
127
|
+
corrector.replace(node.loc.selector, replacement(deprecated).method)
|
128
|
+
end
|
73
129
|
end
|
74
130
|
end
|
75
131
|
end
|
@@ -77,28 +133,16 @@ module RuboCop
|
|
77
133
|
private
|
78
134
|
|
79
135
|
def check(node)
|
80
|
-
DEPRECATED_METHODS_OBJECT.
|
81
|
-
next unless
|
82
|
-
next unless node.method?(
|
136
|
+
DEPRECATED_METHODS_OBJECT.each_key do |deprecated|
|
137
|
+
next unless deprecated.class_nodes.include?(node.receiver)
|
138
|
+
next unless node.method?(deprecated.method)
|
83
139
|
|
84
|
-
yield
|
140
|
+
yield deprecated
|
85
141
|
end
|
86
142
|
end
|
87
143
|
|
88
|
-
def
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
def replacement_method(data)
|
93
|
-
method_call(data.class_constant, data.replacement_method)
|
94
|
-
end
|
95
|
-
|
96
|
-
def method_call(class_constant, method)
|
97
|
-
if class_constant
|
98
|
-
format('%<constant>s.%<method>s', constant: class_constant, method: method)
|
99
|
-
else
|
100
|
-
format('%<method>s', method: method)
|
101
|
-
end
|
144
|
+
def replacement(deprecated)
|
145
|
+
DEPRECATED_METHODS_OBJECT[deprecated]
|
102
146
|
end
|
103
147
|
end
|
104
148
|
end
|
@@ -7,7 +7,11 @@ module RuboCop
|
|
7
7
|
# Such empty blocks are typically an oversight or we should provide a comment
|
8
8
|
# be clearer what we're aiming for.
|
9
9
|
#
|
10
|
-
# Empty lambdas are ignored by default.
|
10
|
+
# Empty lambdas and procs are ignored by default.
|
11
|
+
#
|
12
|
+
# NOTE: For backwards compatibility, the configuration that allows/disallows
|
13
|
+
# empty lambdas and procs is called `AllowEmptyLambdas`, even though it also
|
14
|
+
# applies to procs.
|
11
15
|
#
|
12
16
|
# @example
|
13
17
|
# # bad
|
@@ -40,6 +44,10 @@ module RuboCop
|
|
40
44
|
# end
|
41
45
|
# (callable || placeholder).call
|
42
46
|
#
|
47
|
+
# proc { }
|
48
|
+
#
|
49
|
+
# Proc.new { }
|
50
|
+
#
|
43
51
|
# @example AllowEmptyLambdas: false
|
44
52
|
# # bad
|
45
53
|
# allow(subject).to receive(:callable).and_return(-> {})
|
@@ -48,12 +56,16 @@ module RuboCop
|
|
48
56
|
# end
|
49
57
|
# (callable || placeholder).call
|
50
58
|
#
|
59
|
+
# proc { }
|
60
|
+
#
|
61
|
+
# Proc.new { }
|
62
|
+
#
|
51
63
|
class EmptyBlock < Base
|
52
64
|
MSG = 'Empty block detected.'
|
53
65
|
|
54
66
|
def on_block(node)
|
55
67
|
return if node.body
|
56
|
-
return if allow_empty_lambdas? && node
|
68
|
+
return if allow_empty_lambdas? && lambda_or_proc?(node)
|
57
69
|
return if cop_config['AllowComments'] && allow_comment?(node)
|
58
70
|
|
59
71
|
add_offense(node)
|
@@ -76,6 +88,10 @@ module RuboCop
|
|
76
88
|
regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
|
77
89
|
Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
|
78
90
|
end
|
91
|
+
|
92
|
+
def lambda_or_proc?(node)
|
93
|
+
node.lambda? || node.proc?
|
94
|
+
end
|
79
95
|
end
|
80
96
|
end
|
81
97
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for the presence of `in` pattern branches without a body.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# case condition
|
12
|
+
# in [a]
|
13
|
+
# do_something
|
14
|
+
# in [a, b]
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# case condition
|
19
|
+
# in [a]
|
20
|
+
# do_something
|
21
|
+
# in [a, b]
|
22
|
+
# nil
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @example AllowComments: true (default)
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# case condition
|
29
|
+
# in [a]
|
30
|
+
# do_something
|
31
|
+
# in [a, b]
|
32
|
+
# # noop
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# @example AllowComments: false
|
36
|
+
#
|
37
|
+
# # bad
|
38
|
+
# case condition
|
39
|
+
# in [a]
|
40
|
+
# do_something
|
41
|
+
# in [a, b]
|
42
|
+
# # noop
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
class EmptyInPattern < Base
|
46
|
+
extend TargetRubyVersion
|
47
|
+
|
48
|
+
MSG = 'Avoid `in` branches without a body.'
|
49
|
+
|
50
|
+
minimum_target_ruby_version 2.7
|
51
|
+
|
52
|
+
def on_case_match(node)
|
53
|
+
node.in_pattern_branches.each do |branch|
|
54
|
+
next if branch.body || cop_config['AllowComments'] && comment_lines?(node)
|
55
|
+
|
56
|
+
add_offense(branch)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -5,7 +5,7 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# This cop checks for literals used as the conditions or as
|
7
7
|
# operands in and/or expressions serving as the conditions of
|
8
|
-
# if/while/until.
|
8
|
+
# if/while/until/case-when/case-in.
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
#
|
@@ -67,6 +67,18 @@ module RuboCop
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
def on_case_match(case_match_node)
|
71
|
+
if case_match_node.condition
|
72
|
+
check_case(case_match_node)
|
73
|
+
else
|
74
|
+
case_match_node.each_in_pattern do |in_pattern_node|
|
75
|
+
next unless in_pattern_node.condition.literal?
|
76
|
+
|
77
|
+
add_offense(in_pattern_node)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
70
82
|
def on_send(node)
|
71
83
|
return unless node.negation_method?
|
72
84
|
|
@@ -45,37 +45,52 @@ module RuboCop
|
|
45
45
|
class MissingCopEnableDirective < Base
|
46
46
|
include RangeHelp
|
47
47
|
|
48
|
-
MSG = 'Re-enable %<cop>s
|
49
|
-
MSG_BOUND = 'Re-enable %<cop>s
|
48
|
+
MSG = 'Re-enable %<cop>s %<type>s with `# rubocop:enable` after disabling it.'
|
49
|
+
MSG_BOUND = 'Re-enable %<cop>s %<type>s within %<max_range>s lines after disabling it.'
|
50
50
|
|
51
|
-
# rubocop:disable Metrics/AbcSize
|
52
51
|
def on_new_investigation
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# the case when max_range is Float::INFINITY
|
58
|
-
next if line_range.max - line_range.min < max_range + 2
|
52
|
+
each_missing_enable do |cop, line_range|
|
53
|
+
# This has to remain a strict inequality to handle
|
54
|
+
# the case when max_range is Float::INFINITY
|
55
|
+
next if line_range.max - line_range.min < max_range + 2
|
59
56
|
|
60
|
-
|
57
|
+
range = source_range(processed_source.buffer, line_range.min, (0..0))
|
58
|
+
comment = processed_source.comment_at_line(line_range.begin)
|
61
59
|
|
62
|
-
|
63
|
-
end
|
60
|
+
add_offense(range, message: message(cop, comment))
|
64
61
|
end
|
65
62
|
end
|
66
|
-
# rubocop:enable Metrics/AbcSize
|
67
63
|
|
68
64
|
private
|
69
65
|
|
70
|
-
def
|
66
|
+
def each_missing_enable
|
67
|
+
processed_source.disabled_line_ranges.each do |cop, line_ranges|
|
68
|
+
line_ranges.each { |line_range| yield cop, line_range }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def max_range
|
73
|
+
@max_range ||= cop_config['MaximumRangeSize']
|
74
|
+
end
|
75
|
+
|
76
|
+
def message(cop, comment, type = 'cop')
|
77
|
+
if department_enabled?(cop, comment)
|
78
|
+
type = 'department'
|
79
|
+
cop = cop.split('/').first
|
80
|
+
end
|
81
|
+
|
71
82
|
if max_range == Float::INFINITY
|
72
|
-
format(MSG, cop: cop)
|
83
|
+
format(MSG, cop: cop, type: type)
|
73
84
|
else
|
74
|
-
format(MSG_BOUND, cop: cop, max_range: max_range)
|
85
|
+
format(MSG_BOUND, cop: cop, type: type, max_range: max_range)
|
75
86
|
end
|
76
87
|
end
|
88
|
+
|
89
|
+
def department_enabled?(cop, comment)
|
90
|
+
DirectiveComment.new(comment).in_directive_department?(cop)
|
91
|
+
end
|
77
92
|
end
|
78
93
|
end
|
79
94
|
end
|
80
95
|
end
|
81
|
-
# rubocop:enable Lint/RedundantCopDisableDirective
|
96
|
+
# rubocop:enable Lint/RedundantCopDisableDirective
|