rubocop 1.32.0 → 1.34.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +51 -16
- data/config/obsoletion.yml +23 -1
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
- data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
- data/lib/rubocop/cli/command/suggest_extensions.rb +53 -15
- data/lib/rubocop/config_finder.rb +68 -0
- data/lib/rubocop/config_loader.rb +12 -40
- data/lib/rubocop/config_loader_resolver.rb +1 -5
- data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
- data/lib/rubocop/config_obsoletion.rb +7 -2
- data/lib/rubocop/cop/cop.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +28 -0
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +61 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/block_end_newline.rb +33 -5
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/legacy/corrections_proxy.rb +1 -1
- data/lib/rubocop/cop/legacy/corrector.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +21 -8
- data/lib/rubocop/cop/lint/debugger.rb +26 -16
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +65 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +24 -8
- data/lib/rubocop/cop/lint/shadowed_exception.rb +15 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +9 -1
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
- data/lib/rubocop/cop/metrics/block_length.rb +6 -7
- data/lib/rubocop/cop/metrics/method_length.rb +8 -8
- data/lib/rubocop/cop/mixin/allowed_methods.rb +15 -1
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +4 -9
- data/lib/rubocop/cop/mixin/range_help.rb +2 -2
- data/lib/rubocop/cop/naming/predicate_name.rb +24 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
- data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +32 -7
- data/lib/rubocop/cop/style/double_negation.rb +2 -0
- data/lib/rubocop/cop/style/empty_heredoc.rb +15 -1
- data/lib/rubocop/cop/style/format_string_token.rb +21 -8
- data/lib/rubocop/cop/style/hash_except.rb +0 -4
- data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -6
- data/lib/rubocop/cop/style/numeric_literals.rb +16 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +28 -8
- data/lib/rubocop/cop/style/redundant_condition.rb +19 -4
- data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -22
- data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -3
- data/lib/rubocop/cop/style/symbol_proc.rb +34 -9
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -13
- data/lib/rubocop/ext/range.rb +15 -0
- data/lib/rubocop/feature_loader.rb +90 -0
- data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -1
- data/lib/rubocop/formatter/tap_formatter.rb +1 -1
- data/lib/rubocop/result_cache.rb +22 -20
- data/lib/rubocop/server/cache.rb +33 -1
- data/lib/rubocop/server/cli.rb +19 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +2 -1
- metadata +13 -9
- data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
@@ -5,9 +5,13 @@ module RuboCop
|
|
5
5
|
# This autocorrects parentheses
|
6
6
|
class ParenthesesCorrector
|
7
7
|
class << self
|
8
|
+
include RangeHelp
|
9
|
+
|
8
10
|
def correct(corrector, node)
|
9
11
|
corrector.remove(node.loc.begin)
|
10
12
|
corrector.remove(node.loc.end)
|
13
|
+
handle_orphaned_comma(corrector, node)
|
14
|
+
|
11
15
|
return unless ternary_condition?(node) && next_char_is_question_mark?(node)
|
12
16
|
|
13
17
|
corrector.insert_after(node.loc.end, ' ')
|
@@ -22,6 +26,30 @@ module RuboCop
|
|
22
26
|
def next_char_is_question_mark?(node)
|
23
27
|
node.loc.last_column == node.parent.loc.question.column
|
24
28
|
end
|
29
|
+
|
30
|
+
def only_closing_paren_before_comma?(node)
|
31
|
+
source_buffer = node.source_range.source_buffer
|
32
|
+
line_range = source_buffer.line_range(node.loc.end.line)
|
33
|
+
|
34
|
+
line_range.source.start_with?(/\s*\)\s*,/)
|
35
|
+
end
|
36
|
+
|
37
|
+
# If removing parentheses leaves a comma on its own line, remove all the whitespace
|
38
|
+
# preceding it to prevent a syntax error.
|
39
|
+
def handle_orphaned_comma(corrector, node)
|
40
|
+
return unless only_closing_paren_before_comma?(node)
|
41
|
+
|
42
|
+
range = range_with_surrounding_space(
|
43
|
+
range: node.loc.end,
|
44
|
+
buffer: node.source_range.source_buffer,
|
45
|
+
side: :left,
|
46
|
+
newlines: true,
|
47
|
+
whitespace: true,
|
48
|
+
continuations: true
|
49
|
+
)
|
50
|
+
|
51
|
+
corrector.remove(range)
|
52
|
+
end
|
25
53
|
end
|
26
54
|
end
|
27
55
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# Enforces the use of `node.single_line?` instead of
|
7
|
+
# comparing `first_line` and `last_line` for equality.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# node.loc.first_line == node.loc.last_line
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# node.loc.last_line == node.loc.first_line
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# node.loc.line == node.loc.last_line
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# node.loc.last_line == node.loc.line
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# node.first_line == node.last_line
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# node.single_line?
|
27
|
+
#
|
28
|
+
class SingleLineComparison < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Use `%<preferred>s`.'
|
32
|
+
RESTRICT_ON_SEND = %i[==].freeze
|
33
|
+
|
34
|
+
# @!method single_line_comparison(node)
|
35
|
+
def_node_matcher :single_line_comparison, <<~PATTERN
|
36
|
+
{
|
37
|
+
(send (send $_receiver {:line :first_line}) :== (send _receiver :last_line))
|
38
|
+
(send (send $_receiver :last_line) :== (send _receiver {:line :first_line}))
|
39
|
+
}
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
def on_send(node)
|
43
|
+
return unless (receiver = single_line_comparison(node))
|
44
|
+
|
45
|
+
preferred = "#{extract_receiver(receiver)}.single_line?"
|
46
|
+
|
47
|
+
add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
|
48
|
+
corrector.replace(node, preferred)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def extract_receiver(node)
|
55
|
+
node = node.receiver if node.send_type? && %i[loc source_range].include?(node.method_name)
|
56
|
+
node.source
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -17,6 +17,7 @@ require_relative 'internal_affairs/redundant_let_rubocop_config_new'
|
|
17
17
|
require_relative 'internal_affairs/redundant_location_argument'
|
18
18
|
require_relative 'internal_affairs/redundant_message_argument'
|
19
19
|
require_relative 'internal_affairs/redundant_method_dispatch_node'
|
20
|
+
require_relative 'internal_affairs/single_line_comparison'
|
20
21
|
require_relative 'internal_affairs/style_detected_api_use'
|
21
22
|
require_relative 'internal_affairs/undefined_config'
|
22
23
|
require_relative 'internal_affairs/useless_message_assertion'
|
@@ -36,24 +36,52 @@ module RuboCop
|
|
36
36
|
# If the end is on its own line, there is no offense
|
37
37
|
return if begins_its_line?(node.loc.end)
|
38
38
|
|
39
|
-
|
40
|
-
corrector.replace(delimiter_range(node), "\n#{node.loc.end.source}#{offset(node)}")
|
41
|
-
end
|
39
|
+
register_offense(node)
|
42
40
|
end
|
43
41
|
|
44
42
|
private
|
45
43
|
|
44
|
+
def register_offense(node)
|
45
|
+
add_offense(node.loc.end, message: message(node)) do |corrector|
|
46
|
+
offense_range = offense_range(node)
|
47
|
+
replacement = "\n#{offense_range.source.strip}"
|
48
|
+
|
49
|
+
if (heredoc = last_heredoc_argument(node.body))
|
50
|
+
corrector.remove(offense_range)
|
51
|
+
corrector.insert_after(heredoc.loc.heredoc_end, replacement)
|
52
|
+
else
|
53
|
+
corrector.replace(offense_range, replacement)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
46
58
|
def message(node)
|
47
59
|
format(MSG, line: node.loc.end.line, column: node.loc.end.column + 1)
|
48
60
|
end
|
49
61
|
|
50
|
-
def
|
62
|
+
def last_heredoc_argument(node)
|
63
|
+
return unless node&.call_type?
|
64
|
+
return unless (arguments = node&.arguments)
|
65
|
+
|
66
|
+
heredoc = arguments.reverse.detect { |arg| arg.str_type? && arg.heredoc? }
|
67
|
+
return heredoc if heredoc
|
68
|
+
|
69
|
+
last_heredoc_argument(node.children.first)
|
70
|
+
end
|
71
|
+
|
72
|
+
def offense_range(node)
|
51
73
|
Parser::Source::Range.new(
|
52
74
|
node.loc.expression.source_buffer,
|
53
75
|
node.children.compact.last.loc.expression.end_pos,
|
54
|
-
node.loc.expression.end_pos
|
76
|
+
end_of_method_chain(node).loc.expression.end_pos
|
55
77
|
)
|
56
78
|
end
|
79
|
+
|
80
|
+
def end_of_method_chain(node)
|
81
|
+
return node unless node.parent&.call_type?
|
82
|
+
|
83
|
+
end_of_method_chain(node.parent)
|
84
|
+
end
|
57
85
|
end
|
58
86
|
end
|
59
87
|
end
|
@@ -153,7 +153,8 @@ module RuboCop
|
|
153
153
|
MSG = 'Indent the first argument one step more than %<base>s.'
|
154
154
|
|
155
155
|
def on_send(node)
|
156
|
-
return if style != :consistent && enforce_first_argument_with_fixed_indentation?
|
156
|
+
return if style != :consistent && enforce_first_argument_with_fixed_indentation? &&
|
157
|
+
!enable_layout_first_method_argument_line_break?
|
157
158
|
return if !node.arguments? || bare_operator?(node) || node.setter_method?
|
158
159
|
|
159
160
|
indent = base_indentation(node) + configured_indentation_width
|
@@ -267,6 +268,10 @@ module RuboCop
|
|
267
268
|
argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
|
268
269
|
end
|
269
270
|
|
271
|
+
def enable_layout_first_method_argument_line_break?
|
272
|
+
config.for_cop('Layout/FirstMethodArgumentLineBreak')['Enabled']
|
273
|
+
end
|
274
|
+
|
270
275
|
def argument_alignment_config
|
271
276
|
config.for_cop('Layout/ArgumentAlignment')
|
272
277
|
end
|
@@ -73,7 +73,7 @@ module RuboCop
|
|
73
73
|
return if node.send_type? && node.loc.operator&.source != '='
|
74
74
|
return unless rhs
|
75
75
|
return unless supported_types.include?(rhs.type)
|
76
|
-
return if rhs.
|
76
|
+
return if rhs.single_line?
|
77
77
|
|
78
78
|
check_by_enforced_style(node, rhs)
|
79
79
|
end
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Legacy
|
6
6
|
# Legacy support for Corrector#corrections
|
7
|
-
# See https://docs.rubocop.org/rubocop/
|
7
|
+
# See https://docs.rubocop.org/rubocop/v1_upgrade_notes.html
|
8
8
|
class CorrectionsProxy
|
9
9
|
def initialize(corrector)
|
10
10
|
@corrector = corrector
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Legacy
|
6
6
|
# Legacy Corrector for v0 API support.
|
7
|
-
# See https://docs.rubocop.org/rubocop/
|
7
|
+
# See https://docs.rubocop.org/rubocop/v1_upgrade_notes.html
|
8
8
|
class Corrector < RuboCop::Cop::Corrector
|
9
9
|
# Support legacy second argument
|
10
10
|
def initialize(source, corr = [])
|
@@ -6,8 +6,8 @@ module RuboCop
|
|
6
6
|
# Checks for ambiguous block association with method
|
7
7
|
# when param passed without parentheses.
|
8
8
|
#
|
9
|
-
# This cop can customize
|
10
|
-
# By default, there are no methods to
|
9
|
+
# This cop can customize allowed methods with `AllowedMethods`.
|
10
|
+
# By default, there are no methods to allowed.
|
11
11
|
#
|
12
12
|
# @example
|
13
13
|
#
|
@@ -30,18 +30,30 @@ module RuboCop
|
|
30
30
|
# # Lambda arguments require no disambiguation
|
31
31
|
# foo = ->(bar) { bar.baz }
|
32
32
|
#
|
33
|
-
# @example
|
33
|
+
# @example AllowedMethods: [] (default)
|
34
34
|
#
|
35
35
|
# # bad
|
36
36
|
# expect { do_something }.to change { object.attribute }
|
37
37
|
#
|
38
|
-
# @example
|
38
|
+
# @example AllowedMethods: [change]
|
39
39
|
#
|
40
40
|
# # good
|
41
41
|
# expect { do_something }.to change { object.attribute }
|
42
42
|
#
|
43
|
+
# @example AllowedPatterns: [] (default)
|
44
|
+
#
|
45
|
+
# # bad
|
46
|
+
# expect { do_something }.to change { object.attribute }
|
47
|
+
#
|
48
|
+
# @example AllowedPatterns: [/change/]
|
49
|
+
#
|
50
|
+
# # good
|
51
|
+
# expect { do_something }.to change { object.attribute }
|
52
|
+
# expect { do_something }.to not_change { object.attribute }
|
53
|
+
#
|
43
54
|
class AmbiguousBlockAssociation < Base
|
44
|
-
include
|
55
|
+
include AllowedMethods
|
56
|
+
include AllowedPattern
|
45
57
|
|
46
58
|
MSG = 'Parenthesize the param `%<param>s` to make sure that the ' \
|
47
59
|
'block will be associated with the `%<method>s` method ' \
|
@@ -52,7 +64,7 @@ module RuboCop
|
|
52
64
|
|
53
65
|
return unless ambiguous_block_association?(node)
|
54
66
|
return if node.parenthesized? || node.last_argument.lambda? || node.last_argument.proc? ||
|
55
|
-
|
67
|
+
allowed_method_pattern?(node)
|
56
68
|
|
57
69
|
message = message(node)
|
58
70
|
|
@@ -66,9 +78,10 @@ module RuboCop
|
|
66
78
|
send_node.last_argument.block_type? && !send_node.last_argument.send_node.arguments?
|
67
79
|
end
|
68
80
|
|
69
|
-
def
|
81
|
+
def allowed_method_pattern?(node)
|
70
82
|
node.assignment? || node.operator_method? || node.method?(:[]) ||
|
71
|
-
|
83
|
+
allowed_method?(node.last_argument.method_name) ||
|
84
|
+
matches_allowed_pattern?(node.last_argument.method_name)
|
72
85
|
end
|
73
86
|
|
74
87
|
def message(send_node)
|
@@ -15,9 +15,19 @@ module RuboCop
|
|
15
15
|
# [source,yaml]
|
16
16
|
# ----
|
17
17
|
# Lint/Debugger:
|
18
|
-
#
|
18
|
+
# DebuggerMethods:
|
19
|
+
# WebConsole: ~
|
19
20
|
# ----
|
20
21
|
#
|
22
|
+
# You can also add your own methods by adding a new category:
|
23
|
+
#
|
24
|
+
# [source,yaml]
|
25
|
+
# ----
|
26
|
+
# Lint/Debugger:
|
27
|
+
# DebuggerMethods:
|
28
|
+
# MyDebugger:
|
29
|
+
# MyDebugger.debug_this
|
30
|
+
# ----
|
21
31
|
#
|
22
32
|
# @example
|
23
33
|
#
|
@@ -57,19 +67,6 @@ module RuboCop
|
|
57
67
|
class Debugger < Base
|
58
68
|
MSG = 'Remove debugger entry point `%<source>s`.'
|
59
69
|
|
60
|
-
# @!method kernel?(node)
|
61
|
-
def_node_matcher :kernel?, <<~PATTERN
|
62
|
-
(const {nil? cbase} :Kernel)
|
63
|
-
PATTERN
|
64
|
-
|
65
|
-
# @!method valid_receiver?(node, arg1)
|
66
|
-
def_node_matcher :valid_receiver?, <<~PATTERN
|
67
|
-
{
|
68
|
-
(const {nil? cbase} %1)
|
69
|
-
(send {nil? #kernel?} %1)
|
70
|
-
}
|
71
|
-
PATTERN
|
72
|
-
|
73
70
|
def on_send(node)
|
74
71
|
return unless debugger_method?(node)
|
75
72
|
|
@@ -91,7 +88,7 @@ module RuboCop
|
|
91
88
|
|
92
89
|
*receiver, method_name = v.split('.')
|
93
90
|
{
|
94
|
-
receiver: receiver.empty? ? nil : receiver.
|
91
|
+
receiver: receiver.empty? ? nil : receiver.map(&:to_sym),
|
95
92
|
method_name: method_name.to_sym
|
96
93
|
}
|
97
94
|
end.compact
|
@@ -105,10 +102,23 @@ module RuboCop
|
|
105
102
|
if method[:receiver].nil?
|
106
103
|
send_node.receiver.nil?
|
107
104
|
else
|
108
|
-
|
105
|
+
method[:receiver] == receiver_chain(send_node)
|
109
106
|
end
|
110
107
|
end
|
111
108
|
end
|
109
|
+
|
110
|
+
def receiver_chain(send_node)
|
111
|
+
receivers = []
|
112
|
+
receiver = send_node.receiver
|
113
|
+
|
114
|
+
while receiver
|
115
|
+
name = receiver.send_type? ? receiver.method_name : receiver.const_name&.to_sym
|
116
|
+
receivers.unshift(name)
|
117
|
+
receiver = receiver.receiver
|
118
|
+
end
|
119
|
+
|
120
|
+
receivers
|
121
|
+
end
|
112
122
|
end
|
113
123
|
end
|
114
124
|
end
|
@@ -4,6 +4,14 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for the presence of `if`, `elsif` and `unless` branches without a body.
|
7
|
+
#
|
8
|
+
# NOTE: empty `else` branches are handled by `Style/EmptyElse`.
|
9
|
+
#
|
10
|
+
# @safety
|
11
|
+
# Autocorrection for this cop is not safe. The conditions for empty branches that
|
12
|
+
# the autocorrection removes may have side effects, or the logic in subsequent
|
13
|
+
# branches may change due to the removal of a previous condition.
|
14
|
+
#
|
7
15
|
# @example
|
8
16
|
# # bad
|
9
17
|
# if condition
|
@@ -53,7 +61,9 @@ module RuboCop
|
|
53
61
|
# end
|
54
62
|
#
|
55
63
|
class EmptyConditionalBody < Base
|
64
|
+
extend AutoCorrector
|
56
65
|
include CommentsHelp
|
66
|
+
include RangeHelp
|
57
67
|
|
58
68
|
MSG = 'Avoid `%<keyword>s` branches without a body.'
|
59
69
|
|
@@ -61,7 +71,61 @@ module RuboCop
|
|
61
71
|
return if node.body
|
62
72
|
return if cop_config['AllowComments'] && contains_comments?(node)
|
63
73
|
|
64
|
-
add_offense(node, message: format(MSG, keyword: node.keyword))
|
74
|
+
add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
|
75
|
+
autocorrect(corrector, node)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def autocorrect(corrector, node)
|
82
|
+
remove_comments(corrector, node)
|
83
|
+
remove_empty_branch(corrector, node)
|
84
|
+
correct_other_branches(corrector, node)
|
85
|
+
end
|
86
|
+
|
87
|
+
def remove_comments(corrector, node)
|
88
|
+
comments_in_range(node).each do |comment|
|
89
|
+
range = range_by_whole_lines(comment.loc.expression, include_final_newline: true)
|
90
|
+
corrector.remove(range)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_empty_branch(corrector, node)
|
95
|
+
corrector.remove(deletion_range(branch_range(node)))
|
96
|
+
end
|
97
|
+
|
98
|
+
def correct_other_branches(corrector, node)
|
99
|
+
return unless (node.if? || node.unless?) && node.else_branch
|
100
|
+
|
101
|
+
if node.else_branch.if_type?
|
102
|
+
# Replace an orphaned `elsif` with `if`
|
103
|
+
corrector.replace(node.else_branch.loc.keyword, 'if')
|
104
|
+
else
|
105
|
+
# Flip orphaned `else`
|
106
|
+
corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def branch_range(node)
|
111
|
+
if node.loc.else
|
112
|
+
node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
|
113
|
+
else
|
114
|
+
node.source_range
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def deletion_range(range)
|
119
|
+
# Collect a range between the start of the `if` node and the next relevant node,
|
120
|
+
# including final new line.
|
121
|
+
# Based on `RangeHelp#range_by_whole_lines` but allows the `if` to not start
|
122
|
+
# on the first column.
|
123
|
+
buffer = @processed_source.buffer
|
124
|
+
|
125
|
+
last_line = buffer.source_line(range.last_line)
|
126
|
+
end_offset = last_line.length - range.last_column + 1
|
127
|
+
|
128
|
+
range.adjust(end_pos: end_offset).intersect(buffer.source_range)
|
65
129
|
end
|
66
130
|
end
|
67
131
|
end
|
@@ -16,8 +16,8 @@ module RuboCop
|
|
16
16
|
# NOTE: Some values cannot be converted properly using one of the `Kernel`
|
17
17
|
# method (for instance, `Time` and `DateTime` values are allowed by this
|
18
18
|
# cop by default). Similarly, Rails' duration methods do not work well
|
19
|
-
# with `Integer()` and can be
|
20
|
-
# there are no methods to
|
19
|
+
# with `Integer()` and can be allowed with `AllowedMethods`. By default,
|
20
|
+
# there are no methods to allowed.
|
21
21
|
#
|
22
22
|
# @safety
|
23
23
|
# Autocorrection is unsafe because it is not guaranteed that the
|
@@ -46,12 +46,22 @@ module RuboCop
|
|
46
46
|
# foo.try { |i| Float(i) }
|
47
47
|
# bar.send { |i| Complex(i) }
|
48
48
|
#
|
49
|
-
# @example
|
49
|
+
# @example AllowedMethods: [] (default)
|
50
50
|
#
|
51
51
|
# # bad
|
52
52
|
# 10.minutes.to_i
|
53
53
|
#
|
54
|
-
# @example
|
54
|
+
# @example AllowedMethods: [minutes]
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# 10.minutes.to_i
|
58
|
+
#
|
59
|
+
# @example AllowedPatterns: [] (default)
|
60
|
+
#
|
61
|
+
# # bad
|
62
|
+
# 10.minutes.to_i
|
63
|
+
#
|
64
|
+
# @example AllowedPatterns: [/min*/]
|
55
65
|
#
|
56
66
|
# # good
|
57
67
|
# 10.minutes.to_i
|
@@ -62,7 +72,8 @@ module RuboCop
|
|
62
72
|
# Time.now.to_datetime.to_i
|
63
73
|
class NumberConversion < Base
|
64
74
|
extend AutoCorrector
|
65
|
-
include
|
75
|
+
include AllowedMethods
|
76
|
+
include AllowedPattern
|
66
77
|
|
67
78
|
CONVERSION_METHOD_CLASS_MAPPING = {
|
68
79
|
to_i: "#{Integer.name}(%<number_object>s, 10)",
|
@@ -97,7 +108,7 @@ module RuboCop
|
|
97
108
|
|
98
109
|
def handle_conversion_method(node)
|
99
110
|
to_method(node) do |receiver, to_method|
|
100
|
-
next if receiver.nil? ||
|
111
|
+
next if receiver.nil? || allow_receiver?(receiver)
|
101
112
|
|
102
113
|
message = format(
|
103
114
|
MSG,
|
@@ -141,9 +152,10 @@ module RuboCop
|
|
141
152
|
corrector.remove(node.loc.end)
|
142
153
|
end
|
143
154
|
|
144
|
-
def
|
155
|
+
def allow_receiver?(receiver)
|
145
156
|
if receiver.numeric_type? || (receiver.send_type? &&
|
146
|
-
(conversion_method?(receiver.method_name) ||
|
157
|
+
(conversion_method?(receiver.method_name) ||
|
158
|
+
allowed_method_name?(receiver.method_name)))
|
147
159
|
true
|
148
160
|
elsif (receiver = top_receiver(receiver))
|
149
161
|
receiver.const_type? && ignored_class?(receiver.const_name)
|
@@ -152,6 +164,10 @@ module RuboCop
|
|
152
164
|
end
|
153
165
|
end
|
154
166
|
|
167
|
+
def allowed_method_name?(name)
|
168
|
+
allowed_method?(name) || matches_allowed_pattern?(name)
|
169
|
+
end
|
170
|
+
|
155
171
|
def top_receiver(node)
|
156
172
|
receiver = node
|
157
173
|
receiver = receiver.receiver until receiver.receiver.nil?
|
@@ -7,6 +7,14 @@ module RuboCop
|
|
7
7
|
# less specific exception being rescued before a more specific
|
8
8
|
# exception is rescued.
|
9
9
|
#
|
10
|
+
# An exception is considered shadowed if it is rescued after its
|
11
|
+
# ancestor is, or if it and its ancestor are both rescued in the
|
12
|
+
# same `rescue` statement. In both cases, the more specific rescue is
|
13
|
+
# unnecessary because it is covered by rescuing the less specific
|
14
|
+
# exception. (ie. `rescue Exception, StandardError` has the same behavior
|
15
|
+
# whether `StandardError` is included or not, because all `StandardError`s
|
16
|
+
# are rescued by `rescue Exception`).
|
17
|
+
#
|
10
18
|
# @example
|
11
19
|
#
|
12
20
|
# # bad
|
@@ -19,6 +27,13 @@ module RuboCop
|
|
19
27
|
# handle_standard_error
|
20
28
|
# end
|
21
29
|
#
|
30
|
+
# # bad
|
31
|
+
# begin
|
32
|
+
# something
|
33
|
+
# rescue Exception, StandardError
|
34
|
+
# handle_error
|
35
|
+
# end
|
36
|
+
#
|
22
37
|
# # good
|
23
38
|
#
|
24
39
|
# begin
|
@@ -67,10 +67,18 @@ module RuboCop
|
|
67
67
|
variable_node = variable.scope.node.parent
|
68
68
|
return false unless variable_node.conditional?
|
69
69
|
|
70
|
-
outer_local_variable_node =
|
70
|
+
outer_local_variable_node =
|
71
|
+
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
71
72
|
|
72
73
|
outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
|
73
74
|
end
|
75
|
+
|
76
|
+
def find_conditional_node_from_ascendant(node)
|
77
|
+
return unless (parent = node.parent)
|
78
|
+
return parent if parent.conditional?
|
79
|
+
|
80
|
+
find_conditional_node_from_ascendant(parent)
|
81
|
+
end
|
74
82
|
end
|
75
83
|
end
|
76
84
|
end
|
@@ -33,7 +33,9 @@ module RuboCop
|
|
33
33
|
# render 'pages/search/page'
|
34
34
|
# end
|
35
35
|
#
|
36
|
-
# This cop also takes into account `
|
36
|
+
# This cop also takes into account `AllowedMethods` (defaults to `[]`)
|
37
|
+
# And `AllowedPatterns` (defaults to `[]`)
|
38
|
+
#
|
37
39
|
class AbcSize < Base
|
38
40
|
include MethodComplexity
|
39
41
|
|
@@ -14,8 +14,8 @@ module RuboCop
|
|
14
14
|
#
|
15
15
|
#
|
16
16
|
# NOTE: The `ExcludedMethods` configuration is deprecated and only kept
|
17
|
-
# for backwards compatibility. Please use `
|
18
|
-
# By default, there are no methods to
|
17
|
+
# for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
|
18
|
+
# instead. By default, there are no methods to allowed.
|
19
19
|
#
|
20
20
|
# @example CountAsOne: ['array', 'heredoc']
|
21
21
|
#
|
@@ -38,14 +38,13 @@ module RuboCop
|
|
38
38
|
# NOTE: This cop does not apply for `Struct` definitions.
|
39
39
|
class BlockLength < Base
|
40
40
|
include CodeLength
|
41
|
-
include
|
42
|
-
|
43
|
-
ignored_methods deprecated_key: 'ExcludedMethods'
|
41
|
+
include AllowedMethods
|
42
|
+
include AllowedPattern
|
44
43
|
|
45
44
|
LABEL = 'Block'
|
46
45
|
|
47
46
|
def on_block(node)
|
48
|
-
return if
|
47
|
+
return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
|
49
48
|
return if method_receiver_excluded?(node)
|
50
49
|
return if node.class_constructor? || node.struct_constructor?
|
51
50
|
|
@@ -59,7 +58,7 @@ module RuboCop
|
|
59
58
|
node_receiver = node.receiver&.source&.gsub(/\s+/, '')
|
60
59
|
node_method = String(node.method_name)
|
61
60
|
|
62
|
-
|
61
|
+
allowed_methods.any? do |config|
|
63
62
|
next unless config.is_a?(String)
|
64
63
|
|
65
64
|
receiver, method = config.split('.')
|
@@ -4,16 +4,17 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Metrics
|
6
6
|
# Checks if the length of a method exceeds some maximum value.
|
7
|
-
# Comment lines can optionally be
|
7
|
+
# Comment lines can optionally be allowed.
|
8
8
|
# The maximum allowed length is configurable.
|
9
9
|
#
|
10
10
|
# You can set literals you want to fold with `CountAsOne`.
|
11
11
|
# Available are: 'array', 'hash', and 'heredoc'. Each literal
|
12
12
|
# will be counted as one line regardless of its actual size.
|
13
13
|
#
|
14
|
-
# NOTE: The `ExcludedMethods` configuration is
|
15
|
-
#
|
16
|
-
#
|
14
|
+
# NOTE: The `ExcludedMethods` and `IgnoredMethods` configuration is
|
15
|
+
# deprecated and only kept for backwards compatibility.
|
16
|
+
# Please use `AllowedMethods` and `AllowedPatterns` instead.
|
17
|
+
# By default, there are no methods to allowed.
|
17
18
|
#
|
18
19
|
# @example CountAsOne: ['array', 'heredoc']
|
19
20
|
#
|
@@ -35,14 +36,13 @@ module RuboCop
|
|
35
36
|
#
|
36
37
|
class MethodLength < Base
|
37
38
|
include CodeLength
|
38
|
-
include
|
39
|
-
|
40
|
-
ignored_methods deprecated_key: 'ExcludedMethods'
|
39
|
+
include AllowedMethods
|
40
|
+
include AllowedPattern
|
41
41
|
|
42
42
|
LABEL = 'Method'
|
43
43
|
|
44
44
|
def on_def(node)
|
45
|
-
return if
|
45
|
+
return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
|
46
46
|
|
47
47
|
check_code_length(node)
|
48
48
|
end
|