rubocop 1.36.0 → 1.39.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 +31 -3
- data/lib/rubocop/arguments_env.rb +17 -0
- data/lib/rubocop/arguments_file.rb +17 -0
- data/lib/rubocop/cli/command/execute_runner.rb +7 -7
- data/lib/rubocop/cli/command/suggest_extensions.rb +8 -1
- data/lib/rubocop/comment_config.rb +36 -1
- data/lib/rubocop/cop/commissioner.rb +3 -1
- data/lib/rubocop/cop/generator.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/create_empty_file.rb +37 -0
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +111 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
- data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +30 -3
- data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +6 -2
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +28 -9
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
- data/lib/rubocop/cop/lint/empty_class.rb +3 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +20 -8
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
- data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +38 -10
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +0 -10
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +3 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
- data/lib/rubocop/cop/mixin/range_help.rb +23 -0
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +10 -8
- data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
- data/lib/rubocop/cop/registry.rb +10 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +5 -7
- data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +2 -2
- data/lib/rubocop/cop/style/character_literal.rb +1 -1
- data/lib/rubocop/cop/style/class_equality_comparison.rb +8 -6
- data/lib/rubocop/cop/style/collection_compact.rb +12 -3
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +62 -21
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
- data/lib/rubocop/cop/style/hash_except.rb +4 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +25 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
- data/lib/rubocop/cop/style/module_function.rb +28 -6
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +3 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +53 -0
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
- data/lib/rubocop/cop/style/redundant_each.rb +116 -0
- data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
- data/lib/rubocop/cop/style/redundant_string_escape.rb +181 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/static_class.rb +32 -1
- data/lib/rubocop/cop/style/symbol_array.rb +2 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +2 -0
- data/lib/rubocop/cop/team.rb +3 -4
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +2 -1
- data/lib/rubocop/ext/processed_source.rb +2 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
- data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
- data/lib/rubocop/options.rb +19 -15
- data/lib/rubocop/rspec/cop_helper.rb +21 -1
- data/lib/rubocop/rspec/shared_contexts.rb +14 -1
- data/lib/rubocop/runner.rb +15 -11
- data/lib/rubocop/server/cache.rb +5 -1
- data/lib/rubocop/server/cli.rb +9 -2
- data/lib/rubocop/server/client_command/exec.rb +5 -0
- data/lib/rubocop/server/core.rb +18 -1
- data/lib/rubocop/server/socket_reader.rb +5 -1
- data/lib/rubocop/server.rb +1 -1
- data/lib/rubocop/version.rb +8 -3
- data/lib/rubocop.rb +4 -0
- metadata +13 -5
@@ -10,6 +10,9 @@ module RuboCop
|
|
10
10
|
# one of `return`, `break`, `next`, `raise`, or `fail` is used
|
11
11
|
# in the body of the conditional expression.
|
12
12
|
#
|
13
|
+
# NOTE: Autocorrect works in most cases except with if-else statements
|
14
|
+
# that contain logical operators such as `foo || raise('exception')`
|
15
|
+
#
|
13
16
|
# @example
|
14
17
|
# # bad
|
15
18
|
# def test
|
@@ -90,6 +93,7 @@ module RuboCop
|
|
90
93
|
# end
|
91
94
|
#
|
92
95
|
class GuardClause < Base
|
96
|
+
extend AutoCorrector
|
93
97
|
include MinBodyLength
|
94
98
|
include StatementModifier
|
95
99
|
|
@@ -101,40 +105,49 @@ module RuboCop
|
|
101
105
|
|
102
106
|
return unless body
|
103
107
|
|
104
|
-
|
105
|
-
check_ending_if(body)
|
106
|
-
elsif body.begin_type?
|
107
|
-
final_expression = body.children.last
|
108
|
-
check_ending_if(final_expression) if final_expression&.if_type?
|
109
|
-
end
|
108
|
+
check_ending_body(body)
|
110
109
|
end
|
111
110
|
alias on_defs on_def
|
112
111
|
|
113
112
|
def on_if(node)
|
114
113
|
return if accepted_form?(node)
|
115
114
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
115
|
+
if (guard_clause = node.if_branch&.guard_clause?)
|
116
|
+
kw = node.loc.keyword.source
|
117
|
+
guard = :if
|
118
|
+
elsif (guard_clause = node.else_branch&.guard_clause?)
|
119
|
+
kw = node.inverse_keyword
|
120
|
+
guard = :else
|
121
|
+
else
|
122
|
+
return
|
123
|
+
end
|
120
124
|
|
121
|
-
|
122
|
-
node.loc.keyword.source
|
123
|
-
else
|
124
|
-
node.inverse_keyword
|
125
|
-
end
|
125
|
+
guard = nil if and_or_guard_clause?(guard_clause)
|
126
126
|
|
127
|
-
register_offense(node, guard_clause_source(guard_clause), kw)
|
127
|
+
register_offense(node, guard_clause_source(guard_clause), kw, guard)
|
128
128
|
end
|
129
129
|
|
130
130
|
private
|
131
131
|
|
132
|
+
def check_ending_body(body)
|
133
|
+
return if body.nil?
|
134
|
+
|
135
|
+
if body.if_type?
|
136
|
+
check_ending_if(body)
|
137
|
+
elsif body.begin_type?
|
138
|
+
final_expression = body.children.last
|
139
|
+
check_ending_if(final_expression) if final_expression&.if_type?
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
132
143
|
def check_ending_if(node)
|
133
144
|
return if accepted_form?(node, ending: true) || !min_body_length?(node)
|
134
145
|
return if allowed_consecutive_conditionals? &&
|
135
146
|
consecutive_conditionals?(node.parent, node)
|
136
147
|
|
137
148
|
register_offense(node, 'return', node.inverse_keyword)
|
149
|
+
|
150
|
+
check_ending_body(node.if_branch)
|
138
151
|
end
|
139
152
|
|
140
153
|
def consecutive_conditionals?(parent, node)
|
@@ -145,28 +158,56 @@ module RuboCop
|
|
145
158
|
end
|
146
159
|
end
|
147
160
|
|
148
|
-
def register_offense(node, scope_exiting_keyword, conditional_keyword)
|
161
|
+
def register_offense(node, scope_exiting_keyword, conditional_keyword, guard = nil)
|
149
162
|
condition, = node.node_parts
|
150
163
|
example = [scope_exiting_keyword, conditional_keyword, condition.source].join(' ')
|
151
164
|
if too_long_for_single_line?(node, example)
|
152
165
|
return if trivial?(node)
|
153
166
|
|
154
167
|
example = "#{conditional_keyword} #{condition.source}; #{scope_exiting_keyword}; end"
|
168
|
+
replacement = <<~RUBY.chomp
|
169
|
+
#{conditional_keyword} #{condition.source}
|
170
|
+
#{scope_exiting_keyword}
|
171
|
+
end
|
172
|
+
RUBY
|
155
173
|
end
|
156
174
|
|
157
|
-
add_offense(node.loc.keyword, message: format(MSG, example: example))
|
175
|
+
add_offense(node.loc.keyword, message: format(MSG, example: example)) do |corrector|
|
176
|
+
next if node.else? && guard.nil?
|
177
|
+
|
178
|
+
autocorrect(corrector, node, condition, replacement || example, guard)
|
179
|
+
end
|
158
180
|
end
|
159
181
|
|
160
|
-
def
|
161
|
-
|
182
|
+
def autocorrect(corrector, node, condition, replacement, guard)
|
183
|
+
corrector.replace(node.loc.keyword.join(condition.loc.expression), replacement)
|
184
|
+
corrector.remove(node.loc.end)
|
185
|
+
return unless node.else?
|
186
|
+
|
187
|
+
corrector.remove(node.loc.else)
|
188
|
+
corrector.remove(branch_to_remove(node, guard))
|
189
|
+
end
|
190
|
+
|
191
|
+
def branch_to_remove(node, guard)
|
192
|
+
case guard
|
193
|
+
when :if then node.if_branch
|
194
|
+
when :else then node.else_branch
|
195
|
+
end
|
196
|
+
end
|
162
197
|
|
163
|
-
|
198
|
+
def guard_clause_source(guard_clause)
|
199
|
+
if and_or_guard_clause?(guard_clause)
|
164
200
|
guard_clause.parent.source
|
165
201
|
else
|
166
202
|
guard_clause.source
|
167
203
|
end
|
168
204
|
end
|
169
205
|
|
206
|
+
def and_or_guard_clause?(guard_clause)
|
207
|
+
parent = guard_clause.parent
|
208
|
+
parent.and_type? || parent.or_type?
|
209
|
+
end
|
210
|
+
|
170
211
|
def too_long_for_single_line?(node, example)
|
171
212
|
max = max_line_length
|
172
213
|
max && node.source_range.column + example.length > max
|
@@ -38,28 +38,50 @@ module RuboCop
|
|
38
38
|
({block numblock} $(send (send _ ${:keys :values}) :each) ...)
|
39
39
|
PATTERN
|
40
40
|
|
41
|
+
# @!method kv_each_with_block_pass(node)
|
42
|
+
def_node_matcher :kv_each_with_block_pass, <<~PATTERN
|
43
|
+
(send $(send _ ${:keys :values}) :each (block_pass (sym _)))
|
44
|
+
PATTERN
|
45
|
+
|
41
46
|
def on_block(node)
|
42
|
-
|
47
|
+
kv_each(node) do |target, method|
|
48
|
+
register_kv_offense(target, method)
|
49
|
+
end
|
43
50
|
end
|
44
51
|
|
45
52
|
alias on_numblock on_block
|
46
53
|
|
54
|
+
def on_block_pass(node)
|
55
|
+
kv_each_with_block_pass(node.parent) do |target, method|
|
56
|
+
register_kv_with_block_pass_offense(node, target, method)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
47
60
|
private
|
48
61
|
|
49
|
-
def register_kv_offense(
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
62
|
+
def register_kv_offense(target, method)
|
63
|
+
return unless (parent_receiver = target.receiver.receiver)
|
64
|
+
return if allowed_receiver?(parent_receiver)
|
65
|
+
|
66
|
+
add_offense(kv_range(target), message: format_message(method)) do |corrector|
|
67
|
+
correct_key_value_each(target, corrector)
|
68
|
+
end
|
69
|
+
end
|
54
70
|
|
55
|
-
|
71
|
+
def register_kv_with_block_pass_offense(node, target, method)
|
72
|
+
return unless (parent_receiver = node.parent.receiver.receiver)
|
73
|
+
return if allowed_receiver?(parent_receiver)
|
56
74
|
|
57
|
-
|
58
|
-
|
59
|
-
|
75
|
+
range = target.loc.selector.with(end_pos: node.parent.loc.selector.end_pos)
|
76
|
+
add_offense(range, message: format_message(method)) do |corrector|
|
77
|
+
corrector.replace(range, "each_#{method[0..-2]}")
|
60
78
|
end
|
61
79
|
end
|
62
80
|
|
81
|
+
def format_message(method_name)
|
82
|
+
format(MSG, prefer: "each_#{method_name[0..-2]}", current: "#{method_name}.each")
|
83
|
+
end
|
84
|
+
|
63
85
|
def check_argument(variable)
|
64
86
|
return unless variable.block_argument?
|
65
87
|
|
@@ -13,6 +13,10 @@ module RuboCop
|
|
13
13
|
# when used `==`.
|
14
14
|
# And do not check `Hash#delete_if` and `Hash#keep_if` to change receiver object.
|
15
15
|
#
|
16
|
+
# @safety
|
17
|
+
# This cop is unsafe because it cannot be guaranteed that the receiver
|
18
|
+
# is a `Hash` or responds to the replacement method.
|
19
|
+
#
|
16
20
|
# @example
|
17
21
|
#
|
18
22
|
# # bad
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
# * always - forces use of the 3.1 syntax (e.g. {foo:})
|
29
29
|
# * never - forces use of explicit hash literal value
|
30
30
|
# * either - accepts both shorthand and explicit use of hash literal value
|
31
|
-
# * consistent - like "
|
31
|
+
# * consistent - like "either", but will avoid mixing styles in a single hash
|
32
32
|
#
|
33
33
|
# @example EnforcedStyle: ruby19 (default)
|
34
34
|
# # bad
|
@@ -5,10 +5,27 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# Checks for redundant `if` with boolean literal branches.
|
7
7
|
# It checks only conditions to return boolean value (`true` or `false`) for safe detection.
|
8
|
-
# The conditions to be checked are comparison methods, predicate methods, and
|
8
|
+
# The conditions to be checked are comparison methods, predicate methods, and
|
9
|
+
# double negation (!!).
|
9
10
|
# `nonzero?` method is allowed by default.
|
10
11
|
# These are customizable with `AllowedMethods` option.
|
11
12
|
#
|
13
|
+
# This cop targets only `if`s with a single `elsif` or `else` branch. The following
|
14
|
+
# code will be allowed, because it has two `elsif` branches:
|
15
|
+
#
|
16
|
+
# [source,ruby]
|
17
|
+
# ----
|
18
|
+
# if foo
|
19
|
+
# true
|
20
|
+
# elsif bar > baz
|
21
|
+
# true
|
22
|
+
# elsif qux > quux # Single `elsif` is warned, but two or more `elsif`s are not.
|
23
|
+
# true
|
24
|
+
# else
|
25
|
+
# false
|
26
|
+
# end
|
27
|
+
# ----
|
28
|
+
#
|
12
29
|
# @safety
|
13
30
|
# Autocorrection is unsafe because there is no guarantee that all predicate methods
|
14
31
|
# will return a boolean value. Those methods can be allowed with `AllowedMethods` config.
|
@@ -57,7 +74,7 @@ module RuboCop
|
|
57
74
|
def_node_matcher :double_negative?, '(send (send _ :!) :!)'
|
58
75
|
|
59
76
|
def on_if(node)
|
60
|
-
return
|
77
|
+
return if !if_with_boolean_literal_branches?(node) || multiple_elsif?(node)
|
61
78
|
|
62
79
|
condition = node.condition
|
63
80
|
range, keyword = offense_range_with_keyword(node, condition)
|
@@ -76,6 +93,12 @@ module RuboCop
|
|
76
93
|
|
77
94
|
private
|
78
95
|
|
96
|
+
def multiple_elsif?(node)
|
97
|
+
return false unless (parent = node.parent)
|
98
|
+
|
99
|
+
parent.if_type? && parent.elsif?
|
100
|
+
end
|
101
|
+
|
79
102
|
def offense_range_with_keyword(node, condition)
|
80
103
|
if node.ternary?
|
81
104
|
range = condition.source_range.end.join(node.source_range.end)
|
@@ -20,8 +20,8 @@ module RuboCop
|
|
20
20
|
return if require_parentheses_for_hash_value_omission?(node)
|
21
21
|
return if syntax_like_method_call?(node)
|
22
22
|
return if super_call_without_arguments?(node)
|
23
|
-
return if allowed_camel_case_method_call?(node)
|
24
23
|
return if legitimate_call_with_parentheses?(node)
|
24
|
+
return if allowed_camel_case_method_call?(node)
|
25
25
|
return if allowed_string_interpolation_method_call?(node)
|
26
26
|
|
27
27
|
add_offense(offense_range(node), message: OMIT_MSG) do |corrector|
|
@@ -97,7 +97,8 @@ module RuboCop
|
|
97
97
|
call_in_optional_arguments?(node) ||
|
98
98
|
call_in_single_line_inheritance?(node) ||
|
99
99
|
allowed_multiline_call_with_parentheses?(node) ||
|
100
|
-
allowed_chained_call_with_parentheses?(node)
|
100
|
+
allowed_chained_call_with_parentheses?(node) ||
|
101
|
+
assignment_in_condition?(node)
|
101
102
|
end
|
102
103
|
|
103
104
|
def call_in_literals?(node)
|
@@ -202,6 +203,16 @@ module RuboCop
|
|
202
203
|
def inside_string_interpolation?(node)
|
203
204
|
node.ancestors.drop_while { |a| !a.begin_type? }.any?(&:dstr_type?)
|
204
205
|
end
|
206
|
+
|
207
|
+
def assignment_in_condition?(node)
|
208
|
+
parent = node.parent
|
209
|
+
return false unless parent
|
210
|
+
|
211
|
+
grandparent = parent.parent
|
212
|
+
return false unless grandparent
|
213
|
+
|
214
|
+
parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
|
215
|
+
end
|
205
216
|
end
|
206
217
|
# rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
|
207
218
|
end
|
@@ -3,13 +3,15 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks for use of `extend self` or `module_function` in a
|
7
|
-
# module.
|
6
|
+
# Checks for use of `extend self` or `module_function` in a module.
|
8
7
|
#
|
9
|
-
# Supported styles are: module_function, extend_self
|
10
|
-
# style prohibits the usage of both styles.
|
8
|
+
# Supported styles are: `module_function` (default), `extend_self` and `forbidden`.
|
11
9
|
#
|
12
|
-
#
|
10
|
+
# A couple of things to keep in mind:
|
11
|
+
#
|
12
|
+
# - `forbidden` style prohibits the usage of both styles
|
13
|
+
# - in default mode (`module_function`), the cop won't be activated when the module
|
14
|
+
# contains any private methods
|
13
15
|
#
|
14
16
|
# @safety
|
15
17
|
# Autocorrection is unsafe (and is disabled by default) because `extend self`
|
@@ -28,7 +30,6 @@ module RuboCop
|
|
28
30
|
# # ...
|
29
31
|
# end
|
30
32
|
#
|
31
|
-
# @example EnforcedStyle: module_function (default)
|
32
33
|
# # good
|
33
34
|
# module Test
|
34
35
|
# extend self
|
@@ -37,6 +38,13 @@ module RuboCop
|
|
37
38
|
# # ...
|
38
39
|
# end
|
39
40
|
#
|
41
|
+
# # good
|
42
|
+
# module Test
|
43
|
+
# class << self
|
44
|
+
# # ...
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
40
48
|
# @example EnforcedStyle: extend_self
|
41
49
|
# # bad
|
42
50
|
# module Test
|
@@ -50,6 +58,13 @@ module RuboCop
|
|
50
58
|
# # ...
|
51
59
|
# end
|
52
60
|
#
|
61
|
+
# # good
|
62
|
+
# module Test
|
63
|
+
# class << self
|
64
|
+
# # ...
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
#
|
53
68
|
# @example EnforcedStyle: forbidden
|
54
69
|
# # bad
|
55
70
|
# module Test
|
@@ -70,6 +85,13 @@ module RuboCop
|
|
70
85
|
# private
|
71
86
|
# # ...
|
72
87
|
# end
|
88
|
+
#
|
89
|
+
# # good
|
90
|
+
# module Test
|
91
|
+
# class << self
|
92
|
+
# # ...
|
93
|
+
# end
|
94
|
+
# end
|
73
95
|
class ModuleFunction < Base
|
74
96
|
include ConfigurableEnforcedStyle
|
75
97
|
extend AutoCorrector
|
@@ -49,7 +49,8 @@ module RuboCop
|
|
49
49
|
def on_if(node)
|
50
50
|
return unless if_else?(node)
|
51
51
|
|
52
|
-
condition = node.condition
|
52
|
+
condition = unwrap_begin_nodes(node.condition)
|
53
|
+
|
53
54
|
return if double_negation?(condition) || !negated_condition?(condition)
|
54
55
|
|
55
56
|
type = node.ternary? ? 'ternary' : 'if-else'
|
@@ -71,6 +72,11 @@ module RuboCop
|
|
71
72
|
!node.elsif? && else_branch && (!else_branch.if_type? || !else_branch.elsif?)
|
72
73
|
end
|
73
74
|
|
75
|
+
def unwrap_begin_nodes(node)
|
76
|
+
node = node.children.first while node.begin_type? || node.kwbegin_type?
|
77
|
+
node
|
78
|
+
end
|
79
|
+
|
74
80
|
def negated_condition?(node)
|
75
81
|
node.send_type? &&
|
76
82
|
(node.negation_method? || NEGATED_EQUALITY_METHODS.include?(node.method_name))
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for redundant dot before operator method call.
|
7
|
+
# The target operator methods are `|`, `^`, `&`, `<=>`, `==`, `===`, `=~`, `>`, `>=`, `<`,
|
8
|
+
# `<=`, `<<`, `>>`, `+`, `-`, `*`, `/`, `%`, `**`, `~`, `!`, `!=`, and `!~`.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# foo.+ bar
|
14
|
+
# foo.& bar
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# foo + bar
|
18
|
+
# foo & bar
|
19
|
+
#
|
20
|
+
class OperatorMethodCall < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
23
|
+
MSG = 'Redundant dot detected.'
|
24
|
+
RESTRICT_ON_SEND = %i[| ^ & <=> == === =~ > >= < <= << >> + - * / % ** ~ ! != !~].freeze
|
25
|
+
|
26
|
+
def on_send(node)
|
27
|
+
return unless (dot = node.loc.dot)
|
28
|
+
return if node.receiver.const_type?
|
29
|
+
|
30
|
+
_lhs, _op, rhs = *node
|
31
|
+
return if rhs.nil? || rhs.children.first
|
32
|
+
|
33
|
+
add_offense(dot) do |corrector|
|
34
|
+
wrap_in_parentheses_if_chained(corrector, node)
|
35
|
+
corrector.replace(dot, ' ')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def wrap_in_parentheses_if_chained(corrector, node)
|
42
|
+
return unless node.parent&.call_type?
|
43
|
+
|
44
|
+
operator = node.loc.selector
|
45
|
+
|
46
|
+
ParenthesesCorrector.correct(corrector, node)
|
47
|
+
corrector.insert_after(operator, ' ')
|
48
|
+
corrector.wrap(node, '(', ')')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -145,11 +145,14 @@ module RuboCop
|
|
145
145
|
|
146
146
|
return false unless if_branch && else_branch
|
147
147
|
|
148
|
-
if_branch
|
149
|
-
else_branch.send_type? && else_branch.arguments.count == 1 &&
|
148
|
+
single_argument_method?(if_branch) && single_argument_method?(else_branch) &&
|
150
149
|
same_method?(if_branch, else_branch)
|
151
150
|
end
|
152
151
|
|
152
|
+
def single_argument_method?(node)
|
153
|
+
node.send_type? && !node.method?(:[]) && node.arguments.one?
|
154
|
+
end
|
155
|
+
|
153
156
|
def same_method?(if_branch, else_branch)
|
154
157
|
if_branch.method?(else_branch.method_name) && if_branch.receiver == else_branch.receiver
|
155
158
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for redundant `each`.
|
7
|
+
#
|
8
|
+
# @safety
|
9
|
+
# This cop is unsafe, as it can produce false positives if the receiver
|
10
|
+
# is not an `Enumerator`.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# array.each.each { |v| do_something(v) }
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# array.each { |v| do_something(v) }
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# array.each.each_with_index { |v, i| do_something(v, i) }
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# array.each.with_index { |v, i| do_something(v, i) }
|
25
|
+
# array.each_with_index { |v, i| do_something(v, i) }
|
26
|
+
#
|
27
|
+
# # bad
|
28
|
+
# array.each.each_with_object { |v, o| do_something(v, o) }
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# array.each.with_object { |v, o| do_something(v, o) }
|
32
|
+
# array.each_with_object { |v, o| do_something(v, o) }
|
33
|
+
#
|
34
|
+
class RedundantEach < Base
|
35
|
+
extend AutoCorrector
|
36
|
+
|
37
|
+
MSG = 'Remove redundant `each`.'
|
38
|
+
MSG_WITH_INDEX = 'Use `with_index` to remove redundant `each`.'
|
39
|
+
MSG_WITH_OBJECT = 'Use `with_object` to remove redundant `each`.'
|
40
|
+
|
41
|
+
RESTRICT_ON_SEND = %i[each each_with_index each_with_object].freeze
|
42
|
+
|
43
|
+
def on_send(node)
|
44
|
+
return unless (redundant_node = redundant_each_method(node))
|
45
|
+
|
46
|
+
range = range(node)
|
47
|
+
|
48
|
+
add_offense(range, message: message(node)) do |corrector|
|
49
|
+
case node.method_name
|
50
|
+
when :each
|
51
|
+
remove_redundant_each(corrector, range, redundant_node)
|
52
|
+
when :each_with_index
|
53
|
+
corrector.replace(node.loc.selector, 'with_index')
|
54
|
+
when :each_with_object
|
55
|
+
corrector.replace(node.loc.selector, 'with_object')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
63
|
+
def redundant_each_method(node)
|
64
|
+
return if node.last_argument&.block_pass_type?
|
65
|
+
|
66
|
+
if node.method?(:each) && !node.parent&.block_type?
|
67
|
+
ancestor_node = node.each_ancestor(:send).detect do |ancestor|
|
68
|
+
ancestor.receiver == node &&
|
69
|
+
(RESTRICT_ON_SEND.include?(ancestor.method_name) || ancestor.method?(:reverse_each))
|
70
|
+
end
|
71
|
+
|
72
|
+
return ancestor_node if ancestor_node
|
73
|
+
end
|
74
|
+
|
75
|
+
return unless (prev_method = node.children.first)
|
76
|
+
return if !prev_method.send_type? ||
|
77
|
+
prev_method.parent.block_type? || prev_method.last_argument&.block_pass_type?
|
78
|
+
|
79
|
+
detected = prev_method.method_name.to_s.start_with?('each_') unless node.method?(:each)
|
80
|
+
|
81
|
+
prev_method if detected || prev_method.method?(:reverse_each)
|
82
|
+
end
|
83
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
84
|
+
|
85
|
+
def range(node)
|
86
|
+
if node.method?(:each)
|
87
|
+
node.loc.dot.join(node.loc.selector)
|
88
|
+
else
|
89
|
+
node.loc.selector
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def message(node)
|
94
|
+
case node.method_name
|
95
|
+
when :each
|
96
|
+
MSG
|
97
|
+
when :each_with_index
|
98
|
+
MSG_WITH_INDEX
|
99
|
+
when :each_with_object
|
100
|
+
MSG_WITH_OBJECT
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def remove_redundant_each(corrector, range, redundant_node)
|
105
|
+
corrector.remove(range)
|
106
|
+
|
107
|
+
if redundant_node.method?(:each_with_index)
|
108
|
+
corrector.replace(redundant_node.loc.selector, 'each.with_index')
|
109
|
+
elsif redundant_node.method?(:each_with_object)
|
110
|
+
corrector.replace(redundant_node.loc.selector, 'each.with_object')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -140,7 +140,9 @@ module RuboCop
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def allow_comments?(node)
|
143
|
-
cop_config['AllowComments']
|
143
|
+
return false unless cop_config['AllowComments']
|
144
|
+
|
145
|
+
contains_comments?(node) && !comments_contain_disables?(node, name)
|
144
146
|
end
|
145
147
|
|
146
148
|
def same_args?(super_node, args)
|