rubocop 1.91.0 → 1.92.2
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 +4 -1
- data/lib/rubocop/cached_data.rb +47 -7
- data/lib/rubocop/changed_files.rb +35 -13
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +2 -2
- data/lib/rubocop/cli/command/explain.rb +34 -0
- data/lib/rubocop/cli/command/show_cops.rb +6 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
- data/lib/rubocop/cli.rb +3 -2
- data/lib/rubocop/comment_config.rb +17 -8
- data/lib/rubocop/config.rb +0 -4
- data/lib/rubocop/config_loader.rb +6 -3
- data/lib/rubocop/config_loader_resolver.rb +37 -12
- data/lib/rubocop/config_obsoletion/removed_cop.rb +1 -1
- data/lib/rubocop/config_obsoletion.rb +9 -0
- data/lib/rubocop/config_validator.rb +11 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +42 -21
- data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
- data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
- data/lib/rubocop/cop/cop_documentation.rb +81 -0
- data/lib/rubocop/cop/cop_explanation.rb +140 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +25 -4
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
- data/lib/rubocop/cop/documentation.rb +1 -1
- data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
- data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/class_structure.rb +29 -7
- data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/dot_position.rb +25 -15
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +21 -25
- data/lib/rubocop/cop/layout/extra_spacing.rb +21 -6
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +27 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +16 -8
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +16 -12
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +7 -3
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
- data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
- data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/line_length.rb +176 -26
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +9 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +30 -5
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
- data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +6 -11
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +16 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -9
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
- data/lib/rubocop/cop/lint/literal_as_condition.rb +15 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
- data/lib/rubocop/cop/lint/loop.rb +24 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +71 -11
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +3 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
- data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +39 -9
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
- data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/lint/void.rb +8 -1
- data/lib/rubocop/cop/metrics/class_length.rb +4 -2
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
- data/lib/rubocop/cop/metrics/module_length.rb +4 -2
- data/lib/rubocop/cop/mixin/alignment.rb +4 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -19
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +8 -2
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +41 -6
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +26 -2
- data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +17 -2
- data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +39 -5
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
- data/lib/rubocop/cop/mixin.rb +2 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +59 -3
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +37 -2
- data/lib/rubocop/cop/style/alias.rb +18 -5
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
- data/lib/rubocop/cop/style/and_or.rb +37 -10
- data/lib/rubocop/cop/style/arguments_forwarding.rb +32 -3
- data/lib/rubocop/cop/style/attr.rb +3 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
- data/lib/rubocop/cop/style/block_delimiters.rb +35 -3
- data/lib/rubocop/cop/style/case_equality.rb +14 -3
- data/lib/rubocop/cop/style/case_like_if.rb +6 -3
- data/lib/rubocop/cop/style/class_and_module_children.rb +57 -16
- data/lib/rubocop/cop/style/class_methods_definitions.rb +15 -0
- data/lib/rubocop/cop/style/collection_querying.rb +79 -46
- data/lib/rubocop/cop/style/combinable_loops.rb +89 -11
- data/lib/rubocop/cop/style/concat_array_literals.rb +58 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +65 -9
- data/lib/rubocop/cop/style/double_negation.rb +11 -0
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +3 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
- data/lib/rubocop/cop/style/endless_method.rb +104 -11
- data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
- data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
- data/lib/rubocop/cop/style/float_division.rb +37 -2
- data/lib/rubocop/cop/style/for.rb +53 -2
- data/lib/rubocop/cop/style/format_string.rb +28 -6
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/guard_clause.rb +31 -22
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
- data/lib/rubocop/cop/style/hash_lookup_method.rb +42 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -26
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
- data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
- data/lib/rubocop/cop/style/lambda.rb +34 -1
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/map_into_array.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +80 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +26 -2
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
- data/lib/rubocop/cop/style/method_def_parentheses.rb +38 -4
- data/lib/rubocop/cop/style/missing_else.rb +7 -1
- data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
- data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +52 -7
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
- data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +27 -8
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
- data/lib/rubocop/cop/style/next.rb +24 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +16 -4
- data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
- data/lib/rubocop/cop/style/not.rb +10 -5
- data/lib/rubocop/cop/style/numeric_predicate.rb +28 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +13 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
- data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
- data/lib/rubocop/cop/style/raise_args.rb +80 -11
- data/lib/rubocop/cop/style/reduce_to_hash.rb +47 -33
- data/lib/rubocop/cop/style/redundant_begin.rb +45 -5
- data/lib/rubocop/cop/style/redundant_condition.rb +30 -13
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -0
- data/lib/rubocop/cop/style/redundant_exception.rb +27 -11
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -1
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +20 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
- data/lib/rubocop/cop/style/redundant_self.rb +9 -1
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
- data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
- data/lib/rubocop/cop/style/require_order.rb +25 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +11 -9
- data/lib/rubocop/cop/style/return_nil.rb +17 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/sample.rb +9 -8
- data/lib/rubocop/cop/style/self_assignment.rb +12 -15
- data/lib/rubocop/cop/style/semicolon.rb +16 -5
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +42 -4
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
- data/lib/rubocop/cop/style/string_concatenation.rb +21 -4
- data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
- data/lib/rubocop/cop/style/super_arguments.rb +3 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +24 -6
- data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
- data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
- data/lib/rubocop/cop/team.rb +10 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +14 -1
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/formatter_set.rb +4 -0
- data/lib/rubocop/formatter/json_formatter.rb +71 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +12 -7
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
- data/lib/rubocop/lsp/routes.rb +23 -23
- data/lib/rubocop/lsp/runtime.rb +47 -11
- data/lib/rubocop/lsp/stdin_runner.rb +11 -5
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
- data/lib/rubocop/mcp/explain_tool.rb +68 -0
- data/lib/rubocop/mcp/scope.rb +65 -0
- data/lib/rubocop/mcp/server.rb +184 -76
- data/lib/rubocop/mcp/source_files.rb +35 -0
- data/lib/rubocop/offense_limit.rb +30 -0
- data/lib/rubocop/options.rb +45 -10
- data/lib/rubocop/plugin/configuration_integrator.rb +36 -8
- data/lib/rubocop/remote_config.rb +4 -1
- data/lib/rubocop/result_cache.rb +20 -13
- data/lib/rubocop/runner.rb +110 -42
- data/lib/rubocop/server/cache.rb +6 -6
- data/lib/rubocop/target_ruby.rb +21 -9
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +16 -5
|
@@ -245,20 +245,30 @@ module RuboCop
|
|
|
245
245
|
return if with_space.is?(operator.source)
|
|
246
246
|
|
|
247
247
|
"Space around operator `#{operator.source}` detected."
|
|
248
|
-
elsif
|
|
248
|
+
elsif missing_surrounding_space?(with_space)
|
|
249
249
|
"Surrounding space missing for operator `#{operator.source}`."
|
|
250
|
-
elsif excess_leading_space?(type, operator, with_space) ||
|
|
250
|
+
elsif excess_leading_space?(type, operator, with_space, right_operand) ||
|
|
251
251
|
excess_trailing_space?(right_operand.source_range, with_space)
|
|
252
252
|
"Operator `#{operator.source}` should be surrounded " \
|
|
253
253
|
'by a single space.'
|
|
254
254
|
end
|
|
255
255
|
end
|
|
256
256
|
|
|
257
|
-
def
|
|
257
|
+
def missing_surrounding_space?(with_space)
|
|
258
|
+
return false if /\A\s.*\s\z/m.match?(with_space.source)
|
|
259
|
+
|
|
260
|
+
!with_space.source.start_with?(/\s/) || !line_continuation_after?(with_space)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def line_continuation_after?(range)
|
|
264
|
+
processed_source.buffer.source[range.end_pos, 2] == "\\\n"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def excess_leading_space?(type, operator, with_space, right_operand)
|
|
258
268
|
return false unless allow_for_alignment?
|
|
259
269
|
return false unless with_space.source.start_with?(EXCESSIVE_SPACE)
|
|
260
270
|
|
|
261
|
-
return !
|
|
271
|
+
return !aligned?(type, operator, right_operand) unless grouped_alignment_type?(type)
|
|
262
272
|
|
|
263
273
|
token = Token.new(operator, nil, operator.source)
|
|
264
274
|
align_preceding = aligned_with_preceding_equals_operator(token)
|
|
@@ -269,6 +279,23 @@ module RuboCop
|
|
|
269
279
|
aligned_with_subsequent_equals_operator(token) != :yes
|
|
270
280
|
end
|
|
271
281
|
|
|
282
|
+
def aligned?(type, operator, right_operand)
|
|
283
|
+
return true if aligned_with_operator?(operator)
|
|
284
|
+
|
|
285
|
+
type == :pair && aligned_with_another_hash_rocket?(right_operand)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def aligned_with_another_hash_rocket?(pair)
|
|
289
|
+
hash_rocket_columns(pair.parent)[pair.loc.operator.column] > 1
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def hash_rocket_columns(hash_node)
|
|
293
|
+
@hash_rocket_columns ||= {}.compare_by_identity
|
|
294
|
+
@hash_rocket_columns[hash_node] ||= hash_node.pairs.select(&:hash_rocket?).map do |pair|
|
|
295
|
+
pair.loc.operator.column
|
|
296
|
+
end.tally
|
|
297
|
+
end
|
|
298
|
+
|
|
272
299
|
def grouped_alignment_type?(type)
|
|
273
300
|
type == :assignment || (type == :special_asgn && force_equal_sign_alignment?)
|
|
274
301
|
end
|
|
@@ -49,8 +49,11 @@ module RuboCop
|
|
|
49
49
|
MISSING_MSG = 'Space missing to the left of {.'
|
|
50
50
|
DETECTED_MSG = 'Space detected to the left of {.'
|
|
51
51
|
|
|
52
|
+
# `Style/BlockDelimiters` decides whether to put a space before the `do`
|
|
53
|
+
# it writes by looking at the source before this cop removed the space,
|
|
54
|
+
# so the two corrections cannot be applied in the same pass.
|
|
52
55
|
def self.autocorrect_incompatible_with
|
|
53
|
-
[Style::SymbolProc]
|
|
56
|
+
[Style::BlockDelimiters, Style::SymbolProc]
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
def on_block(node)
|
|
@@ -133,11 +136,23 @@ module RuboCop
|
|
|
133
136
|
|
|
134
137
|
def autocorrect(corrector, range)
|
|
135
138
|
case range.source
|
|
139
|
+
when /\n/ then remove_line_continuation(corrector, range)
|
|
136
140
|
when /\s/ then corrector.remove(range)
|
|
137
141
|
else corrector.insert_before(range, ' ')
|
|
138
142
|
end
|
|
139
143
|
end
|
|
140
144
|
|
|
145
|
+
# When a heredoc body sits between the `\` and the brace, the newline before
|
|
146
|
+
# the brace ends the heredoc, and removing it would break the terminator.
|
|
147
|
+
def remove_line_continuation(corrector, range)
|
|
148
|
+
source = processed_source.buffer.source
|
|
149
|
+
return unless source[range.begin_pos - 1] == '\\'
|
|
150
|
+
|
|
151
|
+
begin_pos = range.begin_pos
|
|
152
|
+
begin_pos -= 1 while source[begin_pos - 1].match?(/[ \t\\]/)
|
|
153
|
+
corrector.remove(range_between(begin_pos, range.end_pos))
|
|
154
|
+
end
|
|
155
|
+
|
|
141
156
|
def style_for_empty_braces
|
|
142
157
|
case cop_config['EnforcedStyleForEmptyBraces']
|
|
143
158
|
when 'space' then :space
|
|
@@ -117,7 +117,7 @@ module RuboCop
|
|
|
117
117
|
elsif style == :space
|
|
118
118
|
SpaceCorrector.add_space(processed_source, corrector, left, right)
|
|
119
119
|
else
|
|
120
|
-
compact_corrections(corrector, tokens, left, right)
|
|
120
|
+
compact_corrections(corrector, node, tokens, left, right)
|
|
121
121
|
end
|
|
122
122
|
end
|
|
123
123
|
|
|
@@ -178,6 +178,8 @@ module RuboCop
|
|
|
178
178
|
space_offenses(node, left, nil, MSG, start_ok: start_ok, end_ok: true)
|
|
179
179
|
end
|
|
180
180
|
|
|
181
|
+
return if closing_bracket_kept_apart?(node, tokens, left, right)
|
|
182
|
+
|
|
181
183
|
if qualifies_for_compact?(tokens, right)
|
|
182
184
|
compact_offense(node, right)
|
|
183
185
|
elsif !multi_dimensional_array?(tokens, right)
|
|
@@ -212,13 +214,24 @@ module RuboCop
|
|
|
212
214
|
end
|
|
213
215
|
end
|
|
214
216
|
|
|
215
|
-
|
|
217
|
+
# A closing bracket on its own line is only collapsed when the opening
|
|
218
|
+
# bracket ends up on the first element's line, so that the brackets
|
|
219
|
+
# stay symmetrical (see `Layout/MultilineArrayBraceLayout`).
|
|
220
|
+
def closing_bracket_kept_apart?(node, tokens, left, right)
|
|
221
|
+
end_has_own_line?(right) &&
|
|
222
|
+
!multi_dimensional_array?(tokens, left, side: :left) &&
|
|
223
|
+
!same_line?(left, node.children.first)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def compact_corrections(corrector, node, tokens, left, right)
|
|
216
227
|
if multi_dimensional_array?(tokens, left, side: :left)
|
|
217
228
|
compact(corrector, left, :right)
|
|
218
229
|
elsif !left.space_after?
|
|
219
230
|
corrector.insert_after(left.pos, ' ')
|
|
220
231
|
end
|
|
221
232
|
|
|
233
|
+
return if closing_bracket_kept_apart?(node, tokens, left, right)
|
|
234
|
+
|
|
222
235
|
if multi_dimensional_array?(tokens, right)
|
|
223
236
|
compact(corrector, right, :left)
|
|
224
237
|
elsif !right.space_before?
|
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
|
83
83
|
extend AutoCorrector
|
|
84
84
|
|
|
85
85
|
def self.autocorrect_incompatible_with
|
|
86
|
-
[Style::BlockDelimiters]
|
|
86
|
+
[Layout::BlockAlignment, Style::BlockDelimiters]
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def on_block(node)
|
|
@@ -153,7 +153,7 @@ module RuboCop
|
|
|
153
153
|
else
|
|
154
154
|
column = node.source_range.column
|
|
155
155
|
return if multiline_block?(left_brace, right_brace) &&
|
|
156
|
-
aligned_braces?(inner, right_brace, column)
|
|
156
|
+
aligned_braces?(inner, right_brace, column, left_brace)
|
|
157
157
|
|
|
158
158
|
space_inside_right_brace(inner, right_brace, column)
|
|
159
159
|
end
|
|
@@ -163,14 +163,21 @@ module RuboCop
|
|
|
163
163
|
left_brace.first_line != right_brace.first_line
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
-
def aligned_braces?(inner, right_brace, column)
|
|
167
|
-
column == right_brace.column ||
|
|
166
|
+
def aligned_braces?(inner, right_brace, column, left_brace)
|
|
167
|
+
column == right_brace.column ||
|
|
168
|
+
column == inner_last_space_count(inner) ||
|
|
169
|
+
aligned_with_opening_brace_line?(left_brace, right_brace)
|
|
168
170
|
end
|
|
169
171
|
|
|
170
172
|
def inner_last_space_count(inner)
|
|
171
173
|
inner.split("\n").last.count(' ')
|
|
172
174
|
end
|
|
173
175
|
|
|
176
|
+
def aligned_with_opening_brace_line?(left_brace, right_brace)
|
|
177
|
+
begins_its_line?(right_brace) &&
|
|
178
|
+
right_brace.column == left_brace.source_line[/\A\s*/].length
|
|
179
|
+
end
|
|
180
|
+
|
|
174
181
|
def no_space_inside_left_brace(left_brace, args_delimiter)
|
|
175
182
|
if pipe?(args_delimiter)
|
|
176
183
|
if left_brace.end_pos == args_delimiter.begin_pos &&
|
|
@@ -197,9 +204,7 @@ module RuboCop
|
|
|
197
204
|
'Space between { and | detected.')
|
|
198
205
|
end
|
|
199
206
|
else
|
|
200
|
-
|
|
201
|
-
space(brace_with_space.begin_pos + 1, brace_with_space.end_pos,
|
|
202
|
-
'Space inside { detected.')
|
|
207
|
+
space_after_left_brace(left_brace)
|
|
203
208
|
end
|
|
204
209
|
end
|
|
205
210
|
|
|
@@ -207,6 +212,20 @@ module RuboCop
|
|
|
207
212
|
args_delimiter&.is?('|')
|
|
208
213
|
end
|
|
209
214
|
|
|
215
|
+
def space_after_left_brace(left_brace)
|
|
216
|
+
brace_with_space = range_with_surrounding_space(left_brace, side: :right)
|
|
217
|
+
return if brace_with_space.source.match?(/\R/)
|
|
218
|
+
return if comment_at?(brace_with_space.end_pos)
|
|
219
|
+
|
|
220
|
+
space(
|
|
221
|
+
brace_with_space.begin_pos + 1, brace_with_space.end_pos, 'Space inside { detected.'
|
|
222
|
+
)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def comment_at?(pos)
|
|
226
|
+
processed_source.comments.any? { |comment| comment.source_range.begin_pos == pos }
|
|
227
|
+
end
|
|
228
|
+
|
|
210
229
|
def space_inside_right_brace(inner, right_brace, column)
|
|
211
230
|
brace_with_space = range_with_surrounding_space(right_brace, side: :left)
|
|
212
231
|
begin_pos = brace_with_space.begin_pos
|
|
@@ -216,7 +235,7 @@ module RuboCop
|
|
|
216
235
|
begin_pos = end_pos - (right_brace.column - column)
|
|
217
236
|
end
|
|
218
237
|
|
|
219
|
-
if
|
|
238
|
+
if closing_bracket_on_own_line?(inner)
|
|
220
239
|
end_pos -= 1
|
|
221
240
|
begin_pos = end_pos - (inner_last_space_count(inner) - column)
|
|
222
241
|
end
|
|
@@ -224,6 +243,10 @@ module RuboCop
|
|
|
224
243
|
space(begin_pos, end_pos, 'Space inside } detected.')
|
|
225
244
|
end
|
|
226
245
|
|
|
246
|
+
def closing_bracket_on_own_line?(inner)
|
|
247
|
+
inner[/[^\n]*\z/].match?(/\A\s*\]\z/)
|
|
248
|
+
end
|
|
249
|
+
|
|
227
250
|
def no_space(begin_pos, end_pos, msg)
|
|
228
251
|
if style == :space
|
|
229
252
|
offense(begin_pos, end_pos, msg)
|
|
@@ -241,7 +264,7 @@ module RuboCop
|
|
|
241
264
|
end
|
|
242
265
|
|
|
243
266
|
def offense(begin_pos, end_pos, msg, style_param = 'EnforcedStyle')
|
|
244
|
-
return if begin_pos
|
|
267
|
+
return if begin_pos >= end_pos
|
|
245
268
|
|
|
246
269
|
range = range_between(begin_pos, end_pos)
|
|
247
270
|
add_offense(range, message: msg) do |corrector|
|
|
@@ -18,6 +18,7 @@ module RuboCop
|
|
|
18
18
|
# # good
|
|
19
19
|
# 'a'..'z'
|
|
20
20
|
class SpaceInsideRangeLiteral < Base
|
|
21
|
+
include RangeHelp
|
|
21
22
|
extend AutoCorrector
|
|
22
23
|
|
|
23
24
|
MSG = 'Space inside range literal.'
|
|
@@ -33,21 +34,38 @@ module RuboCop
|
|
|
33
34
|
private
|
|
34
35
|
|
|
35
36
|
def check(node)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# account for multiline range literals
|
|
41
|
-
expression.sub!(/#{escaped_op}\n\s*/, op)
|
|
42
|
-
|
|
43
|
-
return unless /(\s#{escaped_op})|(#{escaped_op}\s)/.match?(expression)
|
|
37
|
+
operator = node.loc.operator
|
|
38
|
+
spaces = [space_before(node, operator), space_after(node, operator)].compact
|
|
39
|
+
return if spaces.all? { |space| line_break_after_operator?(space, operator) }
|
|
44
40
|
|
|
45
41
|
add_offense(node) do |corrector|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
spaces.each do |space|
|
|
43
|
+
corrector.remove(space)
|
|
44
|
+
end
|
|
49
45
|
end
|
|
50
46
|
end
|
|
47
|
+
|
|
48
|
+
def space_before(node, operator)
|
|
49
|
+
return unless node.begin
|
|
50
|
+
|
|
51
|
+
whitespace_range(node.begin.source_range.end_pos, operator.begin_pos)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def space_after(node, operator)
|
|
55
|
+
return unless node.end
|
|
56
|
+
|
|
57
|
+
whitespace_range(operator.end_pos, node.end.source_range.begin_pos)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def line_break_after_operator?(space, operator)
|
|
61
|
+
space.begin_pos == operator.end_pos && space.source.start_with?("\n")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def whitespace_range(begin_pos, end_pos)
|
|
65
|
+
range = range_between(begin_pos, end_pos)
|
|
66
|
+
|
|
67
|
+
range if range.source.match?(/\A\s+\z/)
|
|
68
|
+
end
|
|
51
69
|
end
|
|
52
70
|
end
|
|
53
71
|
end
|
|
@@ -108,14 +108,9 @@ module RuboCop
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
def left_ref_bracket(node, tokens)
|
|
111
|
-
|
|
112
|
-
previous_token = previous_token(current_token)
|
|
111
|
+
bracket_pos = node.loc.selector.begin_pos
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
tokens.find(&:left_ref_bracket?)
|
|
116
|
-
else
|
|
117
|
-
current_token
|
|
118
|
-
end
|
|
113
|
+
tokens.find { |token| token.left_ref_bracket? && token.begin_pos == bracket_pos }
|
|
119
114
|
end
|
|
120
115
|
|
|
121
116
|
def closing_bracket(tokens, opening_bracket)
|
|
@@ -129,11 +124,6 @@ module RuboCop
|
|
|
129
124
|
end
|
|
130
125
|
end
|
|
131
126
|
|
|
132
|
-
def previous_token(current_token)
|
|
133
|
-
index = processed_source.tokens.index(current_token)
|
|
134
|
-
index.nil? || index.zero? ? nil : processed_source.tokens[index - 1]
|
|
135
|
-
end
|
|
136
|
-
|
|
137
127
|
def empty_config
|
|
138
128
|
cop_config['EnforcedStyleForEmptyBrackets']
|
|
139
129
|
end
|
|
@@ -56,7 +56,8 @@ module RuboCop
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def on_send(node)
|
|
59
|
-
|
|
59
|
+
# `foo.*` is a regular method call, not a binary operator.
|
|
60
|
+
return if node.parenthesized? || node.loc.dot
|
|
60
61
|
|
|
61
62
|
return unless (parent = node.parent)
|
|
62
63
|
return unless operator?(parent)
|
|
@@ -55,7 +55,8 @@ module RuboCop
|
|
|
55
55
|
return node if first_argument_is_regexp?(node) || !node.parent
|
|
56
56
|
|
|
57
57
|
if (node.parent.send_type? && node.receiver) ||
|
|
58
|
-
method_chain_to_regexp_receiver?(node, regexp_receiver)
|
|
58
|
+
method_chain_to_regexp_receiver?(node, regexp_receiver) ||
|
|
59
|
+
part_of_hash_argument?(node)
|
|
59
60
|
node = find_offense_node(node.parent, regexp_receiver)
|
|
60
61
|
end
|
|
61
62
|
|
|
@@ -72,6 +73,10 @@ module RuboCop
|
|
|
72
73
|
|
|
73
74
|
parent.parent && parent_receiver.receiver == regexp_receiver
|
|
74
75
|
end
|
|
76
|
+
|
|
77
|
+
def part_of_hash_argument?(node)
|
|
78
|
+
node.pair_type? || node.parent.pair_type? || (node.hash_type? && !node.braces?)
|
|
79
|
+
end
|
|
75
80
|
end
|
|
76
81
|
end
|
|
77
82
|
end
|
|
@@ -97,12 +97,14 @@ module RuboCop
|
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
def can_simplify_conditional?(node)
|
|
100
|
-
node.else_branch && node.loc.else.source == 'else'
|
|
100
|
+
!node.elsif? && node.else_branch && node.loc.else.source == 'else'
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
def remove_empty_branch(corrector, node)
|
|
104
104
|
range = if empty_if_branch?(node) && else_branch?(node)
|
|
105
105
|
branch_range(node)
|
|
106
|
+
elsif node.condition.last_line == node.loc.else.line
|
|
107
|
+
node.source_range.with(end_pos: node.loc.else.begin_pos)
|
|
106
108
|
else
|
|
107
109
|
deletion_range(branch_range(node))
|
|
108
110
|
end
|
|
@@ -34,6 +34,10 @@ module RuboCop
|
|
|
34
34
|
|
|
35
35
|
MSG = 'Put a method call with a HEREDOC receiver on the same line as the HEREDOC opening.'
|
|
36
36
|
|
|
37
|
+
def self.autocorrect_incompatible_with
|
|
38
|
+
[Style::MethodCallWithArgsParentheses]
|
|
39
|
+
end
|
|
40
|
+
|
|
37
41
|
def on_send(node)
|
|
38
42
|
heredoc = heredoc_node_descendent_receiver(node)
|
|
39
43
|
return unless heredoc
|
|
@@ -41,26 +41,22 @@ module RuboCop
|
|
|
41
41
|
|
|
42
42
|
private
|
|
43
43
|
|
|
44
|
-
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
45
44
|
def check(node)
|
|
46
45
|
return if node.parent&.regexp_type?
|
|
47
46
|
return unless /(?<!\\)#\{.*\}/.match?(node.source)
|
|
48
47
|
return if heredoc?(node)
|
|
49
|
-
return unless node
|
|
48
|
+
return unless single_quoted?(node)
|
|
50
49
|
return unless valid_syntax?(node)
|
|
51
50
|
|
|
52
51
|
add_offense(node) { |corrector| autocorrect(corrector, node) }
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
else
|
|
59
|
-
['"', '"']
|
|
60
|
-
end
|
|
54
|
+
def single_quoted?(node)
|
|
55
|
+
node.loc.begin&.is?("'") && node.loc.end
|
|
56
|
+
end
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
corrector.replace(node
|
|
58
|
+
def autocorrect(corrector, node)
|
|
59
|
+
corrector.replace(node, interpolated_source(node))
|
|
64
60
|
end
|
|
65
61
|
|
|
66
62
|
def heredoc?(node)
|
|
@@ -68,15 +64,22 @@ module RuboCop
|
|
|
68
64
|
end
|
|
69
65
|
|
|
70
66
|
def valid_syntax?(node)
|
|
71
|
-
|
|
72
|
-
node.source.sub(/\A'/, '%{').sub(/'\z/, '}')
|
|
73
|
-
else
|
|
74
|
-
node.source.gsub(/\A'|'\z/, '"')
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
processed_source = parse(double_quoted_string)
|
|
67
|
+
processed_source = parse(interpolated_source(node))
|
|
78
68
|
processed_source.valid_syntax? && processed_source.ast.dstr_type?
|
|
79
69
|
end
|
|
70
|
+
|
|
71
|
+
def interpolated_source(node)
|
|
72
|
+
content = node.source[1...-1]
|
|
73
|
+
return %("#{content}") unless content.include?('"')
|
|
74
|
+
return "%{#{content}}" unless continued_string_part?(node)
|
|
75
|
+
|
|
76
|
+
%("#{content.gsub(/\\.|"/) { |m| m == '"' ? '\"' : m }}")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# A percent literal right after another string part is parsed as the `%` operator.
|
|
80
|
+
def continued_string_part?(node)
|
|
81
|
+
node.parent&.dstr_type? && node.left_sibling
|
|
82
|
+
end
|
|
80
83
|
end
|
|
81
84
|
end
|
|
82
85
|
end
|
|
@@ -98,6 +98,8 @@ module RuboCop
|
|
|
98
98
|
end
|
|
99
99
|
elsif node.condition.falsey_literal?
|
|
100
100
|
add_offense(node.condition) do |corrector|
|
|
101
|
+
next if orphans_loop_control_keyword?(node)
|
|
102
|
+
|
|
101
103
|
corrector.replace(node, node.body.child_nodes.map(&:source).join("\n"))
|
|
102
104
|
end
|
|
103
105
|
end
|
|
@@ -127,6 +129,8 @@ module RuboCop
|
|
|
127
129
|
end
|
|
128
130
|
elsif node.condition.truthy_literal?
|
|
129
131
|
add_offense(node.condition) do |corrector|
|
|
132
|
+
next if orphans_loop_control_keyword?(node)
|
|
133
|
+
|
|
130
134
|
corrector.replace(node, node.body.child_nodes.map(&:source).join("\n"))
|
|
131
135
|
end
|
|
132
136
|
end
|
|
@@ -175,6 +179,15 @@ module RuboCop
|
|
|
175
179
|
|
|
176
180
|
private
|
|
177
181
|
|
|
182
|
+
# Unwrapping the body of a loop that runs once would leave a `break`,
|
|
183
|
+
# `next` or `redo` that belongs to it outside of any loop.
|
|
184
|
+
def orphans_loop_control_keyword?(node)
|
|
185
|
+
node.body.each_node(:next, :break, :redo).any? do |control|
|
|
186
|
+
inner = control.each_ancestor.take_while { |ancestor| !ancestor.equal?(node) }
|
|
187
|
+
inner.none? { |ancestor| ancestor.any_block_type? || ancestor.loop_keyword? }
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
178
191
|
def void_value_expression?(node)
|
|
179
192
|
node = node.children.last while node&.begin_type?
|
|
180
193
|
|
|
@@ -273,6 +286,8 @@ module RuboCop
|
|
|
273
286
|
"#{node.else_branch.source.sub('elsif', 'if')}\nend"
|
|
274
287
|
elsif node.else? || node.ternary?
|
|
275
288
|
node.else_branch.source
|
|
289
|
+
elsif node.value_used?
|
|
290
|
+
'nil'
|
|
276
291
|
else
|
|
277
292
|
'' # Equivalent to removing the node
|
|
278
293
|
end
|
|
@@ -24,30 +24,16 @@ module RuboCop
|
|
|
24
24
|
MSG = 'Literal interpolation detected.'
|
|
25
25
|
COMPOSITE = %i[array hash pair irange erange].freeze
|
|
26
26
|
|
|
27
|
-
# rubocop:disable-next Metrics/AbcSize
|
|
28
27
|
def on_interpolation(begin_node)
|
|
29
28
|
final_node = begin_node.children.last
|
|
30
29
|
return unless offending?(final_node)
|
|
31
|
-
|
|
32
|
-
# %W and %I split the content into words before expansion
|
|
33
|
-
# treating each interpolation as a word component, so
|
|
34
|
-
# interpolation should not be removed if the expanded value
|
|
35
|
-
# contains a space character.
|
|
36
|
-
expanded_value = autocorrected_value(final_node)
|
|
37
|
-
expanded_value = handle_special_regexp_chars(begin_node, expanded_value)
|
|
38
|
-
|
|
39
|
-
return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(expanded_value)
|
|
30
|
+
return unless (expanded_value = correctable_value(begin_node, final_node))
|
|
40
31
|
|
|
41
32
|
add_offense(final_node) do |corrector|
|
|
42
33
|
next if final_node.dstr_type? # nested, fixed in next iteration
|
|
34
|
+
next if follows_literal_interpolation?(begin_node)
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
final_node.source.delete_prefix('"').delete_suffix('"')
|
|
46
|
-
else
|
|
47
|
-
expanded_value
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
corrector.replace(final_node.parent, replacement)
|
|
36
|
+
corrector.replace(final_node.parent, replacement(final_node, expanded_value))
|
|
51
37
|
end
|
|
52
38
|
end
|
|
53
39
|
|
|
@@ -73,6 +59,22 @@ module RuboCop
|
|
|
73
59
|
node.array_type? && grandparent.regexp_type?
|
|
74
60
|
end
|
|
75
61
|
|
|
62
|
+
def correctable_value(begin_node, final_node)
|
|
63
|
+
value = autocorrected_value(final_node)
|
|
64
|
+
value = handle_special_regexp_chars(begin_node, value)
|
|
65
|
+
return if starts_interpolation_after_hash_sign?(begin_node, value)
|
|
66
|
+
|
|
67
|
+
value = escape_trailing_hash_sign(begin_node, value)
|
|
68
|
+
|
|
69
|
+
# %W and %I split the content into words before expansion
|
|
70
|
+
# treating each interpolation as a word component, so
|
|
71
|
+
# interpolation should not be removed if the expanded value
|
|
72
|
+
# contains a space character.
|
|
73
|
+
return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(value)
|
|
74
|
+
|
|
75
|
+
value
|
|
76
|
+
end
|
|
77
|
+
|
|
76
78
|
# rubocop:disable-next Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
77
79
|
def autocorrected_value(node)
|
|
78
80
|
case node.type
|
|
@@ -116,6 +118,17 @@ module RuboCop
|
|
|
116
118
|
end
|
|
117
119
|
end
|
|
118
120
|
|
|
121
|
+
def starts_interpolation_after_hash_sign?(begin_node, value)
|
|
122
|
+
source = processed_source.buffer.source
|
|
123
|
+
range = begin_node.source_range
|
|
124
|
+
# Removing an empty value puts the `#` right before what follows the interpolation.
|
|
125
|
+
following = "#{value}#{source[range.end_pos]}"
|
|
126
|
+
return false unless following.start_with?('{', '@', '$')
|
|
127
|
+
return false unless source[range.begin_pos - 1] == '#'
|
|
128
|
+
|
|
129
|
+
unescaped_hash_sign?(source[0...range.begin_pos])
|
|
130
|
+
end
|
|
131
|
+
|
|
119
132
|
def autocorrected_value_for_string(node)
|
|
120
133
|
return node.source.delete_prefix('"').delete_suffix('"') unless node.value.valid_encoding?
|
|
121
134
|
|
|
@@ -180,7 +193,9 @@ module RuboCop
|
|
|
180
193
|
end
|
|
181
194
|
|
|
182
195
|
def space_literal?(node)
|
|
183
|
-
|
|
196
|
+
# `String#blank?` misses Unicode spaces such as U+3000 that
|
|
197
|
+
# `Layout/TrailingWhitespace` treats as trailing whitespace.
|
|
198
|
+
node.str_type? && node.value.valid_encoding? && node.value.match?(/\A[[:space:]]*\z/)
|
|
184
199
|
end
|
|
185
200
|
|
|
186
201
|
def ends_heredoc_line?(node)
|
|
@@ -188,7 +203,8 @@ module RuboCop
|
|
|
188
203
|
return false unless grandparent&.dstr_type? && grandparent.heredoc?
|
|
189
204
|
|
|
190
205
|
line = processed_source.lines[node.last_line - 1]
|
|
191
|
-
|
|
206
|
+
|
|
207
|
+
line.size == node.parent.source_range.last_column
|
|
192
208
|
end
|
|
193
209
|
|
|
194
210
|
def in_array_percent_literal?(node)
|
|
@@ -198,6 +214,34 @@ module RuboCop
|
|
|
198
214
|
grandparent = parent.parent
|
|
199
215
|
grandparent&.array_type? && grandparent.percent_literal?
|
|
200
216
|
end
|
|
217
|
+
|
|
218
|
+
def escape_trailing_hash_sign(begin_node, value)
|
|
219
|
+
following = processed_source.buffer.source[begin_node.source_range.end_pos]
|
|
220
|
+
return value unless %w[{ @ $].include?(following) && unescaped_hash_sign?(value)
|
|
221
|
+
|
|
222
|
+
"#{value.delete_suffix('#')}\\#"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def unescaped_hash_sign?(text)
|
|
226
|
+
text.end_with?('#') && text.delete_suffix('#')[/\\*\z/].length.even?
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Each interpolation is checked against the original source, so correcting it in the
|
|
230
|
+
# same pass as a preceding one that leaves a `#` (or nothing) could join that `#` and
|
|
231
|
+
# a `{` from this one. It's left for the next iteration instead.
|
|
232
|
+
def follows_literal_interpolation?(begin_node)
|
|
233
|
+
previous = begin_node.left_sibling
|
|
234
|
+
return false unless previous&.begin_type? && offending?(previous.children.last)
|
|
235
|
+
|
|
236
|
+
value = correctable_value(previous, previous.children.last)
|
|
237
|
+
value && (value.empty? || value.end_with?('#'))
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def replacement(node, expanded_value)
|
|
241
|
+
return expanded_value unless node.str_type? && !node.value.valid_encoding?
|
|
242
|
+
|
|
243
|
+
node.source.delete_prefix('"').delete_suffix('"')
|
|
244
|
+
end
|
|
201
245
|
end
|
|
202
246
|
end
|
|
203
247
|
end
|