rubocop 1.38.0 → 1.40.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 +51 -11
- data/exe/rubocop +1 -1
- data/lib/rubocop/comment_config.rb +5 -0
- data/lib/rubocop/config.rb +5 -4
- data/lib/rubocop/config_loader.rb +5 -5
- data/lib/rubocop/config_loader_resolver.rb +1 -1
- data/lib/rubocop/cop/base.rb +2 -9
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
- data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
- data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
- data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +17 -8
- data/lib/rubocop/cop/lint/empty_block.rb +1 -5
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +13 -3
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +15 -6
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +6 -6
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +9 -4
- data/lib/rubocop/cop/metrics/class_length.rb +9 -4
- data/lib/rubocop/cop/metrics/method_length.rb +9 -4
- data/lib/rubocop/cop/metrics/module_length.rb +9 -4
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -2
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +24 -5
- data/lib/rubocop/cop/mixin/range_help.rb +23 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
- data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
- data/lib/rubocop/cop/registry.rb +23 -11
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -25
- data/lib/rubocop/cop/style/array_intersect.rb +111 -0
- data/lib/rubocop/cop/style/class_equality_comparison.rb +7 -5
- data/lib/rubocop/cop/style/collection_compact.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +32 -5
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
- data/lib/rubocop/cop/style/hash_except.rb +4 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -1
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +3 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +13 -0
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
- data/lib/rubocop/cop/style/redundant_constant_base.rb +72 -0
- data/lib/rubocop/cop/style/redundant_each.rb +13 -8
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
- data/lib/rubocop/cop/style/redundant_return.rb +7 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/require_order.rb +88 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
- data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
- data/lib/rubocop/cop/style/string_literals.rb +1 -5
- data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +2 -2
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +20 -29
- data/lib/rubocop/cops_documentation_generator.rb +3 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +3 -1
- data/lib/rubocop/optimized_patterns.rb +38 -0
- data/lib/rubocop/options.rb +9 -1
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/rspec/cop_helper.rb +4 -1
- data/lib/rubocop/rspec/support.rb +2 -2
- data/lib/rubocop/server/core.rb +16 -1
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +14 -6
- metadata +8 -3
@@ -14,7 +14,8 @@ module RuboCop
|
|
14
14
|
# Alternative: 'alternative_value'
|
15
15
|
# DeprecatedVersion: 'deprecated_version'
|
16
16
|
#
|
17
|
-
# By default, `NIL`, `TRUE`, `FALSE`
|
17
|
+
# By default, `NIL`, `TRUE`, `FALSE`, `Net::HTTPServerException, `Random::DEFAULT`,
|
18
|
+
# `Struct::Group`, and `Struct::Passwd` are configured.
|
18
19
|
#
|
19
20
|
# @example
|
20
21
|
#
|
@@ -22,13 +23,19 @@ module RuboCop
|
|
22
23
|
# NIL
|
23
24
|
# TRUE
|
24
25
|
# FALSE
|
26
|
+
# Net::HTTPServerException
|
25
27
|
# Random::DEFAULT # Return value of Ruby 2 is `Random` instance, Ruby 3.0 is `Random` class.
|
28
|
+
# Struct::Group
|
29
|
+
# Struct::Passwd
|
26
30
|
#
|
27
31
|
# # good
|
28
32
|
# nil
|
29
33
|
# true
|
30
34
|
# false
|
35
|
+
# Net::HTTPClientException
|
31
36
|
# Random.new # `::DEFAULT` has been deprecated in Ruby 3, `.new` is compatible with Ruby 2.
|
37
|
+
# Etc::Group
|
38
|
+
# Etc::Passwd
|
32
39
|
#
|
33
40
|
class DeprecatedConstants < Base
|
34
41
|
extend AutoCorrector
|
@@ -51,8 +51,8 @@ module RuboCop
|
|
51
51
|
# alias bar foo
|
52
52
|
class DuplicateMethods < Base
|
53
53
|
MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
|
54
|
-
|
55
54
|
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr].freeze
|
55
|
+
DEF_TYPES = %i[def defs].freeze
|
56
56
|
|
57
57
|
def initialize(config = nil, options = nil)
|
58
58
|
super
|
@@ -127,8 +127,8 @@ module RuboCop
|
|
127
127
|
found_method(node, "#{enclosing}.#{name}")
|
128
128
|
end
|
129
129
|
|
130
|
-
def message_for_dup(node, method_name)
|
131
|
-
format(MSG, method: method_name, defined: source_location(@definitions[
|
130
|
+
def message_for_dup(node, method_name, key)
|
131
|
+
format(MSG, method: method_name, defined: source_location(@definitions[key]),
|
132
132
|
current: source_location(node))
|
133
133
|
end
|
134
134
|
|
@@ -156,18 +156,27 @@ module RuboCop
|
|
156
156
|
end
|
157
157
|
|
158
158
|
def found_method(node, method_name)
|
159
|
-
|
160
|
-
|
161
|
-
|
159
|
+
key = method_key(node, method_name)
|
160
|
+
|
161
|
+
if @definitions.key?(key)
|
162
|
+
loc = if DEF_TYPES.include?(node.type)
|
162
163
|
node.loc.keyword.join(node.loc.name)
|
163
164
|
else
|
164
165
|
node.loc.expression
|
165
166
|
end
|
166
|
-
message = message_for_dup(node, method_name)
|
167
|
+
message = message_for_dup(node, method_name, key)
|
167
168
|
|
168
169
|
add_offense(loc, message: message)
|
169
170
|
else
|
170
|
-
@definitions[
|
171
|
+
@definitions[key] = node
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def method_key(node, method_name)
|
176
|
+
if (ancestor_def = node.each_ancestor(*DEF_TYPES).first)
|
177
|
+
"#{ancestor_def.method_name}.#{method_name}"
|
178
|
+
else
|
179
|
+
method_name
|
171
180
|
end
|
172
181
|
end
|
173
182
|
|
@@ -65,7 +65,7 @@ module RuboCop
|
|
65
65
|
|
66
66
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
67
67
|
return if node.body
|
68
|
-
return if allow_empty_lambdas? && lambda_or_proc?
|
68
|
+
return if allow_empty_lambdas? && node.lambda_or_proc?
|
69
69
|
return if cop_config['AllowComments'] && allow_comment?(node)
|
70
70
|
|
71
71
|
add_offense(node)
|
@@ -88,10 +88,6 @@ module RuboCop
|
|
88
88
|
regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
|
89
89
|
Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
|
90
90
|
end
|
91
|
-
|
92
|
-
def lambda_or_proc?(node)
|
93
|
-
node.lambda? || node.proc?
|
94
|
-
end
|
95
91
|
end
|
96
92
|
end
|
97
93
|
end
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
MSG = 'Avoid `%<keyword>s` branches without a body.'
|
69
69
|
|
70
70
|
def on_if(node)
|
71
|
-
return if node.body
|
71
|
+
return if node.body || same_line?(node.loc.begin, node.loc.end)
|
72
72
|
return if cop_config['AllowComments'] && contains_comments?(node)
|
73
73
|
|
74
74
|
add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
|
@@ -6,9 +6,10 @@ module RuboCop
|
|
6
6
|
# Checks for interpolation in a single quoted string.
|
7
7
|
#
|
8
8
|
# @safety
|
9
|
-
# This cop is
|
10
|
-
# it is
|
11
|
-
#
|
9
|
+
# This cop's autocorrection is unsafe because although it always replaces single quotes as
|
10
|
+
# if it were miswritten double quotes, it is not always the case. For example,
|
11
|
+
# `'#{foo} bar'` would be replaced by `"#{foo} bar"`, so the replaced code would evaluate
|
12
|
+
# the expression `foo`.
|
12
13
|
#
|
13
14
|
# @example
|
14
15
|
#
|
@@ -40,11 +40,16 @@ module RuboCop
|
|
40
40
|
unless node.arguments.one? && first_argument_starts_with_left_parenthesis?(node)
|
41
41
|
return true
|
42
42
|
end
|
43
|
+
return true if first_argument_block_type?(node.first_argument)
|
43
44
|
|
44
45
|
node.operator_method? || node.setter_method? || chained_calls?(node) ||
|
45
46
|
valid_first_argument?(node.first_argument)
|
46
47
|
end
|
47
48
|
|
49
|
+
def first_argument_block_type?(first_arg)
|
50
|
+
first_arg.block_type? || first_arg.numblock_type?
|
51
|
+
end
|
52
|
+
|
48
53
|
def valid_first_argument?(first_arg)
|
49
54
|
first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg)
|
50
55
|
end
|
@@ -131,18 +131,28 @@ module RuboCop
|
|
131
131
|
def each_already_disabled(cop, line_ranges)
|
132
132
|
line_ranges.each_cons(2) do |previous_range, range|
|
133
133
|
next if ignore_offense?(range)
|
134
|
-
next unless followed_ranges?(previous_range, range)
|
135
|
-
|
136
134
|
# If a cop is disabled in a range that begins on the same line as
|
137
135
|
# the end of the previous range, it means that the cop was
|
138
136
|
# already disabled by an earlier comment. So it's redundant
|
139
137
|
# whether there are offenses or not.
|
138
|
+
next unless followed_ranges?(previous_range, range)
|
139
|
+
|
140
140
|
comment = processed_source.comment_at_line(range.begin)
|
141
141
|
|
142
|
+
next unless comment
|
142
143
|
# Comments disabling all cops don't count since it's reasonable
|
143
144
|
# to disable a few select cops first and then all cops further
|
144
145
|
# down in the code.
|
145
|
-
|
146
|
+
next if all_disabled?(comment)
|
147
|
+
|
148
|
+
redundant =
|
149
|
+
if department_disabled?(cop, comment)
|
150
|
+
find_redundant_department(cop, range)
|
151
|
+
else
|
152
|
+
cop
|
153
|
+
end
|
154
|
+
|
155
|
+
yield comment, redundant
|
146
156
|
end
|
147
157
|
end
|
148
158
|
|
@@ -62,15 +62,16 @@ module RuboCop
|
|
62
62
|
# @param [RuboCop::AST::SendNode] send_node
|
63
63
|
# @return [String]
|
64
64
|
def add_safe_navigation_operator(offense_range:, send_node:)
|
65
|
-
source =
|
66
|
-
if
|
65
|
+
source =
|
66
|
+
if (brackets = find_brackets(send_node))
|
67
67
|
format(
|
68
|
-
'%<method_name>s(%<arguments>s)',
|
69
|
-
arguments:
|
70
|
-
method_name:
|
68
|
+
'%<method_name>s(%<arguments>s)%<method_chain>s',
|
69
|
+
arguments: brackets.arguments.map(&:source).join(', '),
|
70
|
+
method_name: brackets.method_name,
|
71
|
+
method_chain: brackets.source_range.end.join(send_node.source_range.end).source
|
71
72
|
)
|
72
73
|
else
|
73
|
-
offense_range.source
|
74
|
+
offense_range.source
|
74
75
|
end
|
75
76
|
source.prepend('.') unless source.start_with?('.')
|
76
77
|
source.prepend('&')
|
@@ -94,6 +95,14 @@ module RuboCop
|
|
94
95
|
chain = chain.parent if chain.send_type? && chain.parent&.call_type?
|
95
96
|
chain
|
96
97
|
end
|
98
|
+
|
99
|
+
def find_brackets(send_node)
|
100
|
+
return send_node if send_node.method?(:[]) || send_node.method?(:[]=)
|
101
|
+
|
102
|
+
send_node.descendants.detect do |node|
|
103
|
+
node.send_type? && (node.method?(:[]) || node.method?(:[]=))
|
104
|
+
end
|
105
|
+
end
|
97
106
|
end
|
98
107
|
end
|
99
108
|
end
|
@@ -48,16 +48,17 @@ module RuboCop
|
|
48
48
|
(send
|
49
49
|
(const _ _) {:#{SEND_METHODS.join(' :')}}
|
50
50
|
({sym str} $#mixin_method?)
|
51
|
-
$(const _ _))
|
51
|
+
$(const _ _)+)
|
52
52
|
PATTERN
|
53
53
|
|
54
54
|
def on_send(node)
|
55
|
-
send_with_mixin_argument?(node) do |method,
|
56
|
-
|
55
|
+
send_with_mixin_argument?(node) do |method, module_names|
|
56
|
+
module_names_source = module_names.map(&:source).join(', ')
|
57
|
+
message = message(method, module_names_source, bad_location(node).source)
|
57
58
|
|
58
59
|
bad_location = bad_location(node)
|
59
60
|
add_offense(bad_location, message: message) do |corrector|
|
60
|
-
corrector.replace(bad_location, "#{method} #{
|
61
|
+
corrector.replace(bad_location, "#{method} #{module_names_source}")
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
@@ -73,10 +73,11 @@ module RuboCop
|
|
73
73
|
outer_local_variable_node =
|
74
74
|
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
75
75
|
return true unless outer_local_variable_node
|
76
|
+
return false unless outer_local_variable_node.conditional?
|
77
|
+
return true if variable_node == outer_local_variable_node
|
76
78
|
|
77
|
-
outer_local_variable_node.
|
78
|
-
|
79
|
-
variable_node == outer_local_variable_node.else_branch)
|
79
|
+
outer_local_variable_node.if_type? &&
|
80
|
+
variable_node == outer_local_variable_node.else_branch
|
80
81
|
end
|
81
82
|
|
82
83
|
def variable_node(variable)
|
@@ -116,7 +116,7 @@ module RuboCop
|
|
116
116
|
private
|
117
117
|
|
118
118
|
def comment_between_rescue_and_end?(node)
|
119
|
-
ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block).first
|
119
|
+
ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first
|
120
120
|
return unless ancestor
|
121
121
|
|
122
122
|
end_line = ancestor.loc.end.line
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Checks for operators, variables, literals, and nonmutating
|
6
|
+
# Checks for operators, variables, literals, lambda, proc and nonmutating
|
7
7
|
# methods used in void context.
|
8
8
|
#
|
9
9
|
# @example CheckForMethodsWithNoSideEffects: false (default)
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
VAR_MSG = 'Variable `%<var>s` used in void context.'
|
46
46
|
LIT_MSG = 'Literal `%<lit>s` used in void context.'
|
47
47
|
SELF_MSG = '`self` used in void context.'
|
48
|
-
|
48
|
+
EXPRESSION_MSG = '`%<expression>s` used in void context.'
|
49
49
|
NONMUTATING_MSG = 'Method `#%<method>s` used in void context. Did you mean `#%<method>s!`?'
|
50
50
|
|
51
51
|
BINARY_OPERATORS = %i[* / % + - == === != < > <= >= <=>].freeze
|
@@ -87,7 +87,7 @@ module RuboCop
|
|
87
87
|
check_literal(expr)
|
88
88
|
check_var(expr)
|
89
89
|
check_self(expr)
|
90
|
-
|
90
|
+
check_void_expression(expr)
|
91
91
|
return unless cop_config['CheckForMethodsWithNoSideEffects']
|
92
92
|
|
93
93
|
check_nonmutating(expr)
|
@@ -117,10 +117,10 @@ module RuboCop
|
|
117
117
|
add_offense(node, message: SELF_MSG)
|
118
118
|
end
|
119
119
|
|
120
|
-
def
|
121
|
-
return unless node.defined_type?
|
120
|
+
def check_void_expression(node)
|
121
|
+
return unless node.defined_type? || node.lambda_or_proc?
|
122
122
|
|
123
|
-
add_offense(node, message: format(
|
123
|
+
add_offense(node, message: format(EXPRESSION_MSG, expression: node.source))
|
124
124
|
end
|
125
125
|
|
126
126
|
def check_nonmutating(node)
|
@@ -20,7 +20,7 @@ module RuboCop
|
|
20
20
|
#
|
21
21
|
# @example CountRepeatedAttributes: false (default is true)
|
22
22
|
#
|
23
|
-
# # `model` and `current_user`,
|
23
|
+
# # `model` and `current_user`, referenced 3 times each,
|
24
24
|
# # are each counted as only 1 branch each if
|
25
25
|
# # `CountRepeatedAttributes` is set to 'false'
|
26
26
|
#
|
@@ -8,8 +8,8 @@ module RuboCop
|
|
8
8
|
# The maximum allowed length is configurable.
|
9
9
|
# The cop can be configured to ignore blocks passed to certain methods.
|
10
10
|
#
|
11
|
-
# You can set
|
12
|
-
# Available are: 'array', 'hash', and '
|
11
|
+
# You can set constructs you want to fold with `CountAsOne`.
|
12
|
+
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
13
13
|
# will be counted as one line regardless of its actual size.
|
14
14
|
#
|
15
15
|
#
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
# for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
|
18
18
|
# instead. By default, there are no methods to allowed.
|
19
19
|
#
|
20
|
-
# @example CountAsOne: ['array', 'heredoc']
|
20
|
+
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
21
21
|
#
|
22
22
|
# something do
|
23
23
|
# array = [ # +1
|
@@ -33,7 +33,12 @@ module RuboCop
|
|
33
33
|
# Heredoc
|
34
34
|
# content.
|
35
35
|
# HEREDOC
|
36
|
-
#
|
36
|
+
#
|
37
|
+
# foo( # +1
|
38
|
+
# 1,
|
39
|
+
# 2
|
40
|
+
# )
|
41
|
+
# end # 6 points
|
37
42
|
#
|
38
43
|
# NOTE: This cop does not apply for `Struct` definitions.
|
39
44
|
class BlockLength < Base
|
@@ -7,11 +7,11 @@ module RuboCop
|
|
7
7
|
# Comment lines can optionally be ignored.
|
8
8
|
# The maximum allowed length is configurable.
|
9
9
|
#
|
10
|
-
# You can set
|
11
|
-
# Available are: 'array', 'hash', and '
|
10
|
+
# You can set constructs you want to fold with `CountAsOne`.
|
11
|
+
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
12
12
|
# will be counted as one line regardless of its actual size.
|
13
13
|
#
|
14
|
-
# @example CountAsOne: ['array', 'heredoc']
|
14
|
+
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
15
15
|
#
|
16
16
|
# class Foo
|
17
17
|
# ARRAY = [ # +1
|
@@ -27,7 +27,12 @@ module RuboCop
|
|
27
27
|
# Heredoc
|
28
28
|
# content.
|
29
29
|
# HEREDOC
|
30
|
-
#
|
30
|
+
#
|
31
|
+
# foo( # +1
|
32
|
+
# 1,
|
33
|
+
# 2
|
34
|
+
# )
|
35
|
+
# end # 6 points
|
31
36
|
#
|
32
37
|
#
|
33
38
|
# NOTE: This cop also applies for `Struct` definitions.
|
@@ -7,8 +7,8 @@ module RuboCop
|
|
7
7
|
# Comment lines can optionally be allowed.
|
8
8
|
# The maximum allowed length is configurable.
|
9
9
|
#
|
10
|
-
# You can set
|
11
|
-
# Available are: 'array', 'hash', and '
|
10
|
+
# You can set constructs you want to fold with `CountAsOne`.
|
11
|
+
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
12
12
|
# will be counted as one line regardless of its actual size.
|
13
13
|
#
|
14
14
|
# NOTE: The `ExcludedMethods` and `IgnoredMethods` configuration is
|
@@ -16,7 +16,7 @@ module RuboCop
|
|
16
16
|
# Please use `AllowedMethods` and `AllowedPatterns` instead.
|
17
17
|
# By default, there are no methods to allowed.
|
18
18
|
#
|
19
|
-
# @example CountAsOne: ['array', 'heredoc']
|
19
|
+
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
20
20
|
#
|
21
21
|
# def m
|
22
22
|
# array = [ # +1
|
@@ -32,7 +32,12 @@ module RuboCop
|
|
32
32
|
# Heredoc
|
33
33
|
# content.
|
34
34
|
# HEREDOC
|
35
|
-
#
|
35
|
+
#
|
36
|
+
# foo( # +1
|
37
|
+
# 1,
|
38
|
+
# 2
|
39
|
+
# )
|
40
|
+
# end # 6 points
|
36
41
|
#
|
37
42
|
class MethodLength < Base
|
38
43
|
include CodeLength
|
@@ -7,11 +7,11 @@ module RuboCop
|
|
7
7
|
# Comment lines can optionally be ignored.
|
8
8
|
# The maximum allowed length is configurable.
|
9
9
|
#
|
10
|
-
# You can set
|
11
|
-
# Available are: 'array', 'hash', and '
|
10
|
+
# You can set constructs you want to fold with `CountAsOne`.
|
11
|
+
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
12
12
|
# will be counted as one line regardless of its actual size.
|
13
13
|
#
|
14
|
-
# @example CountAsOne: ['array', 'heredoc']
|
14
|
+
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
15
15
|
#
|
16
16
|
# module M
|
17
17
|
# ARRAY = [ # +1
|
@@ -27,7 +27,12 @@ module RuboCop
|
|
27
27
|
# Heredoc
|
28
28
|
# content.
|
29
29
|
# HEREDOC
|
30
|
-
#
|
30
|
+
#
|
31
|
+
# foo( # +1
|
32
|
+
# 1,
|
33
|
+
# 2
|
34
|
+
# )
|
35
|
+
# end # 6 points
|
31
36
|
#
|
32
37
|
class ModuleLength < Base
|
33
38
|
include CodeLength
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
extend NodePattern::Macros
|
10
10
|
include Util
|
11
11
|
|
12
|
-
FOLDABLE_TYPES = %i[array hash heredoc].freeze
|
12
|
+
FOLDABLE_TYPES = %i[array hash heredoc send csend].freeze
|
13
13
|
CLASSLIKE_TYPES = %i[class module].freeze
|
14
14
|
private_constant :FOLDABLE_TYPES, :CLASSLIKE_TYPES
|
15
15
|
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
39
39
|
|
40
40
|
private
|
41
41
|
|
42
|
-
def build_foldable_checks(types)
|
42
|
+
def build_foldable_checks(types) # rubocop:disable Metrics/MethodLength
|
43
43
|
types.map do |type|
|
44
44
|
case type
|
45
45
|
when :array
|
@@ -48,6 +48,8 @@ module RuboCop
|
|
48
48
|
->(node) { node.hash_type? }
|
49
49
|
when :heredoc
|
50
50
|
->(node) { heredoc_node?(node) }
|
51
|
+
when :method_call
|
52
|
+
->(node) { node.call_type? }
|
51
53
|
else
|
52
54
|
raise ArgumentError, "Unknown foldable type: #{type.inspect}. " \
|
53
55
|
"Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}."
|
@@ -57,6 +59,7 @@ module RuboCop
|
|
57
59
|
|
58
60
|
def normalize_foldable_types(types)
|
59
61
|
types.concat(%i[str dstr]) if types.delete(:heredoc)
|
62
|
+
types.concat(%i[send csend]) if types.delete(:method_call)
|
60
63
|
types
|
61
64
|
end
|
62
65
|
|
@@ -47,6 +47,12 @@ module RuboCop
|
|
47
47
|
|
48
48
|
def register_offense(node, message, replacement)
|
49
49
|
add_offense(node.value, message: message) do |corrector|
|
50
|
+
if (def_node = def_node_that_require_parentheses(node))
|
51
|
+
white_spaces = range_between(def_node.loc.selector.end_pos,
|
52
|
+
def_node.first_argument.source_range.begin_pos)
|
53
|
+
corrector.replace(white_spaces, '(')
|
54
|
+
corrector.insert_after(def_node.arguments.last, ')')
|
55
|
+
end
|
50
56
|
corrector.replace(node, replacement)
|
51
57
|
end
|
52
58
|
end
|
@@ -76,12 +82,25 @@ module RuboCop
|
|
76
82
|
end
|
77
83
|
|
78
84
|
def require_hash_value_for_around_hash_literal?(node)
|
79
|
-
return false unless (
|
80
|
-
|
85
|
+
return false unless (send_node = find_ancestor_send_node(node))
|
86
|
+
|
87
|
+
!node.parent.braces? && !use_element_of_hash_literal_as_receiver?(send_node, node.parent) &&
|
88
|
+
use_modifier_form_without_parenthesized_method_call?(send_node)
|
89
|
+
end
|
90
|
+
|
91
|
+
def def_node_that_require_parentheses(node)
|
92
|
+
return unless (send_node = find_ancestor_send_node(node))
|
93
|
+
return unless without_parentheses_call_expr_follows?(send_node)
|
94
|
+
|
95
|
+
def_node = node.each_ancestor(:send, :csend).first
|
96
|
+
|
97
|
+
def_node unless def_node && def_node.arguments.empty?
|
98
|
+
end
|
99
|
+
|
100
|
+
def find_ancestor_send_node(node)
|
101
|
+
ancestor = node.parent.parent
|
81
102
|
|
82
|
-
|
83
|
-
(use_modifier_form_without_parenthesized_method_call?(ancestor) ||
|
84
|
-
without_parentheses_call_expr_follows?(ancestor))
|
103
|
+
ancestor if ancestor&.call_type? && !ancestor&.method?(:[])
|
85
104
|
end
|
86
105
|
|
87
106
|
def use_element_of_hash_literal_as_receiver?(ancestor, parent)
|
@@ -126,6 +126,29 @@ module RuboCop
|
|
126
126
|
pos += size * step while condition && src[pos + offset, size] == needle
|
127
127
|
pos.negative? ? 0 : pos
|
128
128
|
end
|
129
|
+
|
130
|
+
def range_with_comments_and_lines(node)
|
131
|
+
range_by_whole_lines(range_with_comments(node), include_final_newline: true)
|
132
|
+
end
|
133
|
+
|
134
|
+
def range_with_comments(node)
|
135
|
+
ranges = [
|
136
|
+
node,
|
137
|
+
*@processed_source.ast_with_comments[node]
|
138
|
+
].map do |element|
|
139
|
+
element.location.expression
|
140
|
+
end
|
141
|
+
ranges.reduce do |result, range|
|
142
|
+
add_range(result, range)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def add_range(range1, range2)
|
147
|
+
range1.with(
|
148
|
+
begin_pos: [range1.begin_pos, range2.begin_pos].min,
|
149
|
+
end_pos: [range1.end_pos, range2.end_pos].max
|
150
|
+
)
|
151
|
+
end
|
129
152
|
end
|
130
153
|
end
|
131
154
|
end
|
@@ -48,11 +48,25 @@ module RuboCop
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def to_modifier_form(node)
|
51
|
-
|
51
|
+
body = if_body_source(node.body)
|
52
|
+
expression = [body, node.keyword, node.condition.source].compact.join(' ')
|
52
53
|
parenthesized = parenthesize?(node) ? "(#{expression})" : expression
|
53
54
|
[parenthesized, first_line_comment(node)].compact.join(' ')
|
54
55
|
end
|
55
56
|
|
57
|
+
def if_body_source(if_body)
|
58
|
+
if if_body.call_type? &&
|
59
|
+
if_body.last_argument&.hash_type? && if_body.last_argument.pairs.last.value_omission?
|
60
|
+
"#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
|
61
|
+
else
|
62
|
+
if_body.source
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def method_source(if_body)
|
67
|
+
range_between(if_body.loc.expression.begin_pos, if_body.loc.selector.end_pos).source
|
68
|
+
end
|
69
|
+
|
56
70
|
def first_line_comment(node)
|
57
71
|
comment = processed_source.find_comment { |c| same_line?(c, node) }
|
58
72
|
return unless comment
|
@@ -1,18 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
4
|
+
|
3
5
|
module RuboCop
|
4
6
|
module Cop
|
5
7
|
# Help methods for determining node visibility.
|
6
8
|
module VisibilityHelp
|
7
9
|
extend NodePattern::Macros
|
8
10
|
|
9
|
-
VISIBILITY_SCOPES =
|
11
|
+
VISIBILITY_SCOPES = ::Set[:private, :protected, :public].freeze
|
10
12
|
|
11
13
|
private
|
12
14
|
|
13
15
|
def node_visibility(node)
|
14
|
-
|
15
|
-
|
16
|
+
node_visibility_from_visibility_inline(node) ||
|
17
|
+
node_visibility_from_visibility_block(node) ||
|
18
|
+
:public
|
19
|
+
end
|
20
|
+
|
21
|
+
def node_visibility_from_visibility_inline(node)
|
22
|
+
return unless node.def_type?
|
23
|
+
|
24
|
+
node_visibility_from_visibility_inline_on_def(node) ||
|
25
|
+
node_visibility_from_visibility_inline_on_method_name(node)
|
26
|
+
end
|
27
|
+
|
28
|
+
def node_visibility_from_visibility_inline_on_def(node)
|
29
|
+
parent = node.parent
|
30
|
+
parent.method_name if visibility_inline_on_def?(parent)
|
31
|
+
end
|
32
|
+
|
33
|
+
def node_visibility_from_visibility_inline_on_method_name(node)
|
34
|
+
node.right_siblings.reverse.find do |sibling|
|
35
|
+
visibility_inline_on_method_name?(sibling, method_name: node.method_name)
|
36
|
+
end&.method_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def node_visibility_from_visibility_block(node)
|
40
|
+
find_visibility_start(node)&.method_name
|
16
41
|
end
|
17
42
|
|
18
43
|
def find_visibility_start(node)
|
@@ -21,7 +46,7 @@ module RuboCop
|
|
21
46
|
|
22
47
|
# Navigate to find the last protected method
|
23
48
|
def find_visibility_end(node)
|
24
|
-
possible_visibilities = VISIBILITY_SCOPES - [node_visibility(node)]
|
49
|
+
possible_visibilities = VISIBILITY_SCOPES - ::Set[node_visibility(node)]
|
25
50
|
right = node.right_siblings
|
26
51
|
right.find do |child_node|
|
27
52
|
possible_visibilities.include?(node_visibility(child_node))
|
@@ -30,7 +55,17 @@ module RuboCop
|
|
30
55
|
|
31
56
|
# @!method visibility_block?(node)
|
32
57
|
def_node_matcher :visibility_block?, <<~PATTERN
|
33
|
-
(send nil?
|
58
|
+
(send nil? VISIBILITY_SCOPES)
|
59
|
+
PATTERN
|
60
|
+
|
61
|
+
# @!method visibility_inline_on_def?(node)
|
62
|
+
def_node_matcher :visibility_inline_on_def?, <<~PATTERN
|
63
|
+
(send nil? VISIBILITY_SCOPES def)
|
64
|
+
PATTERN
|
65
|
+
|
66
|
+
# @!method visibility_inline_on_method_name?(node, method_name:)
|
67
|
+
def_node_matcher :visibility_inline_on_method_name?, <<~PATTERN
|
68
|
+
(send nil? VISIBILITY_SCOPES (sym %method_name))
|
34
69
|
PATTERN
|
35
70
|
end
|
36
71
|
end
|