rubocop 1.70.0 → 1.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +17 -0
- data/lib/rubocop/cli/command/show_cops.rb +24 -2
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +7 -7
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +12 -2
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +12 -17
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -0
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -3
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_subset.rb +170 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +7 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -2
- data/lib/rubocop/cop/security/compound_hash.rb +1 -0
- data/lib/rubocop/cop/style/array_first_last.rb +18 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +6 -19
- data/lib/rubocop/cop/style/collection_methods.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +1 -1
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
- data/lib/rubocop/cop/style/hash_except.rb +5 -131
- data/lib/rubocop/cop/style/hash_slice.rb +65 -0
- data/lib/rubocop/cop/style/map_to_set.rb +3 -2
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/open_struct_use.rb +4 -4
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -10
- data/lib/rubocop/cop/style/redundant_parentheses.rb +3 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
- data/lib/rubocop/cop/style/string_methods.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
- data/lib/rubocop/cops_documentation_generator.rb +13 -13
- data/lib/rubocop/directive_comment.rb +9 -8
- data/lib/rubocop/options.rb +2 -1
- data/lib/rubocop/result_cache.rb +13 -13
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/target_finder.rb +1 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +9 -8
@@ -12,7 +12,7 @@ module RuboCop
|
|
12
12
|
# are handled by Lint/UselessNumericOperation.
|
13
13
|
#
|
14
14
|
# NOTE: This cop doesn't detect offenses for the `-` and `%` operator because it
|
15
|
-
# can't determine the type of `x`. If `x` is an Array or String
|
15
|
+
# can't determine the type of `x`. If `x` is an `Array` or `String`, it doesn't perform
|
16
16
|
# a numeric operation.
|
17
17
|
#
|
18
18
|
# @example
|
@@ -50,43 +50,38 @@ module RuboCop
|
|
50
50
|
|
51
51
|
# @!method operation_with_constant_result?(node)
|
52
52
|
def_node_matcher :operation_with_constant_result?,
|
53
|
-
'(
|
53
|
+
'(call (call nil? $_lhs) $_operation ({int | call nil?} $_rhs))'
|
54
54
|
|
55
55
|
# @!method abbreviated_assignment_with_constant_result?(node)
|
56
56
|
def_node_matcher :abbreviated_assignment_with_constant_result?,
|
57
|
-
'(op-asgn (lvasgn $
|
57
|
+
'(op-asgn (lvasgn $_lhs) $_operation ({int lvar} $_rhs))'
|
58
58
|
|
59
59
|
def on_send(node)
|
60
|
-
return unless operation_with_constant_result?(node)
|
61
|
-
|
62
|
-
variable, operation, number = operation_with_constant_result?(node)
|
63
|
-
result = constant_result?(variable, operation, number)
|
64
|
-
return unless result
|
60
|
+
return unless (lhs, operation, rhs = operation_with_constant_result?(node))
|
61
|
+
return unless (result = constant_result?(lhs, operation, rhs))
|
65
62
|
|
66
63
|
add_offense(node) do |corrector|
|
67
64
|
corrector.replace(node, result.to_s)
|
68
65
|
end
|
69
66
|
end
|
67
|
+
alias on_csend on_send
|
70
68
|
|
71
69
|
def on_op_asgn(node)
|
72
|
-
return unless abbreviated_assignment_with_constant_result?(node)
|
73
|
-
|
74
|
-
variable, operation, number = abbreviated_assignment_with_constant_result?(node)
|
75
|
-
result = constant_result?(variable, operation, number)
|
76
|
-
return unless result
|
70
|
+
return unless (lhs, operation, rhs = abbreviated_assignment_with_constant_result?(node))
|
71
|
+
return unless (result = constant_result?(lhs, operation, rhs))
|
77
72
|
|
78
73
|
add_offense(node) do |corrector|
|
79
|
-
corrector.replace(node, "#{
|
74
|
+
corrector.replace(node, "#{lhs} = #{result}")
|
80
75
|
end
|
81
76
|
end
|
82
77
|
|
83
78
|
private
|
84
79
|
|
85
|
-
def constant_result?(
|
86
|
-
if
|
80
|
+
def constant_result?(lhs, operation, rhs)
|
81
|
+
if rhs.to_s == '0'
|
87
82
|
return 0 if operation == :*
|
88
83
|
return 1 if operation == :**
|
89
|
-
elsif
|
84
|
+
elsif rhs == lhs
|
90
85
|
return 1 if operation == :/
|
91
86
|
end
|
92
87
|
# If we weren't able to find any matches, return false so we can bail out.
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Looks for references of Regexp captures that are out of range
|
6
|
+
# Looks for references of `Regexp` captures that are out of range
|
7
7
|
# and thus always returns nil.
|
8
8
|
#
|
9
9
|
# @safety
|
@@ -61,6 +61,7 @@ module RuboCop
|
|
61
61
|
check_regexp(node.receiver)
|
62
62
|
end
|
63
63
|
end
|
64
|
+
alias after_csend after_send
|
64
65
|
|
65
66
|
def on_when(node)
|
66
67
|
regexp_conditions = node.conditions.select(&:regexp_type?)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Checks for redundant quantifiers inside Regexp literals.
|
6
|
+
# Checks for redundant quantifiers inside `Regexp` literals.
|
7
7
|
#
|
8
8
|
# It is always allowed when interpolation is used in a regexp literal,
|
9
9
|
# because it's unknown what kind of string will be expanded as a result:
|
@@ -29,7 +29,7 @@ module RuboCop
|
|
29
29
|
RESTRICT_ON_SEND = %i[print puts warn].freeze
|
30
30
|
|
31
31
|
# @!method to_s_without_args?(node)
|
32
|
-
def_node_matcher :to_s_without_args?, '(
|
32
|
+
def_node_matcher :to_s_without_args?, '(call _ :to_s)'
|
33
33
|
|
34
34
|
def on_interpolation(begin_node)
|
35
35
|
final_node = begin_node.children.last
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
def on_send(node)
|
43
43
|
return if node.receiver
|
44
44
|
|
45
|
-
node.each_child_node(:send) do |child|
|
45
|
+
node.each_child_node(:send, :csend) do |child|
|
46
46
|
next if !child.method?(:to_s) || child.arguments.any?
|
47
47
|
|
48
48
|
register_offense(child, "`#{node.method_name}`")
|
@@ -97,12 +97,19 @@ module RuboCop
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def require_parentheses?(send_node)
|
100
|
+
return true if operator_inside_hash?(send_node)
|
100
101
|
return false unless send_node.comparison_method?
|
101
102
|
return false unless (node = send_node.parent)
|
102
103
|
|
103
104
|
(node.respond_to?(:logical_operator?) && node.logical_operator?) ||
|
104
105
|
(node.respond_to?(:comparison_method?) && node.comparison_method?)
|
105
106
|
end
|
107
|
+
|
108
|
+
def operator_inside_hash?(send_node)
|
109
|
+
# If an operator call (without a dot) is inside a hash, it needs
|
110
|
+
# to be parenthesized when converted to safe navigation.
|
111
|
+
send_node.parent&.pair_type? && !send_node.loc.dot
|
112
|
+
end
|
106
113
|
end
|
107
114
|
end
|
108
115
|
end
|
@@ -3,11 +3,11 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Checks for Hash creation with a mutable default value.
|
7
|
-
# Creating a Hash in such a way will share the default value
|
6
|
+
# Checks for `Hash` creation with a mutable default value.
|
7
|
+
# Creating a `Hash` in such a way will share the default value
|
8
8
|
# across all keys, causing unexpected behavior when modifying it.
|
9
9
|
#
|
10
|
-
# For example, when the Hash was created with an Array as the argument,
|
10
|
+
# For example, when the `Hash` was created with an `Array` as the argument,
|
11
11
|
# calling `hash[:foo] << 'bar'` will also change the value of all
|
12
12
|
# other keys that have not been explicitly assigned to.
|
13
13
|
#
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
# rescue, ensure, etc.
|
18
18
|
#
|
19
19
|
# This cop's autocorrection avoids cases like `a ||= 1` because removing assignment from
|
20
|
-
# operator assignment can cause NameError if this assignment has been used to declare
|
20
|
+
# operator assignment can cause `NameError` if this assignment has been used to declare
|
21
21
|
# a local variable. For example, replacing `a ||= 1` with `a || 1` may cause
|
22
22
|
# "undefined local variable or method `a' for main:Object (NameError)".
|
23
23
|
#
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
RESTRICT_ON_SEND = %i[+ - * / **].freeze
|
36
36
|
|
37
37
|
# @!method useless_operation?(node)
|
38
|
-
def_node_matcher :useless_operation?, '(
|
38
|
+
def_node_matcher :useless_operation?, '(call (call nil? $_) $_ (int $_))'
|
39
39
|
|
40
40
|
# @!method useless_abbreviated_assignment?(node)
|
41
41
|
def_node_matcher :useless_abbreviated_assignment?, '(op-asgn (lvasgn $_) $_ (int $_))'
|
@@ -50,6 +50,7 @@ module RuboCop
|
|
50
50
|
corrector.replace(node, variable)
|
51
51
|
end
|
52
52
|
end
|
53
|
+
alias on_csend on_send
|
53
54
|
|
54
55
|
def on_op_asgn(node)
|
55
56
|
return unless useless_abbreviated_assignment?(node)
|
@@ -52,12 +52,19 @@ module RuboCop
|
|
52
52
|
'Prefer reading the data from an external source.'
|
53
53
|
RESTRICT_ON_SEND = [:[]].freeze
|
54
54
|
|
55
|
+
# @!method set_const?(node)
|
56
|
+
def_node_matcher :set_const?, <<~PATTERN
|
57
|
+
(const {cbase nil?} :Set)
|
58
|
+
PATTERN
|
59
|
+
|
55
60
|
def on_array(node)
|
56
61
|
add_offense(node) if node.children.length >= collection_threshold
|
57
62
|
end
|
58
63
|
alias on_hash on_array
|
59
64
|
|
60
65
|
def on_index(node)
|
66
|
+
return unless set_const?(node.receiver)
|
67
|
+
|
61
68
|
add_offense(node) if node.arguments.length >= collection_threshold
|
62
69
|
end
|
63
70
|
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
36
36
|
include MethodComplexity
|
37
37
|
include Utils::IteratingBlock
|
38
38
|
|
39
|
-
MSG = 'Cyclomatic complexity for
|
39
|
+
MSG = 'Cyclomatic complexity for `%<method>s` is too high. [%<complexity>d/%<max>d]'
|
40
40
|
COUNTED_NODES = %i[if while until for csend block block_pass
|
41
41
|
rescue when in_pattern and or or_asgn and_asgn].freeze
|
42
42
|
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
# end # ===
|
28
28
|
# end # 7 complexity points
|
29
29
|
class PerceivedComplexity < CyclomaticComplexity
|
30
|
-
MSG = 'Perceived complexity for
|
30
|
+
MSG = 'Perceived complexity for `%<method>s` is too high. [%<complexity>d/%<max>d]'
|
31
31
|
|
32
32
|
COUNTED_NODES = (CyclomaticComplexity::COUNTED_NODES - [:when] + [:case]).freeze
|
33
33
|
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
module FrozenStringLiteral
|
7
7
|
module_function
|
8
8
|
|
9
|
-
|
9
|
+
FROZEN_STRING_LITERAL_REGEXP = /#\s*frozen[-_]?string[-_]?literal:/i.freeze
|
10
10
|
FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
|
11
11
|
FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
|
12
12
|
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for Style/HashExcept and Style/HashSlice cops.
|
6
|
+
# It registers an offense on methods with blocks that are equivalent
|
7
|
+
# to Hash#except or Hash#slice.
|
8
|
+
module HashSubset
|
9
|
+
include RangeHelp
|
10
|
+
extend NodePattern::Macros
|
11
|
+
|
12
|
+
RESTRICT_ON_SEND = %i[reject select filter].freeze
|
13
|
+
|
14
|
+
SUBSET_METHODS = %i[== != eql? include?].freeze
|
15
|
+
ACTIVE_SUPPORT_SUBSET_METHODS = (SUBSET_METHODS + %i[in? exclude?]).freeze
|
16
|
+
|
17
|
+
MSG = 'Use `%<prefer>s` instead.'
|
18
|
+
|
19
|
+
# @!method block_with_first_arg_check?(node)
|
20
|
+
def_node_matcher :block_with_first_arg_check?, <<~PATTERN
|
21
|
+
(block
|
22
|
+
(call _ _)
|
23
|
+
(args
|
24
|
+
$(arg _key)
|
25
|
+
(arg _))
|
26
|
+
{
|
27
|
+
$(send
|
28
|
+
{(lvar _key) $_ _ | _ $_ (lvar _key)})
|
29
|
+
(send
|
30
|
+
$(send
|
31
|
+
{(lvar _key) $_ _ | _ $_ (lvar _key)}) :!)
|
32
|
+
})
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
offense_range, key_source = extract_offense(node)
|
37
|
+
|
38
|
+
return unless offense_range
|
39
|
+
return unless semantically_subset_method?(node)
|
40
|
+
|
41
|
+
preferred_method = "#{preferred_method_name}(#{key_source})"
|
42
|
+
add_offense(offense_range, message: format(MSG, prefer: preferred_method)) do |corrector|
|
43
|
+
corrector.replace(offense_range, preferred_method)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
alias on_csend on_send
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def semantically_subset_method?(node)
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
|
54
|
+
def preferred_method_name
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_offense(node)
|
59
|
+
block = node.parent
|
60
|
+
return unless extracts_hash_subset?(block)
|
61
|
+
|
62
|
+
except_key = except_key(block)
|
63
|
+
return if except_key.nil? || !safe_to_register_offense?(block, except_key)
|
64
|
+
|
65
|
+
[offense_range(node), except_key_source(except_key)]
|
66
|
+
end
|
67
|
+
|
68
|
+
def extracts_hash_subset?(block)
|
69
|
+
block_with_first_arg_check?(block) do |key_arg, send_node, method|
|
70
|
+
return false unless supported_subset_method?(method)
|
71
|
+
|
72
|
+
case method
|
73
|
+
when :include?, :exclude?
|
74
|
+
send_node.first_argument.source == key_arg.source
|
75
|
+
when :in?
|
76
|
+
send_node.receiver.source == key_arg.source
|
77
|
+
else
|
78
|
+
true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def supported_subset_method?(method)
|
84
|
+
if active_support_extensions_enabled?
|
85
|
+
ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
|
86
|
+
else
|
87
|
+
SUBSET_METHODS.include?(method)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def semantically_except_method?(node)
|
92
|
+
block = node.parent
|
93
|
+
body, negated = extract_body_if_negated(block.body)
|
94
|
+
|
95
|
+
if node.method?('reject')
|
96
|
+
body.method?('==') || body.method?('eql?') || included?(body, negated)
|
97
|
+
else
|
98
|
+
body.method?('!=') || not_included?(body, negated)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def semantically_slice_method?(node)
|
103
|
+
!semantically_except_method?(node)
|
104
|
+
end
|
105
|
+
|
106
|
+
def included?(body, negated)
|
107
|
+
if negated
|
108
|
+
body.method?('exclude?')
|
109
|
+
else
|
110
|
+
body.method?('include?') || body.method?('in?')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def not_included?(body, negated)
|
115
|
+
included?(body, !negated)
|
116
|
+
end
|
117
|
+
|
118
|
+
def safe_to_register_offense?(block, except_key)
|
119
|
+
body = block.body
|
120
|
+
|
121
|
+
if body.method?('==') || body.method?('!=')
|
122
|
+
except_key.sym_type? || except_key.str_type?
|
123
|
+
else
|
124
|
+
true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def extract_body_if_negated(body)
|
129
|
+
if body.method?('!')
|
130
|
+
[body.receiver, true]
|
131
|
+
else
|
132
|
+
[body, false]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def except_key_source(key)
|
137
|
+
if key.array_type?
|
138
|
+
key = if key.percent_literal?
|
139
|
+
key.each_value.map { |v| decorate_source(v) }
|
140
|
+
else
|
141
|
+
key.each_value.map(&:source)
|
142
|
+
end
|
143
|
+
return key.join(', ')
|
144
|
+
end
|
145
|
+
|
146
|
+
key.literal? ? key.source : "*#{key.source}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def decorate_source(value)
|
150
|
+
return ":\"#{value.source}\"" if value.dsym_type?
|
151
|
+
return "\"#{value.source}\"" if value.dstr_type?
|
152
|
+
return ":#{value.source}" if value.sym_type?
|
153
|
+
|
154
|
+
"'#{value.source}'"
|
155
|
+
end
|
156
|
+
|
157
|
+
def except_key(node)
|
158
|
+
key_arg = node.argument_list.first.source
|
159
|
+
body, = extract_body_if_negated(node.body)
|
160
|
+
lhs, _method_name, rhs = *body
|
161
|
+
|
162
|
+
lhs.source == key_arg ? rhs : lhs
|
163
|
+
end
|
164
|
+
|
165
|
+
def offense_range(node)
|
166
|
+
range_between(node.loc.selector.begin_pos, node.parent.loc.end.end_pos)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -55,14 +55,19 @@ module RuboCop
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def if_body_source(if_body)
|
58
|
-
if if_body.call_type? &&
|
59
|
-
if_body.last_argument&.hash_type? && if_body.last_argument.pairs.last&.value_omission?
|
58
|
+
if if_body.call_type? && !if_body.method?(:[]=) && omitted_value_in_last_hash_arg?(if_body)
|
60
59
|
"#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
|
61
60
|
else
|
62
61
|
if_body.source
|
63
62
|
end
|
64
63
|
end
|
65
64
|
|
65
|
+
def omitted_value_in_last_hash_arg?(if_body)
|
66
|
+
return false unless (last_argument = if_body.last_argument)
|
67
|
+
|
68
|
+
last_argument.hash_type? && last_argument.pairs.last&.value_omission?
|
69
|
+
end
|
70
|
+
|
66
71
|
def method_source(if_body)
|
67
72
|
end_range = if_body.implicit_call? ? if_body.loc.dot.end : if_body.loc.selector
|
68
73
|
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
|
-
# Common methods shared by Style/TrailingCommaInArguments
|
6
|
-
# Style/
|
5
|
+
# Common methods shared by Style/TrailingCommaInArguments,
|
6
|
+
# Style/TrailingCommaInArrayLiteral and Style/TrailingCommaInHashLiteral
|
7
7
|
module TrailingComma
|
8
8
|
include ConfigurableEnforcedStyle
|
9
9
|
include RangeHelp
|
@@ -42,14 +42,30 @@ module RuboCop
|
|
42
42
|
return if node.parent && brace_method?(node.parent)
|
43
43
|
|
44
44
|
preferred = (value.zero? ? 'first' : 'last')
|
45
|
-
|
46
|
-
|
45
|
+
offense_range = find_offense_range(node)
|
46
|
+
|
47
|
+
add_offense(offense_range, message: format(MSG, preferred: preferred)) do |corrector|
|
48
|
+
corrector.replace(offense_range, preferred_value(node, preferred))
|
47
49
|
end
|
48
50
|
end
|
49
51
|
# rubocop:enable Metrics/AbcSize
|
52
|
+
alias on_csend on_send
|
50
53
|
|
51
54
|
private
|
52
55
|
|
56
|
+
def preferred_value(node, value)
|
57
|
+
value = ".#{value}" unless node.loc.dot
|
58
|
+
value
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_offense_range(node)
|
62
|
+
if node.loc.dot
|
63
|
+
node.loc.selector.join(node.source_range.end)
|
64
|
+
else
|
65
|
+
node.loc.selector
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
53
69
|
def innermost_braces_node(node)
|
54
70
|
node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
|
55
71
|
node
|
@@ -195,6 +195,7 @@ module RuboCop
|
|
195
195
|
end
|
196
196
|
end
|
197
197
|
end
|
198
|
+
alias on_csend on_send
|
198
199
|
|
199
200
|
def on_block(node)
|
200
201
|
return if ignored_node?(node)
|
@@ -348,7 +349,7 @@ module RuboCop
|
|
348
349
|
case node.type
|
349
350
|
when :block, :numblock
|
350
351
|
yield node
|
351
|
-
when :send
|
352
|
+
when :send, :csend
|
352
353
|
# When a method has an argument which is another method with a block,
|
353
354
|
# that block needs braces, otherwise a syntax error will be introduced
|
354
355
|
# for subsequent arguments.
|
@@ -369,9 +370,8 @@ module RuboCop
|
|
369
370
|
end
|
370
371
|
# rubocop:enable Metrics/CyclomaticComplexity
|
371
372
|
|
372
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
373
373
|
def proper_block_style?(node)
|
374
|
-
return true if
|
374
|
+
return true if require_do_end?(node)
|
375
375
|
return special_method_proper_block_style?(node) if special_method?(node.method_name)
|
376
376
|
|
377
377
|
case style
|
@@ -381,15 +381,6 @@ module RuboCop
|
|
381
381
|
when :always_braces then braces_style?(node)
|
382
382
|
end
|
383
383
|
end
|
384
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
385
|
-
|
386
|
-
def require_braces?(node)
|
387
|
-
return false unless node.braces?
|
388
|
-
|
389
|
-
node.each_ancestor(:send).any? do |send|
|
390
|
-
send.arithmetic_operation? && node.source_range.end_pos < send.loc.selector.begin_pos
|
391
|
-
end
|
392
|
-
end
|
393
384
|
|
394
385
|
def require_do_end?(node)
|
395
386
|
return false if node.braces? || node.multiline?
|
@@ -483,14 +474,10 @@ module RuboCop
|
|
483
474
|
end
|
484
475
|
|
485
476
|
def return_value_of_scope?(node)
|
486
|
-
return false unless node.parent
|
487
|
-
|
488
|
-
conditional?(node.parent) || array_or_range?(node.parent) ||
|
489
|
-
node.parent.children.last == node
|
490
|
-
end
|
477
|
+
return false unless (parent = node.parent)
|
491
478
|
|
492
|
-
|
493
|
-
|
479
|
+
parent.conditional? || parent.operator_keyword? || array_or_range?(parent) ||
|
480
|
+
parent.children.last == node
|
494
481
|
end
|
495
482
|
|
496
483
|
def array_or_range?(node)
|
@@ -49,7 +49,6 @@ module RuboCop
|
|
49
49
|
def on_block(node)
|
50
50
|
check_method_node(node.send_node)
|
51
51
|
end
|
52
|
-
|
53
52
|
alias on_numblock on_block
|
54
53
|
|
55
54
|
def on_send(node)
|
@@ -57,6 +56,7 @@ module RuboCop
|
|
57
56
|
|
58
57
|
check_method_node(node)
|
59
58
|
end
|
59
|
+
alias on_csend on_send
|
60
60
|
|
61
61
|
private
|
62
62
|
|
@@ -309,7 +309,7 @@ module RuboCop
|
|
309
309
|
end
|
310
310
|
|
311
311
|
def allowed_single_line?(branches)
|
312
|
-
single_line_conditions_only? && branches.any?(&:begin_type?)
|
312
|
+
single_line_conditions_only? && branches.compact.any?(&:begin_type?)
|
313
313
|
end
|
314
314
|
|
315
315
|
def assignment_node(node)
|
@@ -445,6 +445,8 @@ module RuboCop
|
|
445
445
|
end
|
446
446
|
|
447
447
|
[condition.loc.else, condition.loc.end].each do |loc|
|
448
|
+
next unless loc
|
449
|
+
|
448
450
|
corrector.remove_preceding(loc, loc.column - column)
|
449
451
|
end
|
450
452
|
end
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# Checks for loops which iterate a constant number of times,
|
7
|
-
# using a Range literal and `#each`. This can be done more readably using
|
7
|
+
# using a `Range` literal and `#each`. This can be done more readably using
|
8
8
|
# `Integer#times`.
|
9
9
|
#
|
10
10
|
# This check only applies if the block takes no parameters.
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Suggests `ENV.fetch` for the replacement of `ENV[]`.
|
7
7
|
# `ENV[]` silently fails and returns `nil` when the environment variable is unset,
|
8
8
|
# which may cause unexpected behaviors when the developer forgets to set it.
|
9
|
-
# On the other hand, `ENV.fetch` raises KeyError or returns the explicitly
|
9
|
+
# On the other hand, `ENV.fetch` raises `KeyError` or returns the explicitly
|
10
10
|
# specified default value.
|
11
11
|
#
|
12
12
|
# @example
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks for uses of `each_key` and `each_value` Hash methods.
|
6
|
+
# Checks for uses of `each_key` and `each_value` `Hash` methods.
|
7
7
|
#
|
8
8
|
# NOTE: If you have an array of two-element arrays, you can put
|
9
9
|
# parentheses around the block arguments to indicate that you're not
|