rubocop 1.39.0 → 1.44.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 +2 -2
- data/config/default.yml +149 -11
- data/exe/rubocop +1 -1
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/comment_config.rb +5 -0
- data/lib/rubocop/config.rb +39 -15
- data/lib/rubocop/config_loader.rb +26 -20
- data/lib/rubocop/config_loader_resolver.rb +6 -2
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/badge.rb +9 -4
- data/lib/rubocop/cop/base.rb +84 -74
- data/lib/rubocop/cop/commissioner.rb +8 -3
- data/lib/rubocop/cop/cop.rb +29 -29
- data/lib/rubocop/cop/corrector.rb +30 -10
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
- data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
- data/lib/rubocop/cop/layout/class_structure.rb +32 -11
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
- 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/heredoc_indentation.rb +6 -9
- 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/space_inside_array_literal_brackets.rb +0 -2
- 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/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
- data/lib/rubocop/cop/lint/debugger.rb +3 -1
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
- data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -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/else_layout.rb +2 -6
- data/lib/rubocop/cop/lint/empty_block.rb +1 -5
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -7
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
- data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- 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/parentheses_as_grouped_expression.rb +5 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +15 -3
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -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 +10 -12
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
- data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
- data/lib/rubocop/cop/lint/useless_rescue.rb +85 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +14 -4
- data/lib/rubocop/cop/lint/void.rb +25 -16
- data/lib/rubocop/cop/metrics/block_length.rb +9 -4
- data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +10 -5
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +9 -4
- data/lib/rubocop/cop/metrics/module_length.rb +10 -5
- 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 +3 -6
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
- data/lib/rubocop/cop/mixin/alignment.rb +2 -2
- 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 +59 -6
- data/lib/rubocop/cop/mixin/line_length_help.rb +11 -2
- 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 +16 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +5 -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 +63 -43
- data/lib/rubocop/cop/security/compound_hash.rb +2 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +18 -10
- data/lib/rubocop/cop/style/alias.rb +9 -1
- data/lib/rubocop/cop/style/array_intersect.rb +111 -0
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +2 -9
- data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
- data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
- data/lib/rubocop/cop/style/documentation.rb +11 -5
- data/lib/rubocop/cop/style/guard_clause.rb +44 -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 +4 -4
- data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
- data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -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 +23 -14
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
- data/lib/rubocop/cop/style/min_max_comparison.rb +83 -0
- data/lib/rubocop/cop/style/missing_else.rb +13 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
- data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
- data/lib/rubocop/cop/style/operator_method_call.rb +15 -1
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
- data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
- data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +45 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/redundant_return.rb +7 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
- data/lib/rubocop/cop/style/require_order.rb +135 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
- data/lib/rubocop/cop/style/select_by_regexp.rb +13 -5
- data/lib/rubocop/cop/style/self_assignment.rb +2 -2
- data/lib/rubocop/cop/style/semicolon.rb +26 -3
- 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/string_literals.rb +1 -5
- data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
- 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 +30 -30
- data/lib/rubocop/cop/util.rb +32 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
- data/lib/rubocop/cop/variable_force.rb +18 -30
- 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/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +4 -1
- data/lib/rubocop/options.rb +8 -0
- data/lib/rubocop/path_util.rb +50 -22
- data/lib/rubocop/result_cache.rb +2 -2
- data/lib/rubocop/rspec/cop_helper.rb +4 -1
- data/lib/rubocop/rspec/expect_offense.rb +6 -4
- data/lib/rubocop/rspec/support.rb +2 -2
- data/lib/rubocop/runner.rb +10 -3
- data/lib/rubocop/server/cache.rb +3 -1
- data/lib/rubocop/server/core.rb +1 -1
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +1 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +23 -6
- metadata +23 -9
@@ -50,6 +50,11 @@ module RuboCop
|
|
50
50
|
# foo && foo.bar { |e| e.something }
|
51
51
|
# foo && foo.bar(param) { |e| e.something }
|
52
52
|
#
|
53
|
+
# foo ? foo.bar : nil
|
54
|
+
# foo.nil? ? nil : foo.bar
|
55
|
+
# !foo.nil? ? foo.bar : nil
|
56
|
+
# !foo ? nil : foo.bar
|
57
|
+
#
|
53
58
|
# # good
|
54
59
|
# foo&.bar
|
55
60
|
# foo&.bar&.baz
|
@@ -105,6 +110,17 @@ module RuboCop
|
|
105
110
|
}
|
106
111
|
PATTERN
|
107
112
|
|
113
|
+
# @!method ternary_safe_navigation_candidate(node)
|
114
|
+
def_node_matcher :ternary_safe_navigation_candidate, <<~PATTERN
|
115
|
+
{
|
116
|
+
(if (send $_ {:nil? :!}) nil $_)
|
117
|
+
|
118
|
+
(if (send (send $_ :nil?) :!) $_ nil)
|
119
|
+
|
120
|
+
(if $_ $_ nil)
|
121
|
+
}
|
122
|
+
PATTERN
|
123
|
+
|
108
124
|
# @!method not_nil_check?(node)
|
109
125
|
def_node_matcher :not_nil_check?, '(send (send $_ :nil?) :!)'
|
110
126
|
|
@@ -118,9 +134,11 @@ module RuboCop
|
|
118
134
|
check_node(node)
|
119
135
|
end
|
120
136
|
|
137
|
+
private
|
138
|
+
|
121
139
|
def check_node(node)
|
122
140
|
checked_variable, receiver, method_chain, method = extract_parts(node)
|
123
|
-
return
|
141
|
+
return if receiver != checked_variable || receiver.nil?
|
124
142
|
return if use_var_only_in_unless_modifier?(node, checked_variable)
|
125
143
|
return if chain_length(method_chain, method) > max_chain_length
|
126
144
|
return if unsafe_method_used?(method_chain, method)
|
@@ -133,10 +151,8 @@ module RuboCop
|
|
133
151
|
node.if_type? && node.unless? && !method_called?(variable)
|
134
152
|
end
|
135
153
|
|
136
|
-
private
|
137
|
-
|
138
154
|
def autocorrect(corrector, node)
|
139
|
-
body = node
|
155
|
+
body = extract_body(node)
|
140
156
|
method_call = method_call(node)
|
141
157
|
|
142
158
|
corrector.remove(begin_range(node, body))
|
@@ -147,6 +163,14 @@ module RuboCop
|
|
147
163
|
add_safe_nav_to_all_methods_in_chain(corrector, method_call, body)
|
148
164
|
end
|
149
165
|
|
166
|
+
def extract_body(node)
|
167
|
+
if node.if_type? && node.ternary?
|
168
|
+
node.branches.find { |branch| !branch.nil_type? }
|
169
|
+
else
|
170
|
+
node.node_parts[1]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
150
174
|
def handle_comments(corrector, node, method_call)
|
151
175
|
comments = comments(node)
|
152
176
|
return if comments.empty?
|
@@ -174,7 +198,7 @@ module RuboCop
|
|
174
198
|
end
|
175
199
|
|
176
200
|
def allowed_if_condition?(node)
|
177
|
-
node.else? || node.elsif?
|
201
|
+
node.else? || node.elsif?
|
178
202
|
end
|
179
203
|
|
180
204
|
def method_call(node)
|
@@ -192,7 +216,12 @@ module RuboCop
|
|
192
216
|
end
|
193
217
|
|
194
218
|
def extract_parts_from_if(node)
|
195
|
-
variable, receiver =
|
219
|
+
variable, receiver =
|
220
|
+
if node.ternary?
|
221
|
+
ternary_safe_navigation_candidate(node)
|
222
|
+
else
|
223
|
+
modifier_if_safe_navigation_candidate(node)
|
224
|
+
end
|
196
225
|
|
197
226
|
checked_variable, matching_receiver, method = extract_common_parts(receiver, variable)
|
198
227
|
|
@@ -49,7 +49,8 @@ module RuboCop
|
|
49
49
|
MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
|
50
50
|
RESTRICT_ON_SEND = %i[select find_all reject].freeze
|
51
51
|
REPLACEMENTS = { select: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
|
52
|
-
|
52
|
+
OPPOSITE_REPLACEMENTS = { select: 'grep_v', find_all: 'grep_v', reject: 'grep' }.freeze
|
53
|
+
REGEXP_METHODS = %i[match? =~ !~].to_set.freeze
|
53
54
|
|
54
55
|
# @!method regexp_match?(node)
|
55
56
|
def_node_matcher :regexp_match?, <<~PATTERN
|
@@ -85,13 +86,15 @@ module RuboCop
|
|
85
86
|
|
86
87
|
def on_send(node)
|
87
88
|
return unless (block_node = node.block_node)
|
88
|
-
return if block_node.body
|
89
|
+
return if block_node.body&.begin_type?
|
89
90
|
return if receiver_allowed?(block_node.receiver)
|
90
91
|
return unless (regexp_method_send_node = extract_send_node(block_node))
|
91
92
|
return if match_predicate_without_receiver?(regexp_method_send_node)
|
92
93
|
|
94
|
+
opposite = opposite?(regexp_method_send_node)
|
93
95
|
regexp = find_regexp(regexp_method_send_node, block_node)
|
94
|
-
|
96
|
+
|
97
|
+
register_offense(node, block_node, regexp, opposite)
|
95
98
|
end
|
96
99
|
|
97
100
|
private
|
@@ -102,8 +105,9 @@ module RuboCop
|
|
102
105
|
node.hash_type? || creates_hash?(node) || env_const?(node)
|
103
106
|
end
|
104
107
|
|
105
|
-
def register_offense(node, block_node, regexp)
|
106
|
-
|
108
|
+
def register_offense(node, block_node, regexp, opposite)
|
109
|
+
method_name = node.method_name.to_sym
|
110
|
+
replacement = opposite ? OPPOSITE_REPLACEMENTS[method_name] : REPLACEMENTS[method_name]
|
107
111
|
message = format(MSG, replacement: replacement, original_method: node.method_name)
|
108
112
|
|
109
113
|
add_offense(block_node, message: message) do |corrector|
|
@@ -124,6 +128,10 @@ module RuboCop
|
|
124
128
|
regexp_method_send_node
|
125
129
|
end
|
126
130
|
|
131
|
+
def opposite?(regexp_method_send_node)
|
132
|
+
regexp_method_send_node.send_type? && regexp_method_send_node.method?(:!~)
|
133
|
+
end
|
134
|
+
|
127
135
|
def find_regexp(node, block)
|
128
136
|
return node.child_nodes.first if node.match_with_lvasgn_type?
|
129
137
|
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
|
43
43
|
if rhs.send_type?
|
44
44
|
check_send_node(node, rhs, var_name, var_type)
|
45
|
-
elsif
|
45
|
+
elsif rhs.operator_keyword?
|
46
46
|
check_boolean_node(node, rhs, var_name, var_type)
|
47
47
|
end
|
48
48
|
end
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
|
77
77
|
if rhs.send_type?
|
78
78
|
autocorrect_send_node(corrector, node, rhs)
|
79
|
-
elsif
|
79
|
+
elsif rhs.operator_keyword?
|
80
80
|
autocorrect_boolean_node(corrector, node, rhs)
|
81
81
|
end
|
82
82
|
end
|
@@ -37,13 +37,14 @@ module RuboCop
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def on_new_investigation
|
40
|
-
return if processed_source.blank?
|
40
|
+
return if processed_source.blank? || !processed_source.raw_source.include?(';')
|
41
41
|
|
42
42
|
check_for_line_terminator_or_opener
|
43
43
|
end
|
44
44
|
|
45
45
|
def on_begin(node)
|
46
46
|
return if cop_config['AllowAsExpressionSeparator']
|
47
|
+
return unless node.source.include?(';')
|
47
48
|
|
48
49
|
exprs = node.children
|
49
50
|
|
@@ -71,8 +72,10 @@ module RuboCop
|
|
71
72
|
|
72
73
|
def each_semicolon
|
73
74
|
tokens_for_lines.each do |line, tokens|
|
74
|
-
|
75
|
-
|
75
|
+
semicolon_pos = semicolon_position(tokens)
|
76
|
+
after_expr_pos = semicolon_pos == -1 ? -2 : semicolon_pos
|
77
|
+
|
78
|
+
yield line, tokens[semicolon_pos].column, tokens[after_expr_pos] if semicolon_pos
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
@@ -80,6 +83,26 @@ module RuboCop
|
|
80
83
|
processed_source.tokens.group_by(&:line)
|
81
84
|
end
|
82
85
|
|
86
|
+
def semicolon_position(tokens)
|
87
|
+
if tokens.last.semicolon?
|
88
|
+
-1
|
89
|
+
elsif tokens.first.semicolon?
|
90
|
+
0
|
91
|
+
elsif exist_semicolon_before_right_curly_brace?(tokens)
|
92
|
+
-3
|
93
|
+
elsif exist_semicolon_after_left_curly_brace?(tokens)
|
94
|
+
2
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def exist_semicolon_before_right_curly_brace?(tokens)
|
99
|
+
tokens[-2]&.right_curly_brace? && tokens[-3]&.semicolon?
|
100
|
+
end
|
101
|
+
|
102
|
+
def exist_semicolon_after_left_curly_brace?(tokens)
|
103
|
+
tokens[1]&.left_curly_brace? && tokens[2]&.semicolon?
|
104
|
+
end
|
105
|
+
|
83
106
|
def register_semicolon(line, column, after_expression, token_before_semicolon = nil)
|
84
107
|
range = source_range(processed_source.buffer, line, column)
|
85
108
|
|
@@ -119,11 +119,6 @@ module RuboCop
|
|
119
119
|
# @!method custom_fail_methods(node)
|
120
120
|
def_node_search :custom_fail_methods, '{(def :fail ...) (defs _ :fail ...)}'
|
121
121
|
|
122
|
-
def on_new_investigation
|
123
|
-
ast = processed_source.ast
|
124
|
-
@custom_fail_defined = ast && custom_fail_methods(ast).any?
|
125
|
-
end
|
126
|
-
|
127
122
|
def on_rescue(node)
|
128
123
|
return unless style == :semantic
|
129
124
|
|
@@ -141,7 +136,7 @@ module RuboCop
|
|
141
136
|
when :semantic
|
142
137
|
check_send(:raise, node) unless ignored_node?(node)
|
143
138
|
when :only_raise
|
144
|
-
return if
|
139
|
+
return if custom_fail_defined?
|
145
140
|
|
146
141
|
check_send(:fail, node)
|
147
142
|
when :only_fail
|
@@ -151,6 +146,13 @@ module RuboCop
|
|
151
146
|
|
152
147
|
private
|
153
148
|
|
149
|
+
def custom_fail_defined?
|
150
|
+
return @custom_fail_defined if defined?(@custom_fail_defined)
|
151
|
+
|
152
|
+
ast = processed_source.ast
|
153
|
+
@custom_fail_defined = ast && custom_fail_methods(ast).any?
|
154
|
+
end
|
155
|
+
|
154
156
|
def message(method_name)
|
155
157
|
case style
|
156
158
|
when :semantic
|
@@ -41,10 +41,13 @@ module RuboCop
|
|
41
41
|
|
42
42
|
def on_pair(node)
|
43
43
|
return unless string_hash_key?(node)
|
44
|
+
|
45
|
+
key_content = node.key.str_content
|
46
|
+
return unless key_content.valid_encoding?
|
44
47
|
return if receive_environments_method?(node)
|
45
48
|
|
46
49
|
add_offense(node.key) do |corrector|
|
47
|
-
symbol_content =
|
50
|
+
symbol_content = key_content.to_sym.inspect
|
48
51
|
|
49
52
|
corrector.replace(node.key, symbol_content)
|
50
53
|
end
|
@@ -95,11 +95,7 @@ module RuboCop
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def offense?(node)
|
98
|
-
|
99
|
-
# for this cop.
|
100
|
-
return false if inside_interpolation?(node)
|
101
|
-
|
102
|
-
wrong_quotes?(node)
|
98
|
+
wrong_quotes?(node) && !inside_interpolation?(node)
|
103
99
|
end
|
104
100
|
|
105
101
|
def consistent_multiline?
|
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# If you prefer a style that allows block for method with arguments,
|
9
9
|
# please set `true` to `AllowMethodsWithArguments`.
|
10
|
-
#
|
10
|
+
# `define_method?` methods are allowed by default.
|
11
11
|
# These are customizable with `AllowedMethods` option.
|
12
12
|
#
|
13
13
|
# @safety
|
@@ -72,12 +72,10 @@ module RuboCop
|
|
72
72
|
# # some comment
|
73
73
|
# end
|
74
74
|
#
|
75
|
-
# @example AllowedMethods: [
|
75
|
+
# @example AllowedMethods: [define_method] (default)
|
76
76
|
# # good
|
77
|
-
# respond_to { |foo| foo.bar }
|
78
77
|
# define_method(:foo) { |foo| foo.bar }
|
79
78
|
#
|
80
|
-
#
|
81
79
|
# @example AllowedPatterns: [] (default)
|
82
80
|
# # bad
|
83
81
|
# something.map { |s| s.upcase }
|
@@ -88,6 +88,10 @@ module RuboCop
|
|
88
88
|
include TrailingComma
|
89
89
|
extend AutoCorrector
|
90
90
|
|
91
|
+
def self.autocorrect_incompatible_with
|
92
|
+
[Layout::HeredocArgumentClosingParenthesis]
|
93
|
+
end
|
94
|
+
|
91
95
|
def on_send(node)
|
92
96
|
return unless node.arguments? && node.parenthesized?
|
93
97
|
|
@@ -96,10 +100,6 @@ module RuboCop
|
|
96
100
|
node.source_range.end_pos)
|
97
101
|
end
|
98
102
|
alias on_csend on_send
|
99
|
-
|
100
|
-
def self.autocorrect_incompatible_with
|
101
|
-
[Layout::HeredocArgumentClosingParenthesis]
|
102
|
-
end
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
@@ -27,6 +27,25 @@ module RuboCop
|
|
27
27
|
# # bad (contains spaces)
|
28
28
|
# %w[foo\ bar baz\ quux]
|
29
29
|
#
|
30
|
+
# # bad
|
31
|
+
# [
|
32
|
+
# ['one', 'One'],
|
33
|
+
# ['two', 'Two']
|
34
|
+
# ]
|
35
|
+
#
|
36
|
+
# # good
|
37
|
+
# [
|
38
|
+
# %w[one One],
|
39
|
+
# %w[two Two]
|
40
|
+
# ]
|
41
|
+
#
|
42
|
+
# # good (2d array containing spaces)
|
43
|
+
# [
|
44
|
+
# ['one', 'One'],
|
45
|
+
# ['two', 'Two'],
|
46
|
+
# ['forty two', 'Forty Two']
|
47
|
+
# ]
|
48
|
+
#
|
30
49
|
# @example EnforcedStyle: brackets
|
31
50
|
# # good
|
32
51
|
# ['foo', 'bar', 'baz']
|
@@ -36,6 +55,19 @@ module RuboCop
|
|
36
55
|
#
|
37
56
|
# # good (contains spaces)
|
38
57
|
# ['foo bar', 'baz quux']
|
58
|
+
#
|
59
|
+
# # good
|
60
|
+
# [
|
61
|
+
# ['one', 'One'],
|
62
|
+
# ['two', 'Two']
|
63
|
+
# ]
|
64
|
+
#
|
65
|
+
# # bad
|
66
|
+
# [
|
67
|
+
# %w[one One],
|
68
|
+
# %w[two Two]
|
69
|
+
# ]
|
70
|
+
#
|
39
71
|
class WordArray < Base
|
40
72
|
include ArrayMinSize
|
41
73
|
include ArraySyntax
|
@@ -53,6 +85,7 @@ module RuboCop
|
|
53
85
|
def on_array(node)
|
54
86
|
if bracketed_array_of?(:str, node)
|
55
87
|
return if complex_content?(node.values)
|
88
|
+
return if within_2d_array_of_complex_content?(node)
|
56
89
|
|
57
90
|
check_bracketed_array(node, 'w')
|
58
91
|
elsif node.percent_literal?(:string)
|
@@ -62,6 +95,14 @@ module RuboCop
|
|
62
95
|
|
63
96
|
private
|
64
97
|
|
98
|
+
def within_2d_array_of_complex_content?(node)
|
99
|
+
return false unless (parent = node.parent)
|
100
|
+
|
101
|
+
parent.array_type? &&
|
102
|
+
parent.values.all?(&:array_type?) &&
|
103
|
+
parent.values.any? { |subarray| complex_content?(subarray.values) }
|
104
|
+
end
|
105
|
+
|
65
106
|
def complex_content?(strings, complex_regex: word_regex)
|
66
107
|
strings.any? do |s|
|
67
108
|
next unless s.str_content
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Forbids Yoda expressions, i.e. binary operations (using `*`, `+`, `&`, `|`,
|
7
|
+
# and `^` operators) where the order of expression is reversed, eg. `1 + x`.
|
8
|
+
# This cop complements `Style/YodaCondition` cop, which has a similar purpose.
|
9
|
+
#
|
10
|
+
# This cop is disabled by default to respect user intentions such as:
|
11
|
+
#
|
12
|
+
# [source,ruby]
|
13
|
+
# ----
|
14
|
+
# config.server_port = 9000 + ENV["TEST_ENV_NUMBER"].to_i
|
15
|
+
# ----
|
16
|
+
#
|
17
|
+
# @safety
|
18
|
+
# This cop is unsafe because binary operators can be defined
|
19
|
+
# differently on different classes, and are not guaranteed to
|
20
|
+
# have the same result if reversed.
|
21
|
+
#
|
22
|
+
# @example SupportedOperators: ['*', '+', '&'']
|
23
|
+
# # bad
|
24
|
+
# 1 + x
|
25
|
+
# 10 * y
|
26
|
+
# 1 & z
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# 60 * 24
|
30
|
+
# x + 1
|
31
|
+
# y * 10
|
32
|
+
# z & 1
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# 1 | x
|
36
|
+
#
|
37
|
+
class YodaExpression < Base
|
38
|
+
extend AutoCorrector
|
39
|
+
|
40
|
+
MSG = 'Non-literal operand (`%<source>s`) should be first.'
|
41
|
+
|
42
|
+
RESTRICT_ON_SEND = %i[* + & | ^].freeze
|
43
|
+
|
44
|
+
def on_new_investigation
|
45
|
+
@offended_nodes = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_send(node)
|
49
|
+
return unless supported_operators.include?(node.method_name.to_s)
|
50
|
+
|
51
|
+
lhs = node.receiver
|
52
|
+
rhs = node.first_argument
|
53
|
+
return if !lhs.numeric_type? || rhs.numeric_type?
|
54
|
+
|
55
|
+
return if offended_ancestor?(node)
|
56
|
+
|
57
|
+
message = format(MSG, source: rhs.source)
|
58
|
+
add_offense(node, message: message) do |corrector|
|
59
|
+
corrector.swap(lhs, rhs)
|
60
|
+
end
|
61
|
+
|
62
|
+
offended_nodes.add(node)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def supported_operators
|
68
|
+
Array(cop_config['SupportedOperators'])
|
69
|
+
end
|
70
|
+
|
71
|
+
def offended_ancestor?(node)
|
72
|
+
node.each_ancestor(:send).any? { |ancestor| @offended_nodes&.include?(ancestor) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def offended_nodes
|
76
|
+
@offended_nodes ||= Set.new.compare_by_identity
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -34,43 +34,55 @@ module RuboCop
|
|
34
34
|
class ZeroLengthPredicate < Base
|
35
35
|
extend AutoCorrector
|
36
36
|
|
37
|
-
ZERO_MSG = 'Use `empty?` instead of `%<
|
38
|
-
NONZERO_MSG = 'Use `!empty?` instead of `%<
|
37
|
+
ZERO_MSG = 'Use `empty?` instead of `%<current>s`.'
|
38
|
+
NONZERO_MSG = 'Use `!empty?` instead of `%<current>s`.'
|
39
39
|
|
40
40
|
RESTRICT_ON_SEND = %i[size length].freeze
|
41
41
|
|
42
42
|
def on_send(node)
|
43
43
|
check_zero_length_predicate(node)
|
44
|
-
|
44
|
+
check_zero_length_comparison(node)
|
45
|
+
check_nonzero_length_comparison(node)
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
48
49
|
|
49
50
|
def check_zero_length_predicate(node)
|
50
|
-
|
51
|
-
return unless zero_length_predicate
|
51
|
+
return unless (length_method = zero_length_predicate(node.parent))
|
52
52
|
|
53
|
-
|
53
|
+
offense = node.loc.selector.join(node.parent.source_range.end)
|
54
|
+
message = format(ZERO_MSG, current: "#{length_method}.zero?")
|
55
|
+
|
56
|
+
add_offense(offense, message: message) do |corrector|
|
57
|
+
corrector.replace(offense, 'empty?')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_zero_length_comparison(node)
|
62
|
+
zero_length_comparison = zero_length_comparison(node.parent)
|
63
|
+
return unless zero_length_comparison
|
64
|
+
|
65
|
+
lhs, opr, rhs = zero_length_comparison
|
54
66
|
|
55
67
|
return if non_polymorphic_collection?(node.parent)
|
56
68
|
|
57
69
|
add_offense(
|
58
|
-
node.parent, message: format(ZERO_MSG,
|
70
|
+
node.parent, message: format(ZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
|
59
71
|
) do |corrector|
|
60
72
|
corrector.replace(node.parent, replacement(node.parent))
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
64
|
-
def
|
65
|
-
|
66
|
-
return unless
|
76
|
+
def check_nonzero_length_comparison(node)
|
77
|
+
nonzero_length_comparison = nonzero_length_comparison(node.parent)
|
78
|
+
return unless nonzero_length_comparison
|
67
79
|
|
68
|
-
lhs, opr, rhs =
|
80
|
+
lhs, opr, rhs = nonzero_length_comparison
|
69
81
|
|
70
82
|
return if non_polymorphic_collection?(node.parent)
|
71
83
|
|
72
84
|
add_offense(
|
73
|
-
node.parent, message: format(NONZERO_MSG,
|
85
|
+
node.parent, message: format(NONZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
|
74
86
|
) do |corrector|
|
75
87
|
corrector.replace(node.parent, replacement(node.parent))
|
76
88
|
end
|
@@ -78,14 +90,19 @@ module RuboCop
|
|
78
90
|
|
79
91
|
# @!method zero_length_predicate(node)
|
80
92
|
def_node_matcher :zero_length_predicate, <<~PATTERN
|
93
|
+
(send (send (...) ${:length :size}) :zero?)
|
94
|
+
PATTERN
|
95
|
+
|
96
|
+
# @!method zero_length_comparison(node)
|
97
|
+
def_node_matcher :zero_length_comparison, <<~PATTERN
|
81
98
|
{(send (send (...) ${:length :size}) $:== (int $0))
|
82
99
|
(send (int $0) $:== (send (...) ${:length :size}))
|
83
100
|
(send (send (...) ${:length :size}) $:< (int $1))
|
84
101
|
(send (int $1) $:> (send (...) ${:length :size}))}
|
85
102
|
PATTERN
|
86
103
|
|
87
|
-
# @!method
|
88
|
-
def_node_matcher :
|
104
|
+
# @!method nonzero_length_comparison(node)
|
105
|
+
def_node_matcher :nonzero_length_comparison, <<~PATTERN
|
89
106
|
{(send (send (...) ${:length :size}) ${:> :!=} (int $0))
|
90
107
|
(send (int $0) ${:< :!=} (send (...) ${:length :size}))}
|
91
108
|
PATTERN
|
data/lib/rubocop/cop/team.rb
CHANGED
@@ -10,20 +10,6 @@ module RuboCop
|
|
10
10
|
# first the ones needed for autocorrection (if any), then the rest
|
11
11
|
# (unless autocorrections happened).
|
12
12
|
class Team
|
13
|
-
attr_reader :errors, :warnings, :updated_source_file, :cops
|
14
|
-
|
15
|
-
alias updated_source_file? updated_source_file
|
16
|
-
|
17
|
-
def initialize(cops, config = nil, options = {})
|
18
|
-
@cops = cops
|
19
|
-
@config = config
|
20
|
-
@options = options
|
21
|
-
reset
|
22
|
-
@ready = true
|
23
|
-
|
24
|
-
validate_config
|
25
|
-
end
|
26
|
-
|
27
13
|
# @return [Team]
|
28
14
|
def self.new(cop_or_classes, config, options = {})
|
29
15
|
# Support v0 api:
|
@@ -38,7 +24,7 @@ module RuboCop
|
|
38
24
|
new(cops, config, options)
|
39
25
|
end
|
40
26
|
|
41
|
-
# @return [Array<Cop::
|
27
|
+
# @return [Array<Cop::Base>]
|
42
28
|
def self.mobilize_cops(cop_classes, config, options = {})
|
43
29
|
cop_classes = Registry.new(cop_classes.to_a, options) unless cop_classes.is_a?(Registry)
|
44
30
|
|
@@ -47,6 +33,35 @@ module RuboCop
|
|
47
33
|
end
|
48
34
|
end
|
49
35
|
|
36
|
+
# @return [Array<Force>] needed for the given cops
|
37
|
+
def self.forces_for(cops)
|
38
|
+
needed = Hash.new { |h, k| h[k] = [] }
|
39
|
+
cops.each do |cop|
|
40
|
+
forces = cop.class.joining_forces
|
41
|
+
if forces.is_a?(Array)
|
42
|
+
forces.each { |force| needed[force] << cop }
|
43
|
+
elsif forces
|
44
|
+
needed[forces] << cop
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
needed.map { |force_class, joining_cops| force_class.new(joining_cops) }
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :errors, :warnings, :updated_source_file, :cops
|
52
|
+
|
53
|
+
alias updated_source_file? updated_source_file
|
54
|
+
|
55
|
+
def initialize(cops, config = nil, options = {})
|
56
|
+
@cops = cops
|
57
|
+
@config = config
|
58
|
+
@options = options
|
59
|
+
reset
|
60
|
+
@ready = true
|
61
|
+
|
62
|
+
validate_config
|
63
|
+
end
|
64
|
+
|
50
65
|
def autocorrect?
|
51
66
|
@options[:autocorrect]
|
52
67
|
end
|
@@ -94,21 +109,6 @@ module RuboCop
|
|
94
109
|
@forces ||= self.class.forces_for(cops)
|
95
110
|
end
|
96
111
|
|
97
|
-
# @return [Array<Force>] needed for the given cops
|
98
|
-
def self.forces_for(cops)
|
99
|
-
needed = Hash.new { |h, k| h[k] = [] }
|
100
|
-
cops.each do |cop|
|
101
|
-
forces = cop.class.joining_forces
|
102
|
-
if forces.is_a?(Array)
|
103
|
-
forces.each { |force| needed[force] << cop }
|
104
|
-
elsif forces
|
105
|
-
needed[forces] << cop
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
needed.map { |force_class, joining_cops| force_class.new(joining_cops) }
|
110
|
-
end
|
111
|
-
|
112
112
|
def external_dependency_checksum
|
113
113
|
keys = cops.map(&:external_dependency_checksum).compact
|
114
114
|
Digest::SHA1.hexdigest(keys.join)
|