rubocop 1.6.1 → 1.9.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/LICENSE.txt +1 -1
- data/README.md +4 -3
- data/config/default.yml +145 -19
- data/lib/rubocop.rb +16 -1
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
- data/lib/rubocop/comment_config.rb +6 -6
- data/lib/rubocop/config.rb +13 -7
- data/lib/rubocop/config_loader.rb +11 -14
- data/lib/rubocop/config_loader_resolver.rb +21 -4
- data/lib/rubocop/config_obsoletion.rb +5 -3
- data/lib/rubocop/config_store.rb +12 -1
- data/lib/rubocop/cop/base.rb +2 -1
- data/lib/rubocop/cop/exclude_limit.rb +26 -0
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
- data/lib/rubocop/cop/generator.rb +1 -3
- data/lib/rubocop/cop/internal_affairs.rb +6 -1
- data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
- data/lib/rubocop/cop/layout/class_structure.rb +7 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +56 -20
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
- data/lib/rubocop/cop/layout/line_length.rb +2 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +67 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
- data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
- data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
- data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
- data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
- data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
- data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
- data/lib/rubocop/cop/message_annotator.rb +4 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
- data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
- data/lib/rubocop/cop/mixin/code_length.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
- data/lib/rubocop/cop/naming/variable_name.rb +2 -0
- data/lib/rubocop/cop/naming/variable_number.rb +2 -9
- data/lib/rubocop/cop/registry.rb +10 -0
- data/lib/rubocop/cop/severity.rb +3 -3
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
- data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
- data/lib/rubocop/cop/style/collection_methods.rb +14 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
- data/lib/rubocop/cop/style/empty_literal.rb +6 -2
- data/lib/rubocop/cop/style/endless_method.rb +102 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
- data/lib/rubocop/cop/style/explicit_block_argument.rb +10 -0
- data/lib/rubocop/cop/style/float_division.rb +3 -0
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/format_string_token.rb +18 -2
- data/lib/rubocop/cop/style/hash_except.rb +95 -0
- data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
- data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
- data/lib/rubocop/cop/style/lambda_call.rb +2 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
- data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
- data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
- data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +5 -2
- data/lib/rubocop/cop/style/redundant_argument.rb +7 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +36 -2
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
- data/lib/rubocop/cop/util.rb +3 -1
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
- data/lib/rubocop/magic_comment.rb +30 -1
- data/lib/rubocop/options.rb +10 -10
- data/lib/rubocop/rspec/cop_helper.rb +0 -4
- data/lib/rubocop/rspec/expect_offense.rb +37 -22
- data/lib/rubocop/runner.rb +17 -1
- data/lib/rubocop/target_finder.rb +4 -2
- data/lib/rubocop/target_ruby.rb +47 -11
- data/lib/rubocop/util.rb +16 -0
- data/lib/rubocop/version.rb +8 -2
- metadata +27 -7
@@ -71,11 +71,7 @@ module RuboCop
|
|
71
71
|
add_offense(range, message: message) do |corrector|
|
72
72
|
corrector.replace(range, preferred_name)
|
73
73
|
|
74
|
-
node.body
|
75
|
-
next unless var.children.first == offending_name
|
76
|
-
|
77
|
-
corrector.replace(var, preferred_name)
|
78
|
-
end
|
74
|
+
correct_node(corrector, node.body, offending_name, preferred_name)
|
79
75
|
end
|
80
76
|
end
|
81
77
|
|
@@ -86,6 +82,43 @@ module RuboCop
|
|
86
82
|
variable.loc.expression
|
87
83
|
end
|
88
84
|
|
85
|
+
def variable_name_matches?(node, name)
|
86
|
+
if node.masgn_type?
|
87
|
+
node.each_descendant(:lvasgn).any? do |lvasgn_node|
|
88
|
+
variable_name_matches?(lvasgn_node, name)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
node.children.first == name
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def correct_node(corrector, node, offending_name, preferred_name)
|
96
|
+
return unless node
|
97
|
+
|
98
|
+
node.each_node(:lvar, :lvasgn, :masgn) do |child_node|
|
99
|
+
next unless variable_name_matches?(child_node, offending_name)
|
100
|
+
|
101
|
+
corrector.replace(child_node, preferred_name) if child_node.lvar_type?
|
102
|
+
|
103
|
+
if child_node.masgn_type? || child_node.lvasgn_type?
|
104
|
+
correct_reassignment(corrector, child_node, offending_name, preferred_name)
|
105
|
+
break
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# If the exception variable is reassigned, that assignment needs to be corrected.
|
111
|
+
# Further `lvar` nodes will not be corrected though since they now refer to a
|
112
|
+
# different variable.
|
113
|
+
def correct_reassignment(corrector, node, offending_name, preferred_name)
|
114
|
+
if node.lvasgn_type?
|
115
|
+
correct_node(corrector, node.child_nodes.first, offending_name, preferred_name)
|
116
|
+
elsif node.masgn_type?
|
117
|
+
# With multiple assign, the assignments are in an array as the last child
|
118
|
+
correct_node(corrector, node.children.last, offending_name, preferred_name)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
89
122
|
def preferred_name(variable_name)
|
90
123
|
preferred_name = cop_config.fetch('PreferredName', 'e')
|
91
124
|
if variable_name.to_s.start_with?('_')
|
@@ -20,6 +20,7 @@ module RuboCop
|
|
20
20
|
# # good
|
21
21
|
# fooBar = 1
|
22
22
|
class VariableName < Base
|
23
|
+
include AllowedIdentifiers
|
23
24
|
include ConfigurableNaming
|
24
25
|
|
25
26
|
MSG = 'Use %<style>s for variable names.'
|
@@ -27,6 +28,7 @@ module RuboCop
|
|
27
28
|
def on_lvasgn(node)
|
28
29
|
name, = *node
|
29
30
|
return unless name
|
31
|
+
return if allowed_identifier?(name)
|
30
32
|
|
31
33
|
check_name(node, name, node.loc.name)
|
32
34
|
end
|
@@ -92,11 +92,12 @@ module RuboCop
|
|
92
92
|
# # good
|
93
93
|
# :some_sym_1
|
94
94
|
#
|
95
|
-
# @example
|
95
|
+
# @example AllowedIdentifiers: [capture3]
|
96
96
|
# # good
|
97
97
|
# expect(Open3).to receive(:capture3)
|
98
98
|
#
|
99
99
|
class VariableNumber < Base
|
100
|
+
include AllowedIdentifiers
|
100
101
|
include ConfigurableNumbering
|
101
102
|
|
102
103
|
MSG = 'Use %<style>s for %<identifier_type>s numbers.'
|
@@ -139,14 +140,6 @@ module RuboCop
|
|
139
140
|
|
140
141
|
format(MSG, style: style, identifier_type: identifier_type)
|
141
142
|
end
|
142
|
-
|
143
|
-
def allowed_identifier?(name)
|
144
|
-
allowed_identifiers.include?(name.to_s.delete('@'))
|
145
|
-
end
|
146
|
-
|
147
|
-
def allowed_identifiers
|
148
|
-
cop_config.fetch('AllowedIdentifiers', [])
|
149
|
-
end
|
150
143
|
end
|
151
144
|
end
|
152
145
|
end
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -204,6 +204,12 @@ module RuboCop
|
|
204
204
|
to_h[cop_name].first
|
205
205
|
end
|
206
206
|
|
207
|
+
def freeze
|
208
|
+
clear_enrollment_queue
|
209
|
+
unqualified_cop_names # build cache
|
210
|
+
super
|
211
|
+
end
|
212
|
+
|
207
213
|
@global = new
|
208
214
|
|
209
215
|
class << self
|
@@ -228,6 +234,10 @@ module RuboCop
|
|
228
234
|
@global = previous
|
229
235
|
end
|
230
236
|
|
237
|
+
def self.reset!
|
238
|
+
@global = new
|
239
|
+
end
|
240
|
+
|
231
241
|
private
|
232
242
|
|
233
243
|
def initialize_copy(reg)
|
data/lib/rubocop/cop/severity.rb
CHANGED
@@ -6,10 +6,10 @@ module RuboCop
|
|
6
6
|
class Severity
|
7
7
|
include Comparable
|
8
8
|
|
9
|
-
NAMES = %i[refactor convention warning error fatal].freeze
|
9
|
+
NAMES = %i[info refactor convention warning error fatal].freeze
|
10
10
|
|
11
11
|
# @api private
|
12
|
-
CODE_TABLE = { R: :refactor, C: :convention,
|
12
|
+
CODE_TABLE = { I: :info, R: :refactor, C: :convention,
|
13
13
|
W: :warning, E: :error, F: :fatal }.freeze
|
14
14
|
|
15
15
|
# @api public
|
@@ -18,7 +18,7 @@ module RuboCop
|
|
18
18
|
#
|
19
19
|
# @return [Symbol]
|
20
20
|
# severity.
|
21
|
-
# any of `:refactor`, `:convention`, `:warning`, `:error` or `:fatal`.
|
21
|
+
# any of `:info`, `:refactor`, `:convention`, `:warning`, `:error` or `:fatal`.
|
22
22
|
attr_reader :name
|
23
23
|
|
24
24
|
def self.name_from_code(code)
|
@@ -87,7 +87,9 @@ module RuboCop
|
|
87
87
|
return if allow_modifiers_on_symbols?(node)
|
88
88
|
|
89
89
|
if offense?(node)
|
90
|
-
add_offense(node.loc.selector)
|
90
|
+
add_offense(node.loc.selector) do
|
91
|
+
opposite_style_detected
|
92
|
+
end
|
91
93
|
else
|
92
94
|
correct_style_detected
|
93
95
|
end
|
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
module Style
|
8
8
|
# This cop checks for non-ascii (non-English) characters
|
9
9
|
# in comments. You could set an array of allowed non-ascii chars in
|
10
|
-
# AllowedChars attribute (
|
10
|
+
# `AllowedChars` attribute (copyright notice "©" by default).
|
11
11
|
#
|
12
12
|
# @example
|
13
13
|
# # bad
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def on_send(node)
|
51
|
-
return unless
|
51
|
+
return unless implicit_block?(node)
|
52
52
|
|
53
53
|
check_method_node(node)
|
54
54
|
end
|
@@ -64,9 +64,22 @@ module RuboCop
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
+
def implicit_block?(node)
|
68
|
+
return false unless node.arguments.any?
|
69
|
+
|
70
|
+
node.last_argument.block_pass_type? ||
|
71
|
+
node.last_argument.sym_type? && methods_accepting_symbol.include?(node.method_name.to_s)
|
72
|
+
end
|
73
|
+
|
67
74
|
def message(node)
|
68
75
|
format(MSG, prefer: preferred_method(node.method_name), current: node.method_name)
|
69
76
|
end
|
77
|
+
|
78
|
+
# Some enumerable methods accept a bare symbol (ie. _not_ Symbol#to_proc) instead
|
79
|
+
# of a block.
|
80
|
+
def methods_accepting_symbol
|
81
|
+
Array(cop_config['MethodsAcceptingSymbol'])
|
82
|
+
end
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|
@@ -4,12 +4,15 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# This cop checks for comments put on the same line as some keywords.
|
7
|
-
# These keywords are: `
|
7
|
+
# These keywords are: `class`, `module`, `def`, `begin`, `end`.
|
8
8
|
#
|
9
9
|
# Note that some comments
|
10
10
|
# (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`)
|
11
11
|
# are allowed.
|
12
12
|
#
|
13
|
+
# Auto-correction removes comments from `end` keyword and keeps comments
|
14
|
+
# for `class`, `module`, `def` and `begin` above the keyword.
|
15
|
+
#
|
13
16
|
# @example
|
14
17
|
# # bad
|
15
18
|
# if condition
|
@@ -34,16 +37,17 @@ module RuboCop
|
|
34
37
|
# y
|
35
38
|
# end
|
36
39
|
class CommentedKeyword < Base
|
40
|
+
include RangeHelp
|
41
|
+
extend AutoCorrector
|
42
|
+
|
37
43
|
MSG = 'Do not place comments on the same line as the ' \
|
38
44
|
'`%<keyword>s` keyword.'
|
39
45
|
|
40
46
|
def on_new_investigation
|
41
47
|
processed_source.comments.each do |comment|
|
42
|
-
next unless (match = line(comment).match(/(?<keyword>\S+).*#/))
|
48
|
+
next unless (match = line(comment).match(/(?<keyword>\S+).*#/)) && offensive?(comment)
|
43
49
|
|
44
|
-
|
45
|
-
add_offense(comment, message: format(MSG, keyword: match[:keyword]))
|
46
|
-
end
|
50
|
+
register_offense(comment, match[:keyword])
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
@@ -60,6 +64,19 @@ module RuboCop
|
|
60
64
|
].freeze
|
61
65
|
ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }.freeze
|
62
66
|
|
67
|
+
def register_offense(comment, matched_keyword)
|
68
|
+
add_offense(comment, message: format(MSG, keyword: matched_keyword)) do |corrector|
|
69
|
+
range = range_with_surrounding_space(range: comment.loc.expression, newlines: false)
|
70
|
+
corrector.remove(range)
|
71
|
+
|
72
|
+
unless matched_keyword == 'end'
|
73
|
+
corrector.insert_before(
|
74
|
+
range.source_buffer.line_range(comment.loc.line), "#{comment.text}\n"
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
63
80
|
def offensive?(comment)
|
64
81
|
line = line(comment)
|
65
82
|
KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
|
@@ -9,37 +9,77 @@ module RuboCop
|
|
9
9
|
# This is useful if want to make sure that every RuboCop error gets fixed
|
10
10
|
# and not quickly disabled with a comment.
|
11
11
|
#
|
12
|
+
# Specific cops can be allowed with the `AllowedCops` configuration. Note that
|
13
|
+
# if this configuration is set, `rubocop:disable all` is still disallowed.
|
14
|
+
#
|
12
15
|
# @example
|
13
16
|
# # bad
|
14
17
|
# # rubocop:disable Metrics/AbcSize
|
15
|
-
# def
|
18
|
+
# def foo
|
16
19
|
# end
|
17
20
|
# # rubocop:enable Metrics/AbcSize
|
18
21
|
#
|
19
22
|
# # good
|
20
|
-
# def
|
23
|
+
# def foo
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @example AllowedCops: [Metrics/AbcSize]
|
27
|
+
# # good
|
28
|
+
# # rubocop:disable Metrics/AbcSize
|
29
|
+
# def foo
|
21
30
|
# end
|
31
|
+
# # rubocop:enable Metrics/AbcSize
|
22
32
|
#
|
23
33
|
class DisableCopsWithinSourceCodeDirective < Base
|
24
34
|
extend AutoCorrector
|
25
35
|
|
26
36
|
# rubocop:enable Lint/RedundantCopDisableDirective
|
27
|
-
MSG = '
|
37
|
+
MSG = 'Rubocop disable/enable directives are not permitted.'
|
38
|
+
MSG_FOR_COPS = 'Rubocop disable/enable directives for %<cops>s are not permitted.'
|
28
39
|
|
29
40
|
def on_new_investigation
|
30
41
|
processed_source.comments.each do |comment|
|
31
|
-
|
42
|
+
directive_cops = directive_cops(comment)
|
43
|
+
disallowed_cops = directive_cops - allowed_cops
|
32
44
|
|
33
|
-
|
34
|
-
|
35
|
-
|
45
|
+
next unless disallowed_cops.any?
|
46
|
+
|
47
|
+
register_offense(comment, directive_cops, disallowed_cops)
|
36
48
|
end
|
37
49
|
end
|
38
50
|
|
39
51
|
private
|
40
52
|
|
41
|
-
def
|
42
|
-
|
53
|
+
def register_offense(comment, directive_cops, disallowed_cops)
|
54
|
+
message = if any_cops_allowed?
|
55
|
+
format(MSG_FOR_COPS, cops: "`#{disallowed_cops.join('`, `')}`")
|
56
|
+
else
|
57
|
+
MSG
|
58
|
+
end
|
59
|
+
|
60
|
+
add_offense(comment, message: message) do |corrector|
|
61
|
+
replacement = ''
|
62
|
+
|
63
|
+
if directive_cops.length != disallowed_cops.length
|
64
|
+
replacement = comment.text.sub(/#{Regexp.union(disallowed_cops)},?\s*/, '')
|
65
|
+
.sub(/,\s*$/, '')
|
66
|
+
end
|
67
|
+
|
68
|
+
corrector.replace(comment, replacement)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def directive_cops(comment)
|
73
|
+
match = CommentConfig::COMMENT_DIRECTIVE_REGEXP.match(comment.text)
|
74
|
+
match && match[2] ? match[2].split(',').map(&:strip) : []
|
75
|
+
end
|
76
|
+
|
77
|
+
def allowed_cops
|
78
|
+
Array(cop_config['AllowedCops'])
|
79
|
+
end
|
80
|
+
|
81
|
+
def any_cops_allowed?
|
82
|
+
allowed_cops.any?
|
43
83
|
end
|
44
84
|
end
|
45
85
|
end
|
@@ -32,8 +32,12 @@ module RuboCop
|
|
32
32
|
def_node_matcher :str_node, '(send (const {nil? cbase} :String) :new)'
|
33
33
|
def_node_matcher :array_with_block,
|
34
34
|
'(block (send (const {nil? cbase} :Array) :new) args _)'
|
35
|
-
def_node_matcher :hash_with_block,
|
36
|
-
|
35
|
+
def_node_matcher :hash_with_block, <<~PATTERN
|
36
|
+
{
|
37
|
+
(block (send (const {nil? cbase} :Hash) :new) args _)
|
38
|
+
(numblock (send (const {nil? cbase} :Hash) :new) ...)
|
39
|
+
}
|
40
|
+
PATTERN
|
37
41
|
|
38
42
|
def on_send(node)
|
39
43
|
return unless (message = offense_message(node))
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for endless methods.
|
7
|
+
#
|
8
|
+
# It can enforce either the use of endless methods definitions
|
9
|
+
# for single-lined method bodies, or disallow endless methods.
|
10
|
+
#
|
11
|
+
# Other method definition types are not considered by this cop.
|
12
|
+
#
|
13
|
+
# The supported styles are:
|
14
|
+
# * allow_single_line (default) - only single line endless method definitions are allowed.
|
15
|
+
# * allow_always - all endless method definitions are allowed.
|
16
|
+
# * disallow - all endless method definitions are disallowed.
|
17
|
+
#
|
18
|
+
# NOTE: Incorrect endless method definitions will always be
|
19
|
+
# corrected to a multi-line definition.
|
20
|
+
#
|
21
|
+
# @example EnforcedStyle: allow_single_line (default)
|
22
|
+
# # good
|
23
|
+
# def my_method() = x
|
24
|
+
#
|
25
|
+
# # bad, multi-line endless method
|
26
|
+
# def my_method() = x.foo
|
27
|
+
# .bar
|
28
|
+
# .baz
|
29
|
+
#
|
30
|
+
# @example EnforcedStyle: allow_always
|
31
|
+
# # good
|
32
|
+
# def my_method() = x
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# def my_method() = x.foo
|
36
|
+
# .bar
|
37
|
+
# .baz
|
38
|
+
#
|
39
|
+
# @example EnforcedStyle: disallow
|
40
|
+
# # bad
|
41
|
+
# def my_method; x end
|
42
|
+
#
|
43
|
+
# # bad
|
44
|
+
# def my_method() = x.foo
|
45
|
+
# .bar
|
46
|
+
# .baz
|
47
|
+
#
|
48
|
+
class EndlessMethod < Base
|
49
|
+
include ConfigurableEnforcedStyle
|
50
|
+
extend TargetRubyVersion
|
51
|
+
extend AutoCorrector
|
52
|
+
|
53
|
+
minimum_target_ruby_version 3.0
|
54
|
+
|
55
|
+
CORRECTION_STYLES = %w[multiline single_line].freeze
|
56
|
+
MSG = 'Avoid endless method definitions.'
|
57
|
+
MSG_MULTI_LINE = 'Avoid endless method definitions with multiple lines.'
|
58
|
+
|
59
|
+
def on_def(node)
|
60
|
+
if style == :disallow
|
61
|
+
handle_disallow_style(node)
|
62
|
+
else
|
63
|
+
handle_allow_style(node)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def handle_allow_style(node)
|
70
|
+
return unless node.endless?
|
71
|
+
return if node.single_line? || style == :allow_always
|
72
|
+
|
73
|
+
add_offense(node, message: MSG_MULTI_LINE) do |corrector|
|
74
|
+
correct_to_multiline(corrector, node)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_disallow_style(node)
|
79
|
+
return unless node.endless?
|
80
|
+
|
81
|
+
add_offense(node) do |corrector|
|
82
|
+
correct_to_multiline(corrector, node)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def correct_to_multiline(corrector, node)
|
87
|
+
replacement = <<~RUBY.strip
|
88
|
+
def #{node.method_name}#{arguments(node)}
|
89
|
+
#{node.body.source}
|
90
|
+
end
|
91
|
+
RUBY
|
92
|
+
|
93
|
+
corrector.replace(node, replacement)
|
94
|
+
end
|
95
|
+
|
96
|
+
def arguments(node, missing = '')
|
97
|
+
node.arguments.any? ? node.arguments.source : missing
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|