rubocop 1.4.2 → 1.5.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 +47 -7
- data/lib/rubocop.rb +4 -0
- data/lib/rubocop/cli.rb +5 -1
- data/lib/rubocop/cli/command/suggest_extensions.rb +67 -0
- data/lib/rubocop/config_loader.rb +1 -1
- data/lib/rubocop/config_loader_resolver.rb +5 -1
- data/lib/rubocop/config_obsoletion.rb +21 -3
- data/lib/rubocop/config_validator.rb +8 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
- data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +1 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +8 -5
- data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
- data/lib/rubocop/cop/metrics/block_length.rb +13 -7
- data/lib/rubocop/cop/metrics/method_length.rb +7 -2
- data/lib/rubocop/cop/metrics/parameter_lists.rb +64 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
- data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
- data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
- data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
- data/lib/rubocop/cop/style/and_or.rb +10 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
- data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
- data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
- data/lib/rubocop/cop/style/redundant_argument.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +49 -3
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
- data/lib/rubocop/core_ext/hash.rb +20 -0
- data/lib/rubocop/ext/regexp_node.rb +5 -10
- data/lib/rubocop/ext/regexp_parser.rb +2 -9
- data/lib/rubocop/version.rb +1 -1
- metadata +11 -7
@@ -6,7 +6,12 @@ module RuboCop
|
|
6
6
|
module Utils
|
7
7
|
# @api private
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# Identifies repetitions `&.` on the same variable:
|
10
|
+
#
|
11
|
+
# my_var&.foo
|
12
|
+
# my_var&.bar # => repeated
|
13
|
+
# my_var = baz # => reset
|
14
|
+
# my_var&.qux # => not repeated
|
10
15
|
module RepeatedCsendDiscount
|
11
16
|
def reset_repeated_csend
|
12
17
|
@repeated_csend = {}
|
@@ -4,15 +4,48 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# This module encapsulates the ability to ignore certain methods when
|
6
6
|
# parsing.
|
7
|
+
# Cops that use `IgnoredMethods` can accept either strings or regexes to match
|
8
|
+
# against.
|
7
9
|
module IgnoredMethods
|
8
|
-
|
10
|
+
# Configuration for IgnoredMethods. It is added to classes that include
|
11
|
+
# the module so that configuration can be set using the `ignored_methods`
|
12
|
+
# class macro.
|
13
|
+
module Config
|
14
|
+
attr_accessor :deprecated_key
|
15
|
+
|
16
|
+
def ignored_methods(**config)
|
17
|
+
self.deprecated_key = config[:deprecated_key]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.included(base)
|
22
|
+
base.extend(Config)
|
23
|
+
end
|
9
24
|
|
10
25
|
def ignored_method?(name)
|
11
|
-
ignored_methods.
|
26
|
+
ignored_methods.any? do |value|
|
27
|
+
case value
|
28
|
+
when Regexp
|
29
|
+
value.match? String(name)
|
30
|
+
else
|
31
|
+
value == String(name)
|
32
|
+
end
|
33
|
+
end
|
12
34
|
end
|
13
35
|
|
14
36
|
def ignored_methods
|
15
|
-
|
37
|
+
keys = %w[IgnoredMethods]
|
38
|
+
keys << deprecated_key if deprecated_key
|
39
|
+
|
40
|
+
cop_config.slice(*keys).values.reduce(&:concat)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def deprecated_key
|
46
|
+
return unless self.class.respond_to?(:deprecated_key)
|
47
|
+
|
48
|
+
self.class.deprecated_key&.to_s
|
16
49
|
end
|
17
50
|
end
|
18
51
|
end
|
@@ -11,6 +11,12 @@ module RuboCop
|
|
11
11
|
include Metrics::Utils::RepeatedCsendDiscount
|
12
12
|
extend NodePattern::Macros
|
13
13
|
|
14
|
+
# Ensure cops that include `MethodComplexity` have the config
|
15
|
+
# `attr_accessor`s that `ignored_method?` needs.
|
16
|
+
def self.included(base)
|
17
|
+
base.extend(IgnoredMethods::Config)
|
18
|
+
end
|
19
|
+
|
14
20
|
def on_def(node)
|
15
21
|
return if ignored_method?(node.method_name)
|
16
22
|
|
@@ -72,6 +72,8 @@ module RuboCop
|
|
72
72
|
end
|
73
73
|
|
74
74
|
corrector.replace(node.loc.operator, node.alternate_operator)
|
75
|
+
|
76
|
+
keep_operator_precedence(corrector, node)
|
75
77
|
end
|
76
78
|
end
|
77
79
|
|
@@ -123,6 +125,14 @@ module RuboCop
|
|
123
125
|
corrector.wrap(node, '(', ')')
|
124
126
|
end
|
125
127
|
|
128
|
+
def keep_operator_precedence(corrector, node)
|
129
|
+
if node.or_type? && node.parent&.and_type?
|
130
|
+
corrector.wrap(node, '(', ')')
|
131
|
+
elsif node.and_type? && node.rhs.or_type?
|
132
|
+
corrector.wrap(node.rhs, '(', ')')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
126
136
|
def correctable_send?(node)
|
127
137
|
!node.parenthesized? && node.arguments? && !node.method?(:[])
|
128
138
|
end
|
@@ -55,13 +55,18 @@ module RuboCop
|
|
55
55
|
padding = ((' ' * indent_width) + leading_spaces(node)).to_s
|
56
56
|
padding_for_trailing_end = padding.sub(' ' * node.loc.end.column, '')
|
57
57
|
|
58
|
-
|
58
|
+
replace_namespace_keyword(corrector, node)
|
59
59
|
split_on_double_colon(corrector, node, padding)
|
60
60
|
add_trailing_end(corrector, node, padding_for_trailing_end)
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
64
|
-
|
63
|
+
def replace_namespace_keyword(corrector, node)
|
64
|
+
class_definition = node.left_sibling&.each_node(:class)&.find do |class_node|
|
65
|
+
class_node.identifier == node.identifier.namespace
|
66
|
+
end
|
67
|
+
namespace_keyword = class_definition ? 'class' : 'module'
|
68
|
+
|
69
|
+
corrector.replace(node.loc.keyword, namespace_keyword)
|
65
70
|
end
|
66
71
|
|
67
72
|
def split_on_double_colon(corrector, node, padding)
|
@@ -17,26 +17,61 @@ module RuboCop
|
|
17
17
|
include OnNormalIfUnless
|
18
18
|
extend AutoCorrector
|
19
19
|
|
20
|
-
|
20
|
+
MSG_IF_ELSE = 'Do not use `if %<expr>s;` - use `if/else` instead.'
|
21
|
+
MSG_TERNARY = 'Do not use `if %<expr>s;` - use a ternary operator instead.'
|
21
22
|
|
22
23
|
def on_normal_if_unless(node)
|
23
24
|
return unless node.else_branch
|
25
|
+
return if node.parent&.if_type?
|
24
26
|
|
25
27
|
beginning = node.loc.begin
|
26
28
|
return unless beginning&.is?(';')
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
+
message = node.else_branch.if_type? ? MSG_IF_ELSE : MSG_TERNARY
|
31
|
+
|
32
|
+
add_offense(node, message: format(message, expr: node.condition.source)) do |corrector|
|
33
|
+
corrector.replace(node, autocorrect(node))
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
33
37
|
private
|
34
38
|
|
35
|
-
def
|
39
|
+
def autocorrect(node)
|
40
|
+
return correct_elsif(node) if node.else_branch.if_type?
|
41
|
+
|
36
42
|
else_code = node.else_branch ? node.else_branch.source : 'nil'
|
37
43
|
|
38
44
|
"#{node.condition.source} ? #{node.if_branch.source} : #{else_code}"
|
39
45
|
end
|
46
|
+
|
47
|
+
def correct_elsif(node)
|
48
|
+
<<~RUBY.chop
|
49
|
+
if #{node.condition.source}
|
50
|
+
#{node.if_branch.source}
|
51
|
+
#{build_else_branch(node.else_branch).chop}
|
52
|
+
end
|
53
|
+
RUBY
|
54
|
+
end
|
55
|
+
|
56
|
+
def build_else_branch(second_condition)
|
57
|
+
result = <<~RUBY
|
58
|
+
elsif #{second_condition.condition.source}
|
59
|
+
#{second_condition.if_branch.source}
|
60
|
+
RUBY
|
61
|
+
|
62
|
+
if second_condition.else_branch
|
63
|
+
result += if second_condition.else_branch.if_type?
|
64
|
+
build_else_branch(second_condition.else_branch)
|
65
|
+
else
|
66
|
+
<<~RUBY
|
67
|
+
else
|
68
|
+
#{second_condition.else_branch.source}
|
69
|
+
RUBY
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
result
|
74
|
+
end
|
40
75
|
end
|
41
76
|
end
|
42
77
|
end
|
@@ -21,21 +21,30 @@ module RuboCop
|
|
21
21
|
def on_send(node)
|
22
22
|
return unless !node.arguments? && node.parenthesized?
|
23
23
|
return if ineligible_node?(node)
|
24
|
+
return if default_argument?(node)
|
24
25
|
return if ignored_method?(node.method_name)
|
25
26
|
return if same_name_assignment?(node)
|
26
27
|
|
28
|
+
register_offense(node)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def register_offense(node)
|
27
34
|
add_offense(offense_range(node)) do |corrector|
|
28
35
|
corrector.remove(node.loc.begin)
|
29
36
|
corrector.remove(node.loc.end)
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
33
|
-
private
|
34
|
-
|
35
40
|
def ineligible_node?(node)
|
36
41
|
node.camel_case_method? || node.implicit_call? || node.prefix_not?
|
37
42
|
end
|
38
43
|
|
44
|
+
def default_argument?(node)
|
45
|
+
node.parent&.optarg_type?
|
46
|
+
end
|
47
|
+
|
39
48
|
def same_name_assignment?(node)
|
40
49
|
any_assignment?(node) do |asgn_node|
|
41
50
|
next variable_in_mass_assignment?(node.method_name, asgn_node) if asgn_node.masgn_type?
|
@@ -27,12 +27,13 @@ module RuboCop
|
|
27
27
|
# # bad
|
28
28
|
# 10_000_00 # typical representation of $10,000 in cents
|
29
29
|
#
|
30
|
-
class NumericLiterals <
|
30
|
+
class NumericLiterals < Base
|
31
31
|
# The parameter is called MinDigits (meaning the minimum number of
|
32
32
|
# digits for which an offense can be registered), but essentially it's
|
33
33
|
# a Max parameter (the maximum number of something that's allowed).
|
34
34
|
include ConfigurableMax
|
35
35
|
include IntegerNode
|
36
|
+
extend AutoCorrector
|
36
37
|
|
37
38
|
MSG = 'Use underscores(_) as thousands separator and ' \
|
38
39
|
'separate every 3 digits with them.'
|
@@ -46,12 +47,6 @@ module RuboCop
|
|
46
47
|
check(node)
|
47
48
|
end
|
48
49
|
|
49
|
-
def autocorrect(node)
|
50
|
-
lambda do |corrector|
|
51
|
-
corrector.replace(node, format_number(node))
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
50
|
private
|
56
51
|
|
57
52
|
def max_parameter_name
|
@@ -67,11 +62,19 @@ module RuboCop
|
|
67
62
|
|
68
63
|
case int
|
69
64
|
when /^\d+$/
|
70
|
-
|
65
|
+
return unless (self.max = int.size + 1)
|
66
|
+
|
67
|
+
register_offense(node)
|
71
68
|
when /\d{4}/, short_group_regex
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
return unless (self.config_to_allow_offenses = { 'Enabled' => false })
|
70
|
+
|
71
|
+
register_offense(node)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def register_offense(node)
|
76
|
+
add_offense(node) do |corrector|
|
77
|
+
corrector.replace(node, format_number(node))
|
75
78
|
end
|
76
79
|
end
|
77
80
|
|
@@ -131,7 +131,8 @@ module RuboCop
|
|
131
131
|
end
|
132
132
|
|
133
133
|
def without_argument_parentheses_method?(node)
|
134
|
-
node.send_type? &&
|
134
|
+
node.send_type? &&
|
135
|
+
!node.arguments.empty? && !node.parenthesized? && !node.operator_method?
|
135
136
|
end
|
136
137
|
end
|
137
138
|
end
|
@@ -82,7 +82,7 @@ module RuboCop
|
|
82
82
|
|
83
83
|
def each_escape(node)
|
84
84
|
node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
|
85
|
-
yield(expr.text[1], expr.
|
85
|
+
yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
|
86
86
|
|
87
87
|
if expr.type == :set
|
88
88
|
char_class_depth + (event == :enter ? 1 : -1)
|
@@ -33,17 +33,22 @@ module RuboCop
|
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
class SoleNestedConditional < Base
|
36
|
+
include RangeHelp
|
37
|
+
extend AutoCorrector
|
38
|
+
|
36
39
|
MSG = 'Consider merging nested conditions into '\
|
37
40
|
'outer `%<conditional_type>s` conditions.'
|
38
41
|
|
39
42
|
def on_if(node)
|
40
43
|
return if node.ternary? || node.else? || node.elsif?
|
41
44
|
|
42
|
-
|
43
|
-
return unless offending_branch?(
|
45
|
+
if_branch = node.if_branch
|
46
|
+
return unless offending_branch?(if_branch)
|
44
47
|
|
45
48
|
message = format(MSG, conditional_type: node.keyword)
|
46
|
-
add_offense(
|
49
|
+
add_offense(if_branch.loc.keyword, message: message) do |corrector|
|
50
|
+
autocorrect(corrector, node, if_branch)
|
51
|
+
end
|
47
52
|
end
|
48
53
|
|
49
54
|
private
|
@@ -57,6 +62,47 @@ module RuboCop
|
|
57
62
|
!(branch.modifier_form? && allow_modifier?)
|
58
63
|
end
|
59
64
|
|
65
|
+
def autocorrect(corrector, node, if_branch)
|
66
|
+
if node.unless?
|
67
|
+
corrector.replace(node.loc.keyword, 'if')
|
68
|
+
corrector.insert_before(node.condition, '!')
|
69
|
+
end
|
70
|
+
|
71
|
+
and_operator = if_branch.unless? ? ' && !' : ' && '
|
72
|
+
if if_branch.modifier_form?
|
73
|
+
correct_for_gurad_condition_style(corrector, node, if_branch, and_operator)
|
74
|
+
else
|
75
|
+
correct_for_basic_condition_style(corrector, node, if_branch, and_operator)
|
76
|
+
end
|
77
|
+
|
78
|
+
correct_for_comment(corrector, node, if_branch)
|
79
|
+
end
|
80
|
+
|
81
|
+
def correct_for_gurad_condition_style(corrector, node, if_branch, and_operator)
|
82
|
+
corrector.insert_after(node.condition, "#{and_operator}#{if_branch.condition.source}")
|
83
|
+
|
84
|
+
range = range_between(
|
85
|
+
if_branch.loc.keyword.begin_pos, if_branch.condition.source_range.end_pos
|
86
|
+
)
|
87
|
+
corrector.remove(range_with_surrounding_space(range: range, newlines: false))
|
88
|
+
corrector.remove(if_branch.loc.keyword)
|
89
|
+
end
|
90
|
+
|
91
|
+
def correct_for_basic_condition_style(corrector, node, if_branch, and_operator)
|
92
|
+
range = range_between(
|
93
|
+
node.condition.source_range.end_pos, if_branch.condition.source_range.begin_pos
|
94
|
+
)
|
95
|
+
corrector.replace(range, and_operator)
|
96
|
+
corrector.remove(range_by_whole_lines(node.loc.end, include_final_newline: true))
|
97
|
+
end
|
98
|
+
|
99
|
+
def correct_for_comment(corrector, node, if_branch)
|
100
|
+
comments = processed_source.comments_before_line(if_branch.source_range.line)
|
101
|
+
comment_text = comments.map(&:text).join("\n") << "\n"
|
102
|
+
|
103
|
+
corrector.insert_before(node.loc.keyword, comment_text) unless comments.empty?
|
104
|
+
end
|
105
|
+
|
60
106
|
def allow_modifier?
|
61
107
|
cop_config['AllowModifier']
|
62
108
|
end
|
@@ -8,6 +8,7 @@ module RuboCop
|
|
8
8
|
# @example
|
9
9
|
# # bad
|
10
10
|
# something.map { |s| s.upcase }
|
11
|
+
# something.map { _1.upcase }
|
11
12
|
#
|
12
13
|
# # good
|
13
14
|
# something.map(&:upcase)
|
@@ -22,9 +23,9 @@ module RuboCop
|
|
22
23
|
|
23
24
|
def_node_matcher :proc_node?, '(send (const {nil? cbase} :Proc) :new)'
|
24
25
|
def_node_matcher :symbol_proc?, <<~PATTERN
|
25
|
-
(block
|
26
|
+
({block numblock}
|
26
27
|
${(send ...) (super ...) zsuper}
|
27
|
-
$(args (arg
|
28
|
+
${(args (arg _)) %Integer}
|
28
29
|
(send (lvar _var) $_))
|
29
30
|
PATTERN
|
30
31
|
|
@@ -40,11 +41,12 @@ module RuboCop
|
|
40
41
|
return if proc_node?(dispatch_node)
|
41
42
|
return if %i[lambda proc].include?(dispatch_node.method_name)
|
42
43
|
return if ignored_method?(dispatch_node.method_name)
|
43
|
-
return if destructuring_block_argument?(arguments_node)
|
44
|
+
return if node.block_type? && destructuring_block_argument?(arguments_node)
|
44
45
|
|
45
46
|
register_offense(node, method_name, dispatch_node.method_name)
|
46
47
|
end
|
47
48
|
end
|
49
|
+
alias on_numblock on_block
|
48
50
|
|
49
51
|
def destructuring_block_argument?(argument_node)
|
50
52
|
argument_node.one? && argument_node.source.include?(',')
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Extensions to the core Hash class
|
4
|
+
class Hash
|
5
|
+
unless method_defined?(:slice)
|
6
|
+
# Adds `Hash#slice` for Ruby 2.4.
|
7
|
+
# Returns a hash containing a subset of keys. If a given key is not
|
8
|
+
# in the hash, it will not be returned.
|
9
|
+
#
|
10
|
+
# @return [Hash] hash containing only the keys given.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# { one: 1, two: 2 }.slice(:two, :three) #=> { two: 2 }
|
14
|
+
def slice(*keys)
|
15
|
+
h = {}
|
16
|
+
keys.each { |k| h[k] = self[k] if key?(k) }
|
17
|
+
h
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -19,18 +19,13 @@ module RuboCop
|
|
19
19
|
super
|
20
20
|
|
21
21
|
str = with_interpolations_blanked
|
22
|
-
begin
|
23
|
-
|
22
|
+
@parsed_tree = begin
|
23
|
+
Regexp::Parser.parse(str, options: options)
|
24
24
|
rescue StandardError
|
25
|
-
|
26
|
-
else
|
27
|
-
origin = loc.begin.end
|
28
|
-
source = @parsed_tree.to_s
|
29
|
-
@parsed_tree.each_expression(true) do |e|
|
30
|
-
e.origin = origin
|
31
|
-
e.source = source
|
32
|
-
end
|
25
|
+
nil
|
33
26
|
end
|
27
|
+
origin = loc.begin.end
|
28
|
+
@parsed_tree&.each_expression(true) { |e| e.origin = origin }
|
34
29
|
end
|
35
30
|
|
36
31
|
def each_capture(named: ANY)
|