rubocop 1.56.4 → 1.60.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 -4
- data/config/default.yml +57 -3
- data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +0 -2
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_obsoletion.rb +11 -8
- data/lib/rubocop/config_validator.rb +0 -2
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +12 -2
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +16 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +11 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
- data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +0 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +63 -4
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +43 -12
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +8 -3
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
- data/lib/rubocop/cop/naming/constant_name.rb +1 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +120 -17
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/case_like_if.rb +4 -4
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/class_equality_comparison.rb +5 -0
- data/lib/rubocop/cop/style/collection_compact.rb +18 -8
- data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/guard_clause.rb +26 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +83 -10
- data/lib/rubocop/cop/style/hash_except.rb +2 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +28 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +39 -2
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
- data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -3
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +9 -1
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +22 -5
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +10 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +68 -21
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
- data/lib/rubocop/cop/style/sample.rb +2 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +8 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cops_documentation_generator.rb +11 -1
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +5 -4
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/options.rb +0 -8
- data/lib/rubocop/result_cache.rb +0 -1
- data/lib/rubocop/rspec/shared_contexts.rb +6 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/server/cache.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +16 -24
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -23,6 +23,8 @@ module RuboCop
|
|
23
23
|
# array.reject { |e| e.nil? }
|
24
24
|
# array.delete_if { |e| e.nil? }
|
25
25
|
# array.select { |e| !e.nil? }
|
26
|
+
# array.grep_v(nil)
|
27
|
+
# array.grep_v(NilClass)
|
26
28
|
#
|
27
29
|
# # good
|
28
30
|
# array.compact
|
@@ -46,14 +48,14 @@ module RuboCop
|
|
46
48
|
extend TargetRubyVersion
|
47
49
|
|
48
50
|
MSG = 'Use `%<good>s` instead of `%<bad>s`.'
|
49
|
-
RESTRICT_ON_SEND = %i[reject delete_if reject! select select!].freeze
|
51
|
+
RESTRICT_ON_SEND = %i[reject delete_if reject! select select! grep_v].freeze
|
50
52
|
TO_ENUM_METHODS = %i[to_enum lazy].freeze
|
51
53
|
|
52
54
|
minimum_target_ruby_version 2.4
|
53
55
|
|
54
56
|
# @!method reject_method_with_block_pass?(node)
|
55
57
|
def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
|
56
|
-
(
|
58
|
+
(call !nil? {:reject :delete_if :reject!}
|
57
59
|
(block_pass
|
58
60
|
(sym :nil?)))
|
59
61
|
PATTERN
|
@@ -61,24 +63,29 @@ module RuboCop
|
|
61
63
|
# @!method reject_method?(node)
|
62
64
|
def_node_matcher :reject_method?, <<~PATTERN
|
63
65
|
(block
|
64
|
-
(
|
66
|
+
(call
|
65
67
|
!nil? {:reject :delete_if :reject!})
|
66
68
|
$(args ...)
|
67
|
-
(
|
69
|
+
(call
|
68
70
|
$(lvar _) :nil?))
|
69
71
|
PATTERN
|
70
72
|
|
71
73
|
# @!method select_method?(node)
|
72
74
|
def_node_matcher :select_method?, <<~PATTERN
|
73
75
|
(block
|
74
|
-
(
|
76
|
+
(call
|
75
77
|
!nil? {:select :select!})
|
76
78
|
$(args ...)
|
77
|
-
(
|
78
|
-
(
|
79
|
+
(call
|
80
|
+
(call
|
79
81
|
$(lvar _) :nil?) :!))
|
80
82
|
PATTERN
|
81
83
|
|
84
|
+
# @!method grep_v_with_nil?(node)
|
85
|
+
def_node_matcher :grep_v_with_nil?, <<~PATTERN
|
86
|
+
(send _ :grep_v {(nil) (const {nil? cbase} :NilClass)})
|
87
|
+
PATTERN
|
88
|
+
|
82
89
|
def on_send(node)
|
83
90
|
return unless (range = offense_range(node))
|
84
91
|
return if allowed_receiver?(node.receiver)
|
@@ -91,11 +98,13 @@ module RuboCop
|
|
91
98
|
|
92
99
|
add_offense(range, message: message) { |corrector| corrector.replace(range, good) }
|
93
100
|
end
|
101
|
+
alias on_csend on_send
|
94
102
|
|
95
103
|
private
|
96
104
|
|
105
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
97
106
|
def offense_range(node)
|
98
|
-
if reject_method_with_block_pass?(node)
|
107
|
+
if reject_method_with_block_pass?(node) || grep_v_with_nil?(node)
|
99
108
|
range(node, node)
|
100
109
|
else
|
101
110
|
block_node = node.parent
|
@@ -109,6 +118,7 @@ module RuboCop
|
|
109
118
|
range(node, block_node)
|
110
119
|
end
|
111
120
|
end
|
121
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
112
122
|
|
113
123
|
def to_enum_method?(node)
|
114
124
|
return false unless node.receiver.send_type?
|
@@ -59,8 +59,6 @@ module RuboCop
|
|
59
59
|
class CombinableLoops < Base
|
60
60
|
extend AutoCorrector
|
61
61
|
|
62
|
-
include RangeHelp
|
63
|
-
|
64
62
|
MSG = 'Combine this loop with the previous loop.'
|
65
63
|
|
66
64
|
def on_block(node)
|
@@ -105,11 +103,19 @@ module RuboCop
|
|
105
103
|
end
|
106
104
|
|
107
105
|
def combine_with_left_sibling(corrector, node)
|
108
|
-
corrector.
|
109
|
-
|
110
|
-
|
111
|
-
)
|
112
|
-
|
106
|
+
corrector.remove(node.left_sibling.body.source_range.end.join(node.left_sibling.loc.end))
|
107
|
+
corrector.remove(node.source_range.begin.join(node.body.source_range.begin))
|
108
|
+
|
109
|
+
correct_end_of_block(corrector, node)
|
110
|
+
end
|
111
|
+
|
112
|
+
def correct_end_of_block(corrector, node)
|
113
|
+
return unless node.left_sibling.respond_to?(:braces?)
|
114
|
+
return if node.right_sibling&.block_type? || node.right_sibling&.numblock_type?
|
115
|
+
|
116
|
+
end_of_block = node.left_sibling.braces? ? '}' : ' end'
|
117
|
+
corrector.remove(node.loc.end)
|
118
|
+
corrector.insert_before(node.source_range.end, end_of_block)
|
113
119
|
end
|
114
120
|
end
|
115
121
|
end
|
@@ -233,7 +233,7 @@ module RuboCop
|
|
233
233
|
PATTERN
|
234
234
|
|
235
235
|
ASSIGNMENT_TYPES.each do |type|
|
236
|
-
define_method "on_#{type}" do |node|
|
236
|
+
define_method :"on_#{type}" do |node|
|
237
237
|
return if part_of_ignored_node?(node)
|
238
238
|
return if node.parent&.shorthand_asgn?
|
239
239
|
|
@@ -534,7 +534,7 @@ module RuboCop
|
|
534
534
|
end
|
535
535
|
|
536
536
|
def element_assignment?(node)
|
537
|
-
node.send_type? && node.
|
537
|
+
node.send_type? && !node.method?(:[]=)
|
538
538
|
end
|
539
539
|
|
540
540
|
def extract_branches(node)
|
@@ -49,12 +49,12 @@ module RuboCop
|
|
49
49
|
class DateTime < Base
|
50
50
|
extend AutoCorrector
|
51
51
|
|
52
|
-
CLASS_MSG = 'Prefer Time over DateTime
|
53
|
-
COERCION_MSG = 'Do not use
|
52
|
+
CLASS_MSG = 'Prefer `Time` over `DateTime`.'
|
53
|
+
COERCION_MSG = 'Do not use `#to_datetime`.'
|
54
54
|
|
55
55
|
# @!method date_time?(node)
|
56
56
|
def_node_matcher :date_time?, <<~PATTERN
|
57
|
-
(
|
57
|
+
(call (const {nil? (cbase)} :DateTime) ...)
|
58
58
|
PATTERN
|
59
59
|
|
60
60
|
# @!method historic_date?(node)
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
|
65
65
|
# @!method to_datetime?(node)
|
66
66
|
def_node_matcher :to_datetime?, <<~PATTERN
|
67
|
-
(
|
67
|
+
(call _ :to_datetime)
|
68
68
|
PATTERN
|
69
69
|
|
70
70
|
def on_send(node)
|
@@ -75,6 +75,7 @@ module RuboCop
|
|
75
75
|
|
76
76
|
add_offense(node, message: message) { |corrector| autocorrect(corrector, node) }
|
77
77
|
end
|
78
|
+
alias on_csend on_send
|
78
79
|
|
79
80
|
private
|
80
81
|
|
@@ -32,27 +32,27 @@ module RuboCop
|
|
32
32
|
|
33
33
|
send_node = node.send_node
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
add_offense(range) do |corrector|
|
35
|
+
add_offense(send_node) do |corrector|
|
38
36
|
range_type, min, max = each_range(node)
|
39
37
|
|
40
38
|
max += 1 if range_type == :irange
|
41
39
|
|
42
|
-
corrector.replace(
|
40
|
+
corrector.replace(send_node, "#{max - min}.times")
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
44
|
private
|
47
45
|
|
48
46
|
def offending?(node)
|
47
|
+
return false unless node.arguments.empty?
|
48
|
+
|
49
49
|
each_range_with_zero_origin?(node) || each_range_without_block_argument?(node)
|
50
50
|
end
|
51
51
|
|
52
52
|
# @!method each_range(node)
|
53
53
|
def_node_matcher :each_range, <<~PATTERN
|
54
54
|
(block
|
55
|
-
(
|
55
|
+
(call
|
56
56
|
(begin
|
57
57
|
(${irange erange}
|
58
58
|
(int $_) (int $_)))
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
# @!method each_range_with_zero_origin?(node)
|
65
65
|
def_node_matcher :each_range_with_zero_origin?, <<~PATTERN
|
66
66
|
(block
|
67
|
-
(
|
67
|
+
(call
|
68
68
|
(begin
|
69
69
|
({irange erange}
|
70
70
|
(int 0) (int _)))
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
# @!method each_range_without_block_argument?(node)
|
77
77
|
def_node_matcher :each_range_without_block_argument?, <<~PATTERN
|
78
78
|
(block
|
79
|
-
(
|
79
|
+
(call
|
80
80
|
(begin
|
81
81
|
({irange erange}
|
82
82
|
(int _) (int _)))
|
@@ -58,12 +58,12 @@ module RuboCop
|
|
58
58
|
|
59
59
|
# @!method each_with_object_block_candidate?(node)
|
60
60
|
def_node_matcher :each_with_object_block_candidate?, <<~PATTERN
|
61
|
-
(block $(
|
61
|
+
(block $(call _ {:inject :reduce} _) $_ $_)
|
62
62
|
PATTERN
|
63
63
|
|
64
64
|
# @!method each_with_object_numblock_candidate?(node)
|
65
65
|
def_node_matcher :each_with_object_numblock_candidate?, <<~PATTERN
|
66
|
-
(numblock $(
|
66
|
+
(numblock $(call _ {:inject :reduce} _) 2 $_)
|
67
67
|
PATTERN
|
68
68
|
|
69
69
|
def autocorrect_block(corrector, node, return_value)
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
83
83
|
parent = node.parent
|
84
84
|
return false unless parent && %i[send super zsuper].include?(parent.type)
|
85
85
|
|
86
|
-
node.equal?(parent.
|
86
|
+
node.equal?(parent.first_argument) && !parentheses?(node.parent)
|
87
87
|
end
|
88
88
|
|
89
89
|
def replacement_range(node)
|
@@ -84,7 +84,7 @@ module RuboCop
|
|
84
84
|
# are considered.
|
85
85
|
return if node.method?(:eval) && !valid_eval_receiver?(node.receiver)
|
86
86
|
|
87
|
-
code = node.
|
87
|
+
code = node.first_argument
|
88
88
|
return unless code && (code.str_type? || code.dstr_type?)
|
89
89
|
|
90
90
|
check_location(node, code)
|
@@ -128,17 +128,6 @@ module RuboCop
|
|
128
128
|
node.method?(:eval) ? node.arguments.size >= 2 : true
|
129
129
|
end
|
130
130
|
|
131
|
-
# FIXME: It's a Style/ConditionalAssignment's false positive.
|
132
|
-
# rubocop:disable Style/ConditionalAssignment
|
133
|
-
def with_lineno?(node)
|
134
|
-
if node.method?(:eval)
|
135
|
-
node.arguments.size == 4
|
136
|
-
else
|
137
|
-
node.arguments.size == 3
|
138
|
-
end
|
139
|
-
end
|
140
|
-
# rubocop:enable Style/ConditionalAssignment
|
141
|
-
|
142
131
|
def add_offense_for_incorrect_line(method_name, line_node, sign, line_diff)
|
143
132
|
expected = expected_line(sign, line_diff)
|
144
133
|
message = format(MSG_INCORRECT_LINE,
|
@@ -165,7 +154,7 @@ module RuboCop
|
|
165
154
|
end
|
166
155
|
|
167
156
|
def check_line(node, code)
|
168
|
-
line_node = node.
|
157
|
+
line_node = node.last_argument
|
169
158
|
line_diff = line_difference(line_node, code)
|
170
159
|
if line_diff.zero?
|
171
160
|
add_offense_for_same_line(node, line_node)
|
@@ -227,7 +216,7 @@ module RuboCop
|
|
227
216
|
end
|
228
217
|
|
229
218
|
def missing_line(node, code)
|
230
|
-
line_diff = line_difference(node.
|
219
|
+
line_diff = line_difference(node.last_argument, code)
|
231
220
|
sign = line_diff.positive? ? :+ : :-
|
232
221
|
expected_line(sign, line_diff)
|
233
222
|
end
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
30
30
|
|
31
31
|
# @!method exact_regexp_match(node)
|
32
32
|
def_node_matcher :exact_regexp_match, <<~PATTERN
|
33
|
-
(
|
33
|
+
(call
|
34
34
|
_ {:=~ :=== :!~ :match :match?}
|
35
35
|
(regexp
|
36
36
|
(str $_)
|
@@ -49,6 +49,7 @@ module RuboCop
|
|
49
49
|
corrector.replace(node, prefer)
|
50
50
|
end
|
51
51
|
end
|
52
|
+
alias on_csend on_send
|
52
53
|
|
53
54
|
private
|
54
55
|
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
def extract_block_name(def_node)
|
88
88
|
if def_node.block_argument?
|
89
|
-
def_node.
|
89
|
+
def_node.last_argument.name
|
90
90
|
else
|
91
91
|
'block'
|
92
92
|
end
|
@@ -127,7 +127,7 @@ module RuboCop
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def insert_argument(node, corrector, block_name)
|
130
|
-
last_arg = node.
|
130
|
+
last_arg = node.last_argument
|
131
131
|
arg_range = range_with_surrounding_comma(last_arg.source_range, :right)
|
132
132
|
replacement = " &#{block_name}"
|
133
133
|
replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
|
@@ -4,13 +4,25 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# Enforces the use of a single string formatting utility.
|
7
|
-
# Valid options include Kernel#format
|
7
|
+
# Valid options include `Kernel#format`, `Kernel#sprintf`, and `String#%`.
|
8
8
|
#
|
9
|
-
# The detection of String
|
9
|
+
# The detection of `String#%` cannot be implemented in a reliable
|
10
10
|
# manner for all cases, so only two scenarios are considered -
|
11
11
|
# if the first argument is a string literal and if the second
|
12
12
|
# argument is an array literal.
|
13
13
|
#
|
14
|
+
# Autocorrection will be applied when using argument is a literal or known built-in conversion
|
15
|
+
# methods such as `to_d`, `to_f`, `to_h`, `to_i`, `to_r`, `to_s`, and `to_sym` on variables,
|
16
|
+
# provided that their return value is not an array. For example, when using `to_s`,
|
17
|
+
# `'%s' % [1, 2, 3].to_s` can be autocorrected without any incompatibility:
|
18
|
+
#
|
19
|
+
# [source,ruby]
|
20
|
+
# ----
|
21
|
+
# '%s' % [1, 2, 3] #=> '1'
|
22
|
+
# format('%s', [1, 2, 3]) #=> '[1, 2, 3]'
|
23
|
+
# '%s' % [1, 2, 3].to_s #=> '[1, 2, 3]'
|
24
|
+
# ----
|
25
|
+
#
|
14
26
|
# @example EnforcedStyle: format (default)
|
15
27
|
# # bad
|
16
28
|
# puts sprintf('%10s', 'hoge')
|
@@ -42,6 +54,9 @@ module RuboCop
|
|
42
54
|
MSG = 'Favor `%<prefer>s` over `%<current>s`.'
|
43
55
|
RESTRICT_ON_SEND = %i[format sprintf %].freeze
|
44
56
|
|
57
|
+
# Known conversion methods whose return value is not an array.
|
58
|
+
AUTOCORRECTABLE_METHODS = %i[to_d to_f to_h to_i to_r to_s to_sym].freeze
|
59
|
+
|
45
60
|
# @!method formatter(node)
|
46
61
|
def_node_matcher :formatter, <<~PATTERN
|
47
62
|
{
|
@@ -53,7 +68,7 @@ module RuboCop
|
|
53
68
|
|
54
69
|
# @!method variable_argument?(node)
|
55
70
|
def_node_matcher :variable_argument?, <<~PATTERN
|
56
|
-
(send {str dstr} :%
|
71
|
+
(send {str dstr} :% #autocorrectable?)
|
57
72
|
PATTERN
|
58
73
|
|
59
74
|
def on_send(node)
|
@@ -70,6 +85,12 @@ module RuboCop
|
|
70
85
|
|
71
86
|
private
|
72
87
|
|
88
|
+
def autocorrectable?(node)
|
89
|
+
return true if node.lvar_type?
|
90
|
+
|
91
|
+
node.send_type? && !AUTOCORRECTABLE_METHODS.include?(node.method_name)
|
92
|
+
end
|
93
|
+
|
73
94
|
def message(detected_style)
|
74
95
|
format(MSG, prefer: method_name(style), current: method_name(detected_style))
|
75
96
|
end
|
@@ -55,6 +55,25 @@ module RuboCop
|
|
55
55
|
# foo || raise('exception') if something
|
56
56
|
# ok
|
57
57
|
#
|
58
|
+
# # bad
|
59
|
+
# define_method(:test) do
|
60
|
+
# if something
|
61
|
+
# work
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# # good
|
66
|
+
# define_method(:test) do
|
67
|
+
# return unless something
|
68
|
+
#
|
69
|
+
# work
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# # also good
|
73
|
+
# define_method(:test) do
|
74
|
+
# work if something
|
75
|
+
# end
|
76
|
+
#
|
58
77
|
# @example AllowConsecutiveConditionals: false (default)
|
59
78
|
# # bad
|
60
79
|
# def test
|
@@ -110,6 +129,13 @@ module RuboCop
|
|
110
129
|
end
|
111
130
|
alias on_defs on_def
|
112
131
|
|
132
|
+
def on_block(node)
|
133
|
+
return unless node.method?(:define_method) || node.method?(:define_singleton_method)
|
134
|
+
|
135
|
+
on_def(node)
|
136
|
+
end
|
137
|
+
alias on_numblock on_block
|
138
|
+
|
113
139
|
def on_if(node)
|
114
140
|
return if accepted_form?(node)
|
115
141
|
|
@@ -17,10 +17,16 @@ module RuboCop
|
|
17
17
|
# @example
|
18
18
|
# # bad
|
19
19
|
# hash.keys.each { |k| p k }
|
20
|
-
# hash.
|
20
|
+
# hash.each { |k, unused_value| p k }
|
21
21
|
#
|
22
22
|
# # good
|
23
23
|
# hash.each_key { |k| p k }
|
24
|
+
#
|
25
|
+
# # bad
|
26
|
+
# hash.values.each { |v| p v }
|
27
|
+
# hash.each { |unused_key, v| p v }
|
28
|
+
#
|
29
|
+
# # good
|
24
30
|
# hash.each_value { |v| p v }
|
25
31
|
#
|
26
32
|
# @example AllowedReceivers: ['execute']
|
@@ -33,22 +39,46 @@ module RuboCop
|
|
33
39
|
extend AutoCorrector
|
34
40
|
|
35
41
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
42
|
+
UNUSED_BLOCK_ARG_MSG = "#{MSG.chop} and remove the unused `%<unused_code>s` block argument."
|
36
43
|
|
37
44
|
# @!method kv_each(node)
|
38
45
|
def_node_matcher :kv_each, <<~PATTERN
|
39
|
-
({block numblock} $(
|
46
|
+
({block numblock} $(call (call _ ${:keys :values}) :each) ...)
|
47
|
+
PATTERN
|
48
|
+
|
49
|
+
# @!method each_arguments(node)
|
50
|
+
def_node_matcher :each_arguments, <<~PATTERN
|
51
|
+
(block (call _ :each)(args $_key $_value) ...)
|
40
52
|
PATTERN
|
41
53
|
|
42
54
|
# @!method kv_each_with_block_pass(node)
|
43
55
|
def_node_matcher :kv_each_with_block_pass, <<~PATTERN
|
44
|
-
(
|
56
|
+
(call $(call _ ${:keys :values}) :each (block_pass (sym _)))
|
45
57
|
PATTERN
|
46
58
|
|
59
|
+
# rubocop:disable Metrics/AbcSize
|
47
60
|
def on_block(node)
|
61
|
+
return unless handleable?(node)
|
62
|
+
|
48
63
|
kv_each(node) do |target, method|
|
49
|
-
register_kv_offense(target, method)
|
64
|
+
register_kv_offense(target, method) and return
|
65
|
+
end
|
66
|
+
|
67
|
+
return unless (key, value = each_arguments(node))
|
68
|
+
|
69
|
+
if unused_block_arg_exist?(node, value)
|
70
|
+
message = message('each_key', node.method_name, value.source)
|
71
|
+
unused_range = key.source_range.end.join(value.source_range.end)
|
72
|
+
|
73
|
+
register_each_args_offense(node, message, 'each_key', unused_range)
|
74
|
+
elsif unused_block_arg_exist?(node, key)
|
75
|
+
message = message('each_value', node.method_name, key.source)
|
76
|
+
unused_range = key.source_range.begin.join(value.source_range.begin)
|
77
|
+
|
78
|
+
register_each_args_offense(node, message, 'each_value', unused_range)
|
50
79
|
end
|
51
80
|
end
|
81
|
+
# rubocop:enable Metrics/AbcSize
|
52
82
|
|
53
83
|
alias on_numblock on_block
|
54
84
|
|
@@ -60,27 +90,70 @@ module RuboCop
|
|
60
90
|
|
61
91
|
private
|
62
92
|
|
93
|
+
def handleable?(node)
|
94
|
+
return false unless (root_receiver = root_receiver(node))
|
95
|
+
|
96
|
+
!root_receiver.literal? || root_receiver.hash_type?
|
97
|
+
end
|
98
|
+
|
63
99
|
def register_kv_offense(target, method)
|
64
100
|
return unless (parent_receiver = target.receiver.receiver)
|
65
101
|
return if allowed_receiver?(parent_receiver)
|
66
102
|
|
67
|
-
|
103
|
+
current = target.receiver.loc.selector.join(target.source_range.end).source
|
104
|
+
|
105
|
+
add_offense(kv_range(target), message: format_message(method, current)) do |corrector|
|
68
106
|
correct_key_value_each(target, corrector)
|
69
107
|
end
|
70
108
|
end
|
71
109
|
|
110
|
+
def unused_block_arg_exist?(node, block_arg)
|
111
|
+
lvar_sources = node.body.each_descendant(:lvar).map(&:source)
|
112
|
+
|
113
|
+
if block_arg.mlhs_type?
|
114
|
+
block_arg.each_descendant(:arg, :restarg).all? do |block_arg|
|
115
|
+
lvar_sources.none?(block_arg.source.delete_prefix('*'))
|
116
|
+
end
|
117
|
+
else
|
118
|
+
lvar_sources.none?(block_arg.source.delete_prefix('*'))
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def message(prefer, method_name, unused_code)
|
123
|
+
format(
|
124
|
+
UNUSED_BLOCK_ARG_MSG, prefer: prefer, current: method_name, unused_code: unused_code
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def register_each_args_offense(node, message, prefer, unused_range)
|
129
|
+
add_offense(node, message: message) do |corrector|
|
130
|
+
corrector.replace(node.send_node.loc.selector, prefer)
|
131
|
+
corrector.remove(unused_range)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
72
135
|
def register_kv_with_block_pass_offense(node, target, method)
|
73
136
|
return unless (parent_receiver = node.parent.receiver.receiver)
|
74
137
|
return if allowed_receiver?(parent_receiver)
|
75
138
|
|
76
|
-
range = target.loc.selector.
|
77
|
-
|
139
|
+
range = target.loc.selector.join(node.parent.loc.selector.end)
|
140
|
+
|
141
|
+
add_offense(range, message: format_message(method, range.source)) do |corrector|
|
78
142
|
corrector.replace(range, "each_#{method[0..-2]}")
|
79
143
|
end
|
80
144
|
end
|
81
145
|
|
82
|
-
def
|
83
|
-
|
146
|
+
def root_receiver(node)
|
147
|
+
receiver = node.receiver
|
148
|
+
if receiver&.receiver
|
149
|
+
root_receiver(receiver)
|
150
|
+
else
|
151
|
+
receiver
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def format_message(method_name, current)
|
156
|
+
format(MSG, prefer: "each_#{method_name[0..-2]}", current: current)
|
84
157
|
end
|
85
158
|
|
86
159
|
def check_argument(variable)
|
@@ -103,7 +176,7 @@ module RuboCop
|
|
103
176
|
name = "each_#{node.receiver.method_name.to_s.chop}"
|
104
177
|
return correct_implicit(node, corrector, name) unless receiver
|
105
178
|
|
106
|
-
new_source = receiver.source + "
|
179
|
+
new_source = receiver.source + "#{node.loc.dot.source}#{name}"
|
107
180
|
corrector.replace(node, new_source)
|
108
181
|
end
|
109
182
|
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
# @!method bad_method_with_poro?(node)
|
44
44
|
def_node_matcher :bad_method_with_poro?, <<~PATTERN
|
45
45
|
(block
|
46
|
-
(
|
46
|
+
(call _ _)
|
47
47
|
(args
|
48
48
|
$(arg _)
|
49
49
|
(arg _))
|
@@ -86,6 +86,7 @@ module RuboCop
|
|
86
86
|
corrector.replace(range, preferred_method)
|
87
87
|
end
|
88
88
|
end
|
89
|
+
alias on_csend on_send
|
89
90
|
|
90
91
|
private
|
91
92
|
|
@@ -136,7 +136,7 @@ module RuboCop
|
|
136
136
|
|
137
137
|
private
|
138
138
|
|
139
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
139
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
140
140
|
def check_branches(node, branches)
|
141
141
|
# return if any branch is empty. An empty branch can be an `if`
|
142
142
|
# without an `else` or a branch that contains only comments.
|
@@ -149,9 +149,26 @@ module RuboCop
|
|
149
149
|
branches.any? { |branch| single_child_branch?(branch) }
|
150
150
|
|
151
151
|
heads = branches.map { |branch| head(branch) }
|
152
|
-
|
152
|
+
|
153
|
+
return unless duplicated_expressions?(node, heads)
|
154
|
+
|
155
|
+
condition_variable = assignable_condition_value(node)
|
156
|
+
|
157
|
+
head = heads.first
|
158
|
+
if head.assignment?
|
159
|
+
# The `send` node is used instead of the `indexasgn` node, so `name` cannot be used.
|
160
|
+
# https://github.com/rubocop/rubocop-ast/blob/v1.29.0/lib/rubocop/ast/node/indexasgn_node.rb
|
161
|
+
#
|
162
|
+
# FIXME: It would be better to update `RuboCop::AST::OpAsgnNode` or its subclasses to
|
163
|
+
# handle `self.foo ||= value` as a solution, instead of using `head.node_parts[0].to_s`.
|
164
|
+
assigned_value = head.send_type? ? head.receiver.source : head.node_parts[0].to_s
|
165
|
+
|
166
|
+
return if condition_variable == assigned_value
|
167
|
+
end
|
168
|
+
|
169
|
+
check_expressions(node, heads, :before_condition)
|
153
170
|
end
|
154
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
171
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
155
172
|
|
156
173
|
def duplicated_expressions?(node, expressions)
|
157
174
|
unique_expressions = expressions.uniq
|
@@ -164,6 +181,14 @@ module RuboCop
|
|
164
181
|
node.condition.child_nodes.none? { |n| n.source == lhs.source if n.variable? }
|
165
182
|
end
|
166
183
|
|
184
|
+
def assignable_condition_value(node)
|
185
|
+
if node.condition.call_type?
|
186
|
+
(receiver = node.condition.receiver) ? receiver.source : node.condition.source
|
187
|
+
elsif node.condition.variable?
|
188
|
+
node.condition.source
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
167
192
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
168
193
|
def check_expressions(node, expressions, insert_position)
|
169
194
|
return if expressions.any?(&:nil?)
|