rubocop 1.40.0 → 1.43.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/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +52 -2
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +34 -11
- data/lib/rubocop/config_loader.rb +9 -0
- data/lib/rubocop/config_loader_resolver.rb +5 -1
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/badge.rb +9 -4
- data/lib/rubocop/cop/base.rb +83 -66
- data/lib/rubocop/cop/commissioner.rb +8 -3
- data/lib/rubocop/cop/cop.rb +29 -29
- data/lib/rubocop/cop/corrector.rb +23 -11
- data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +32 -11
- data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
- data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
- data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
- data/lib/rubocop/cop/layout/line_length.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
- data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
- data/lib/rubocop/cop/lint/debugger.rb +3 -1
- data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
- data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -19
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
- data/lib/rubocop/cop/lint/useless_rescue.rb +71 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -3
- data/lib/rubocop/cop/metrics/class_length.rb +1 -1
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -4
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -2
- data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
- data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/require_library.rb +2 -0
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
- data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
- data/lib/rubocop/cop/registry.rb +28 -25
- data/lib/rubocop/cop/security/compound_hash.rb +2 -1
- data/lib/rubocop/cop/style/alias.rb +9 -1
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
- data/lib/rubocop/cop/style/documentation.rb +11 -5
- data/lib/rubocop/cop/style/guard_clause.rb +17 -9
- data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +11 -7
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
- data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
- data/lib/rubocop/cop/style/map_to_set.rb +61 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -9
- data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
- data/lib/rubocop/cop/style/min_max_comparison.rb +73 -0
- data/lib/rubocop/cop/style/missing_else.rb +13 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +15 -1
- data/lib/rubocop/cop/style/redundant_constant_base.rb +13 -0
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
- data/lib/rubocop/cop/style/require_order.rb +63 -9
- data/lib/rubocop/cop/style/select_by_regexp.rb +6 -2
- data/lib/rubocop/cop/style/semicolon.rb +2 -1
- data/lib/rubocop/cop/style/signal_exception.rb +8 -6
- data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
- data/lib/rubocop/cop/style/word_array.rb +41 -0
- data/lib/rubocop/cop/style/yoda_expression.rb +81 -0
- data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
- data/lib/rubocop/cop/team.rb +29 -29
- data/lib/rubocop/cop/util.rb +31 -4
- data/lib/rubocop/cop/variable_force.rb +0 -3
- data/lib/rubocop/cops_documentation_generator.rb +33 -11
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/file_patterns.rb +43 -0
- data/lib/rubocop/formatter.rb +2 -0
- data/lib/rubocop/options.rb +1 -1
- data/lib/rubocop/path_util.rb +38 -22
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +10 -3
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +7 -1
- metadata +16 -10
- data/lib/rubocop/optimized_patterns.rb +0 -38
@@ -17,13 +17,19 @@ module RuboCop
|
|
17
17
|
# do_something
|
18
18
|
# end
|
19
19
|
class RegexpAsCondition < Base
|
20
|
+
include IgnoredNode
|
20
21
|
extend AutoCorrector
|
21
22
|
|
22
23
|
MSG = 'Do not use regexp literal as a condition. ' \
|
23
24
|
'The regexp literal matches `$_` implicitly.'
|
24
25
|
|
25
26
|
def on_match_current_line(node)
|
27
|
+
return if node.ancestors.none?(&:conditional?)
|
28
|
+
return if part_of_ignored_node?(node)
|
29
|
+
|
26
30
|
add_offense(node) { |corrector| corrector.replace(node, "#{node.source} =~ $_") }
|
31
|
+
|
32
|
+
ignore_node(node)
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
@@ -46,7 +46,9 @@ module RuboCop
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def check_ternary(ternary, node)
|
49
|
-
|
49
|
+
if node.method?(:[]) || node.assignment_method? || !ternary.condition.operator_keyword?
|
50
|
+
return
|
51
|
+
end
|
50
52
|
|
51
53
|
range = range_between(node.source_range.begin_pos, ternary.condition.source_range.end_pos)
|
52
54
|
|
@@ -45,13 +45,12 @@ module RuboCop
|
|
45
45
|
bad_method?(node) do |safe_nav, method|
|
46
46
|
return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
|
47
47
|
|
48
|
-
method_chain = method_chain(node)
|
49
48
|
location =
|
50
49
|
Parser::Source::Range.new(node.source_range.source_buffer,
|
51
50
|
safe_nav.source_range.end_pos,
|
52
|
-
|
51
|
+
node.source_range.end_pos)
|
53
52
|
add_offense(location) do |corrector|
|
54
|
-
autocorrect(corrector, offense_range: location, send_node:
|
53
|
+
autocorrect(corrector, offense_range: location, send_node: node)
|
55
54
|
end
|
56
55
|
end
|
57
56
|
end
|
@@ -63,12 +62,12 @@ module RuboCop
|
|
63
62
|
# @return [String]
|
64
63
|
def add_safe_navigation_operator(offense_range:, send_node:)
|
65
64
|
source =
|
66
|
-
if
|
65
|
+
if brackets?(send_node)
|
67
66
|
format(
|
68
67
|
'%<method_name>s(%<arguments>s)%<method_chain>s',
|
69
|
-
arguments:
|
70
|
-
method_name:
|
71
|
-
method_chain:
|
68
|
+
arguments: send_node.arguments.map(&:source).join(', '),
|
69
|
+
method_name: send_node.method_name,
|
70
|
+
method_chain: send_node.source_range.end.join(send_node.source_range.end).source
|
72
71
|
)
|
73
72
|
else
|
74
73
|
offense_range.source
|
@@ -90,18 +89,8 @@ module RuboCop
|
|
90
89
|
)
|
91
90
|
end
|
92
91
|
|
93
|
-
def
|
94
|
-
|
95
|
-
chain = chain.parent if chain.send_type? && chain.parent&.call_type?
|
96
|
-
chain
|
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
|
92
|
+
def brackets?(send_node)
|
93
|
+
send_node.method?(:[]) || send_node.method?(:[]=)
|
105
94
|
end
|
106
95
|
end
|
107
96
|
end
|
@@ -100,7 +100,8 @@ module RuboCop
|
|
100
100
|
|
101
101
|
unless variable.keyword_argument?
|
102
102
|
message << " If it's necessary, use `_` or `_#{variable.name}` " \
|
103
|
-
"as an argument name to indicate that it won't be used."
|
103
|
+
"as an argument name to indicate that it won't be used. " \
|
104
|
+
"If it's unnecessary, remove it."
|
104
105
|
end
|
105
106
|
|
106
107
|
scope = variable.scope
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for useless `rescue`s, which only reraise rescued exceptions.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# def foo
|
11
|
+
# do_something
|
12
|
+
# rescue
|
13
|
+
# raise
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# def foo
|
18
|
+
# do_something
|
19
|
+
# rescue => e
|
20
|
+
# raise # or 'raise e', or 'raise $!', or 'raise $ERROR_INFO'
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# def foo
|
25
|
+
# do_something
|
26
|
+
# rescue
|
27
|
+
# do_cleanup
|
28
|
+
# raise
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# # bad (latest rescue)
|
32
|
+
# def foo
|
33
|
+
# do_something
|
34
|
+
# rescue ArgumentError
|
35
|
+
# # noop
|
36
|
+
# rescue
|
37
|
+
# raise
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good (not the latest rescue)
|
41
|
+
# def foo
|
42
|
+
# do_something
|
43
|
+
# rescue ArgumentError
|
44
|
+
# raise
|
45
|
+
# rescue
|
46
|
+
# # noop
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
class UselessRescue < Base
|
50
|
+
MSG = 'Useless `rescue` detected.'
|
51
|
+
|
52
|
+
def on_rescue(node)
|
53
|
+
resbody_node = node.resbody_branches.last
|
54
|
+
add_offense(resbody_node) if only_reraising?(resbody_node)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def only_reraising?(resbody_node)
|
60
|
+
body = resbody_node.body
|
61
|
+
return false if body.nil? || !body.send_type? || !body.method?(:raise)
|
62
|
+
return true unless body.arguments?
|
63
|
+
return false if body.arguments.size > 1
|
64
|
+
|
65
|
+
exception_name = body.first_argument.source
|
66
|
+
[resbody_node.exception_variable&.source, '$!', '$ERROR_INFO'].include?(exception_name)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -77,10 +77,12 @@ module RuboCop
|
|
77
77
|
PATTERN
|
78
78
|
|
79
79
|
def on_send(node)
|
80
|
-
|
81
|
-
|
80
|
+
return unless (first_argument = node.first_argument)
|
81
|
+
|
82
|
+
if first_argument.def_type?
|
83
|
+
inspect_def(node, first_argument)
|
82
84
|
elsif node.first_argument.sym_type?
|
83
|
-
inspect_sym(node,
|
85
|
+
inspect_sym(node, first_argument)
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Metrics
|
6
|
-
# Checks if the length a class exceeds some maximum value.
|
6
|
+
# Checks if the length of a class exceeds some maximum value.
|
7
7
|
# Comment lines can optionally be ignored.
|
8
8
|
# The maximum allowed length is configurable.
|
9
9
|
#
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Metrics
|
6
|
-
# Checks if the length a module exceeds some maximum value.
|
6
|
+
# Checks if the length of a module exceeds some maximum value.
|
7
7
|
# Comment lines can optionally be ignored.
|
8
8
|
# The maximum allowed length is configurable.
|
9
9
|
#
|
@@ -9,6 +9,20 @@ module RuboCop
|
|
9
9
|
# Keyword arguments can optionally be excluded from the total count,
|
10
10
|
# as they add less complexity than positional or optional parameters.
|
11
11
|
#
|
12
|
+
# Any number of arguments for `initialize` method inside a block of
|
13
|
+
# `Struct.new` and `Data.define` like this is always allowed:
|
14
|
+
#
|
15
|
+
# [source,ruby]
|
16
|
+
# ----
|
17
|
+
# Struct.new(:one, :two, :three, :four, :five, keyword_init: true) do
|
18
|
+
# def initialize(one:, two:, three:, four:, five:)
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# ----
|
22
|
+
#
|
23
|
+
# This is because checking the number of arguments of the `initialize` method
|
24
|
+
# does not make sense.
|
25
|
+
#
|
12
26
|
# NOTE: Explicit block argument `&block` is not counted to prevent
|
13
27
|
# erroneous change that is avoided by making block argument implicit.
|
14
28
|
#
|
@@ -63,6 +77,16 @@ module RuboCop
|
|
63
77
|
NAMED_KEYWORD_TYPES = %i[kwoptarg kwarg].freeze
|
64
78
|
private_constant :NAMED_KEYWORD_TYPES
|
65
79
|
|
80
|
+
# @!method struct_new_or_data_define_block?(node)
|
81
|
+
def_node_matcher :struct_new_or_data_define_block?, <<~PATTERN
|
82
|
+
(block
|
83
|
+
{
|
84
|
+
(send (const {nil? cbase} :Struct) :new ...)
|
85
|
+
(send (const {nil? cbase} :Data) :define ...)
|
86
|
+
}
|
87
|
+
(args) ...)
|
88
|
+
PATTERN
|
89
|
+
|
66
90
|
def on_def(node)
|
67
91
|
optargs = node.arguments.select(&:optarg_type?)
|
68
92
|
return if optargs.count <= max_optional_parameters
|
@@ -78,6 +102,9 @@ module RuboCop
|
|
78
102
|
alias on_defs on_def
|
79
103
|
|
80
104
|
def on_args(node)
|
105
|
+
parent = node.parent
|
106
|
+
return if parent.method?(:initialize) && struct_new_or_data_define_block?(parent.parent)
|
107
|
+
|
81
108
|
count = args_count(node)
|
82
109
|
return unless count > max_params
|
83
110
|
|
@@ -25,15 +25,15 @@ module RuboCop
|
|
25
25
|
# > http://c2.com/cgi/wiki?AbcMetric
|
26
26
|
CONDITION_NODES = CyclomaticComplexity::COUNTED_NODES.freeze
|
27
27
|
|
28
|
-
def self.calculate(node, discount_repeated_attributes: false)
|
29
|
-
new(node, discount_repeated_attributes: discount_repeated_attributes).calculate
|
30
|
-
end
|
31
|
-
|
32
28
|
# TODO: move to rubocop-ast
|
33
29
|
ARGUMENT_TYPES = %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg].freeze
|
34
30
|
|
35
31
|
private_constant :BRANCH_NODES, :CONDITION_NODES, :ARGUMENT_TYPES
|
36
32
|
|
33
|
+
def self.calculate(node, discount_repeated_attributes: false)
|
34
|
+
new(node, discount_repeated_attributes: discount_repeated_attributes).calculate
|
35
|
+
end
|
36
|
+
|
37
37
|
def initialize(node)
|
38
38
|
@assignment = 0
|
39
39
|
@branch = 0
|
@@ -58,8 +58,8 @@ module RuboCop
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def normalize_foldable_types(types)
|
61
|
-
types.
|
62
|
-
types.
|
61
|
+
types.push(:str, :dstr) if types.delete(:heredoc)
|
62
|
+
types.push(:send, :csend) if types.delete(:method_call)
|
63
63
|
types
|
64
64
|
end
|
65
65
|
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
|
29
29
|
each_bad_alignment(items, base_column) do |current|
|
30
30
|
expr = current.source_range
|
31
|
-
if @current_offenses
|
31
|
+
if @current_offenses&.any? { |o| within?(expr, o.location) }
|
32
32
|
# If this offense is within a line range that is already being
|
33
33
|
# realigned by autocorrect, we report the offense without
|
34
34
|
# autocorrecting it. Two rewrites in the same area by the same
|
@@ -7,11 +7,11 @@ module RuboCop
|
|
7
7
|
SIGILS = '@$' # if a variable starts with a sigil it will be removed
|
8
8
|
|
9
9
|
def allowed_identifier?(name)
|
10
|
-
allowed_identifiers.include?(name.to_s.delete(SIGILS))
|
10
|
+
!allowed_identifiers.empty? && allowed_identifiers.include?(name.to_s.delete(SIGILS))
|
11
11
|
end
|
12
12
|
|
13
13
|
def allowed_identifiers
|
14
|
-
cop_config.fetch('AllowedIdentifiers'
|
14
|
+
cop_config.fetch('AllowedIdentifiers') { [] }
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -41,18 +41,25 @@ module RuboCop
|
|
41
41
|
def split_comment(comment)
|
42
42
|
# Sort keywords by reverse length so that if a keyword is in a phrase
|
43
43
|
# but also on its own, both will match properly.
|
44
|
-
keywords_regex = Regexp.new(
|
45
|
-
Regexp.union(keywords.sort_by { |w| -w.length }).source,
|
46
|
-
Regexp::IGNORECASE
|
47
|
-
)
|
48
|
-
regex = /^(# ?)(\b#{keywords_regex}\b)(\s*:)?(\s+)?(\S+)?/i
|
49
|
-
|
50
44
|
match = comment.text.match(regex)
|
51
45
|
return false unless match
|
52
46
|
|
53
47
|
match.captures
|
54
48
|
end
|
55
49
|
|
50
|
+
KEYWORDS_REGEX_CACHE = {} # rubocop:disable Style/MutableConstant
|
51
|
+
private_constant :KEYWORDS_REGEX_CACHE
|
52
|
+
|
53
|
+
def regex
|
54
|
+
KEYWORDS_REGEX_CACHE[keywords] ||= begin
|
55
|
+
keywords_regex = Regexp.new(
|
56
|
+
Regexp.union(keywords.sort_by { |w| -w.length }).source,
|
57
|
+
Regexp::IGNORECASE
|
58
|
+
)
|
59
|
+
/^(# ?)(\b#{keywords_regex}\b)(\s*:)?(\s+)?(\S+)?/i
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
56
63
|
def keyword_appearance?
|
57
64
|
keyword && (colon || space)
|
58
65
|
end
|
@@ -20,19 +20,30 @@ module RuboCop
|
|
20
20
|
style_detected(possibilities)
|
21
21
|
end
|
22
22
|
|
23
|
+
SYMBOL_TO_STRING_CACHE = Hash.new do |hash, key|
|
24
|
+
hash[key] = key.to_s if key.is_a?(Symbol)
|
25
|
+
end
|
26
|
+
private_constant :SYMBOL_TO_STRING_CACHE
|
27
|
+
|
28
|
+
# rubocop:disable Metrics
|
23
29
|
def style_detected(detected)
|
24
30
|
return if no_acceptable_style?
|
25
31
|
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
32
|
+
# This logic is more complex than it needs to be
|
33
|
+
# to avoid allocating Arrays in the hot code path.
|
34
|
+
updated_list =
|
35
|
+
if detected_style
|
36
|
+
if detected_style.size == 1 && detected_style.include?(SYMBOL_TO_STRING_CACHE[detected])
|
37
|
+
detected_style
|
38
|
+
else
|
39
|
+
detected_as_strings = SYMBOL_TO_STRING_CACHE.values_at(*detected)
|
40
|
+
detected_style & detected_as_strings
|
41
|
+
end
|
42
|
+
else
|
43
|
+
# We haven't observed any specific style yet.
|
44
|
+
SYMBOL_TO_STRING_CACHE.values_at(*detected)
|
45
|
+
end
|
29
46
|
|
30
|
-
updated_list = if detected_style
|
31
|
-
detected_style & detected_as_strings
|
32
|
-
else
|
33
|
-
# We haven't observed any specific style yet.
|
34
|
-
detected_as_strings
|
35
|
-
end
|
36
47
|
if updated_list.empty?
|
37
48
|
no_acceptable_style!
|
38
49
|
else
|
@@ -40,6 +51,7 @@ module RuboCop
|
|
40
51
|
config_to_allow_offenses[style_parameter_name] = updated_list.first
|
41
52
|
end
|
42
53
|
end
|
54
|
+
# rubocop:enable Metrics
|
43
55
|
|
44
56
|
def no_acceptable_style?
|
45
57
|
config_to_allow_offenses['Enabled'] == false
|
@@ -7,12 +7,12 @@ module RuboCop
|
|
7
7
|
module FirstElementLineBreak
|
8
8
|
private
|
9
9
|
|
10
|
-
def check_method_line_break(node, children)
|
10
|
+
def check_method_line_break(node, children, ignore_last: false)
|
11
11
|
return if children.empty?
|
12
12
|
|
13
13
|
return unless method_uses_parens?(node, children.first)
|
14
14
|
|
15
|
-
check_children_line_break(node, children)
|
15
|
+
check_children_line_break(node, children, ignore_last: ignore_last)
|
16
16
|
end
|
17
17
|
|
18
18
|
def method_uses_parens?(node, limit)
|
@@ -20,7 +20,7 @@ module RuboCop
|
|
20
20
|
/\s*\(\s*$/.match?(source)
|
21
21
|
end
|
22
22
|
|
23
|
-
def check_children_line_break(node, children, start = node)
|
23
|
+
def check_children_line_break(node, children, start = node, ignore_last: false)
|
24
24
|
return if children.empty?
|
25
25
|
|
26
26
|
line = start.first_line
|
@@ -28,8 +28,8 @@ module RuboCop
|
|
28
28
|
min = first_by_line(children)
|
29
29
|
return if line != min.first_line
|
30
30
|
|
31
|
-
|
32
|
-
return if line ==
|
31
|
+
max_line = last_line(children, ignore_last: ignore_last)
|
32
|
+
return if line == max_line
|
33
33
|
|
34
34
|
add_offense(min) { |corrector| EmptyLineCorrector.insert_before(corrector, min) }
|
35
35
|
end
|
@@ -38,8 +38,12 @@ module RuboCop
|
|
38
38
|
nodes.min_by(&:first_line)
|
39
39
|
end
|
40
40
|
|
41
|
-
def
|
42
|
-
|
41
|
+
def last_line(nodes, ignore_last:)
|
42
|
+
if ignore_last
|
43
|
+
nodes.map(&:first_line)
|
44
|
+
else
|
45
|
+
nodes.map(&:last_line)
|
46
|
+
end.max
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
# This module checks for Ruby 3.1's hash value omission syntax.
|
6
|
+
# rubocop:disable Metrics/ModuleLength
|
6
7
|
module HashShorthandSyntax
|
7
8
|
OMIT_HASH_VALUE_MSG = 'Omit the hash value.'
|
8
9
|
EXPLICIT_HASH_VALUE_MSG = 'Include the hash value.'
|
@@ -45,17 +46,21 @@ module RuboCop
|
|
45
46
|
|
46
47
|
private
|
47
48
|
|
49
|
+
# rubocop:disable Metrics/AbcSize
|
48
50
|
def register_offense(node, message, replacement)
|
49
51
|
add_offense(node.value, message: message) do |corrector|
|
50
52
|
if (def_node = def_node_that_require_parentheses(node))
|
51
53
|
white_spaces = range_between(def_node.loc.selector.end_pos,
|
52
54
|
def_node.first_argument.source_range.begin_pos)
|
53
55
|
corrector.replace(white_spaces, '(')
|
54
|
-
|
56
|
+
|
57
|
+
last_argument = def_node.arguments.last
|
58
|
+
corrector.insert_after(last_argument, ')') if node == last_argument.pairs.last
|
55
59
|
end
|
56
60
|
corrector.replace(node, replacement)
|
57
61
|
end
|
58
62
|
end
|
63
|
+
# rubocop:enable Metrics/AbcSize
|
59
64
|
|
60
65
|
def ignore_mixed_hash_shorthand_syntax?(hash_node)
|
61
66
|
target_ruby_version <= 3.0 || enforced_shorthand_syntax != 'consistent' ||
|
@@ -89,6 +94,8 @@ module RuboCop
|
|
89
94
|
end
|
90
95
|
|
91
96
|
def def_node_that_require_parentheses(node)
|
97
|
+
last_pair = node.parent.pairs.last
|
98
|
+
return unless last_pair.key.source == last_pair.value.source
|
92
99
|
return unless (send_node = find_ancestor_send_node(node))
|
93
100
|
return unless without_parentheses_call_expr_follows?(send_node)
|
94
101
|
|
@@ -100,7 +107,11 @@ module RuboCop
|
|
100
107
|
def find_ancestor_send_node(node)
|
101
108
|
ancestor = node.parent.parent
|
102
109
|
|
103
|
-
ancestor if ancestor&.call_type? && !
|
110
|
+
ancestor if ancestor&.call_type? && !brackets?(ancestor)
|
111
|
+
end
|
112
|
+
|
113
|
+
def brackets?(send_node)
|
114
|
+
send_node.method?(:[]) || send_node.method?(:[]=)
|
104
115
|
end
|
105
116
|
|
106
117
|
def use_element_of_hash_literal_as_receiver?(ancestor, parent)
|
@@ -180,4 +191,5 @@ module RuboCop
|
|
180
191
|
end
|
181
192
|
end
|
182
193
|
end
|
194
|
+
# rubocop:enable Metrics/ModuleLength
|
183
195
|
end
|
@@ -57,7 +57,14 @@ module RuboCop
|
|
57
57
|
def indentation_difference(line)
|
58
58
|
return 0 unless tab_indentation_width
|
59
59
|
|
60
|
-
|
60
|
+
index =
|
61
|
+
if line.match?(/^[^\t]/)
|
62
|
+
0
|
63
|
+
else
|
64
|
+
line.index(/[^\t]/) || 0
|
65
|
+
end
|
66
|
+
|
67
|
+
index * (tab_indentation_width - 1)
|
61
68
|
end
|
62
69
|
|
63
70
|
def extend_uri_end_position(line, end_position)
|
@@ -59,13 +59,15 @@ module RuboCop
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def complexity(body)
|
62
|
-
|
62
|
+
score = 1
|
63
|
+
body.each_node(:lvasgn, *self.class::COUNTED_NODES) do |node|
|
63
64
|
if node.lvasgn_type?
|
64
65
|
reset_on_lvasgn(node)
|
65
|
-
|
66
|
+
else
|
67
|
+
score += complexity_score_for(node)
|
66
68
|
end
|
67
|
-
score + complexity_score_for(node)
|
68
69
|
end
|
70
|
+
score
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
@@ -10,8 +10,8 @@ module RuboCop
|
|
10
10
|
module MultilineElementLineBreaks
|
11
11
|
private
|
12
12
|
|
13
|
-
def check_line_breaks(_node, children)
|
14
|
-
return if all_on_same_line?(children)
|
13
|
+
def check_line_breaks(_node, children, ignore_last: false)
|
14
|
+
return if all_on_same_line?(children, ignore_last: ignore_last)
|
15
15
|
|
16
16
|
last_seen_line = -1
|
17
17
|
children.each do |child|
|
@@ -23,9 +23,11 @@ module RuboCop
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def all_on_same_line?(nodes)
|
26
|
+
def all_on_same_line?(nodes, ignore_last: false)
|
27
27
|
return true if nodes.empty?
|
28
28
|
|
29
|
+
return same_line?(nodes.first, nodes.last) if ignore_last
|
30
|
+
|
29
31
|
nodes.first.first_line == nodes.last.last_line
|
30
32
|
end
|
31
33
|
end
|
@@ -97,9 +97,7 @@ module RuboCop
|
|
97
97
|
# @return [String]
|
98
98
|
def whitespace_between(node)
|
99
99
|
if node.children.length >= 2
|
100
|
-
node.source
|
101
|
-
node.children[0].loc.expression.end_pos...node.children[1].loc.expression.begin_pos
|
102
|
-
]
|
100
|
+
node.children[0].source_range.end.join(node.children[1].source_range.begin).source
|
103
101
|
else
|
104
102
|
' '
|
105
103
|
end
|
@@ -111,7 +109,7 @@ module RuboCop
|
|
111
109
|
# @param [RuboCop::AST::ArrayNode] node
|
112
110
|
# @return [String]
|
113
111
|
def whitespace_leading(node)
|
114
|
-
node.
|
112
|
+
node.loc.begin.end.join(node.children[0].source_range.begin).source
|
115
113
|
end
|
116
114
|
|
117
115
|
# Provides trailing whitespace for building a bracketed array.
|
@@ -120,7 +118,7 @@ module RuboCop
|
|
120
118
|
# @param [RuboCop::AST::ArrayNode] node
|
121
119
|
# @return [String]
|
122
120
|
def whitespace_trailing(node)
|
123
|
-
node.
|
121
|
+
node.children[-1].source_range.end.join(node.loc.end.begin).source
|
124
122
|
end
|
125
123
|
end
|
126
124
|
end
|
@@ -175,7 +175,7 @@ module RuboCop
|
|
175
175
|
|
176
176
|
def remove_optarg_equals(asgn_tokens, processed_source)
|
177
177
|
optargs = processed_source.ast.each_node(:optarg)
|
178
|
-
optarg_eql = optargs.
|
178
|
+
optarg_eql = optargs.to_set { |o| o.loc.operator.begin_pos }
|
179
179
|
asgn_tokens.reject { |t| optarg_eql.include?(t.begin_pos) }
|
180
180
|
end
|
181
181
|
end
|
@@ -4,8 +4,8 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for checking `rescue` nodes.
|
6
6
|
module RescueNode
|
7
|
-
def
|
8
|
-
@modifier_locations
|
7
|
+
def modifier_locations
|
8
|
+
@modifier_locations ||= processed_source.tokens.select(&:rescue_modifier?).map!(&:pos)
|
9
9
|
end
|
10
10
|
|
11
11
|
private
|
@@ -13,7 +13,7 @@ module RuboCop
|
|
13
13
|
def rescue_modifier?(node)
|
14
14
|
return false unless node.respond_to?(:resbody_type?)
|
15
15
|
|
16
|
-
node.resbody_type? &&
|
16
|
+
node.resbody_type? && modifier_locations.include?(node.loc.keyword)
|
17
17
|
end
|
18
18
|
|
19
19
|
# @deprecated Use ResbodyNode#exceptions instead
|
@@ -5,6 +5,7 @@ module RuboCop
|
|
5
5
|
# Common functionality for modifier cops.
|
6
6
|
module StatementModifier
|
7
7
|
include LineLengthHelp
|
8
|
+
include RangeHelp
|
8
9
|
|
9
10
|
private
|
10
11
|
|
@@ -56,7 +57,7 @@ module RuboCop
|
|
56
57
|
|
57
58
|
def if_body_source(if_body)
|
58
59
|
if if_body.call_type? &&
|
59
|
-
if_body.last_argument&.hash_type? && if_body.last_argument.pairs.last
|
60
|
+
if_body.last_argument&.hash_type? && if_body.last_argument.pairs.last&.value_omission?
|
60
61
|
"#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
|
61
62
|
else
|
62
63
|
if_body.source
|
@@ -108,7 +108,7 @@ module RuboCop
|
|
108
108
|
return if node.body.nil?
|
109
109
|
|
110
110
|
node.body.each_descendant(:lvar, :lvasgn).any? do |lvar|
|
111
|
-
!lvar.parent.block_pass_type? && lvar.
|
111
|
+
!lvar.parent.block_pass_type? && lvar.node_parts[0].to_s == last_argument
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|