rubocop 1.32.0 → 1.34.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 +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
|