rubocop 1.79.2 → 1.87.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/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +185 -20
- data/config/obsoletion.yml +9 -0
- data/exe/rubocop +1 -8
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +30 -4
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/lsp.rb +1 -1
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli/command/show_cops.rb +2 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +35 -9
- data/lib/rubocop/comment_config.rb +59 -17
- data/lib/rubocop/config.rb +14 -10
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +37 -23
- data/lib/rubocop/config_loader_resolver.rb +20 -10
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_store.rb +7 -2
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/base.rb +8 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +26 -7
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/documentation.rb +2 -3
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +5 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +14 -7
- data/lib/rubocop/cop/layout/dot_position.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +26 -7
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +10 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- data/lib/rubocop/cop/layout/hash_alignment.rb +3 -6
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +123 -7
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -9
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +229 -39
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +4 -2
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +93 -11
- data/lib/rubocop/cop/lint/constant_resolution.rb +6 -6
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -12
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/else_layout.rb +19 -0
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
- data/lib/rubocop/cop/lint/empty_when.rb +8 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -9
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
- data/lib/rubocop/cop/lint/number_conversion.rb +6 -6
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -11
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- data/lib/rubocop/cop/lint/self_assignment.rb +15 -6
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/to_json.rb +12 -16
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +7 -5
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +48 -25
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +37 -11
- data/lib/rubocop/cop/lint/void.rb +39 -12
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +12 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +4 -6
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
- data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
- data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
- data/lib/rubocop/cop/mixin.rb +86 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_method.rb +32 -8
- data/lib/rubocop/cop/naming/predicate_prefix.rb +12 -12
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +17 -1
- data/lib/rubocop/cop/registry.rb +62 -38
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +15 -4
- data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
- data/lib/rubocop/cop/style/alias.rb +14 -2
- data/lib/rubocop/cop/style/and_or.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
- data/lib/rubocop/cop/style/array_intersect.rb +46 -12
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +5 -2
- data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
- data/lib/rubocop/cop/style/begin_block.rb +3 -1
- data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +27 -34
- data/lib/rubocop/cop/style/case_equality.rb +15 -13
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -2
- data/lib/rubocop/cop/style/collection_compact.rb +36 -16
- data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +8 -18
- data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
- data/lib/rubocop/cop/style/copyright.rb +22 -11
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/documentation.rb +6 -6
- data/lib/rubocop/cop/style/documentation_method.rb +8 -8
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -0
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_class_definition.rb +119 -0
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +0 -6
- data/lib/rubocop/cop/style/encoding.rb +7 -1
- data/lib/rubocop/cop/style/end_block.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +23 -5
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/file_write.rb +18 -16
- data/lib/rubocop/cop/style/float_division.rb +15 -1
- data/lib/rubocop/cop/style/for.rb +3 -0
- data/lib/rubocop/cop/style/format_string.rb +4 -3
- data/lib/rubocop/cop/style/format_string_token.rb +49 -5
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +27 -22
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
- data/lib/rubocop/cop/style/hash_lookup_method.rb +106 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
- data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
- data/lib/rubocop/cop/style/if_unless_modifier.rb +57 -17
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inline_comment.rb +4 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/lambda_call.rb +8 -8
- data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
- data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
- data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
- data/lib/rubocop/cop/style/not.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +21 -12
- data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +6 -2
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
- data/lib/rubocop/cop/style/proc.rb +3 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +37 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +6 -3
- data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
- data/lib/rubocop/cop/style/redundant_each.rb +3 -3
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +26 -5
- data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +36 -30
- data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
- data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +25 -8
- data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
- data/lib/rubocop/cop/style/select_by_range.rb +197 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +25 -7
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +12 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
- data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
- data/lib/rubocop/cop/style/super_arguments.rb +2 -2
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
- data/lib/rubocop/cop/team.rb +87 -36
- data/lib/rubocop/cop/util.rb +2 -3
- data/lib/rubocop/cop/utils/format_string.rb +10 -0
- data/lib/rubocop/cop/variable_force/branch.rb +30 -6
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +9 -7
- data/lib/rubocop/cops_documentation_generator.rb +4 -4
- data/lib/rubocop/directive_comment.rb +48 -4
- data/lib/rubocop/file_patterns.rb +9 -1
- data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +24 -7
- data/lib/rubocop/formatter/formatter_set.rb +2 -2
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
- data/lib/rubocop/formatter/tap_formatter.rb +5 -2
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +22 -21
- data/lib/rubocop/lsp/diagnostic.rb +18 -33
- data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
- data/lib/rubocop/lsp/routes.rb +43 -7
- data/lib/rubocop/lsp/runtime.rb +13 -4
- data/lib/rubocop/lsp/stdin_runner.rb +8 -17
- data/lib/rubocop/magic_comment.rb +20 -0
- data/lib/rubocop/mcp/server.rb +200 -0
- data/lib/rubocop/options.rb +35 -4
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/project_index_loader.rb +66 -0
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +10 -8
- data/lib/rubocop/result_cache.rb +61 -38
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/shared_contexts.rb +39 -5
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +134 -57
- data/lib/rubocop/server/cache.rb +6 -29
- data/lib/rubocop/server/core.rb +2 -0
- data/lib/rubocop/target_finder.rb +17 -10
- data/lib/rubocop/target_ruby.rb +31 -14
- data/lib/rubocop/version.rb +21 -3
- data/lib/rubocop.rb +28 -96
- data/lib/ruby_lsp/rubocop/addon.rb +23 -8
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +38 -9
|
@@ -37,6 +37,7 @@ module RuboCop
|
|
|
37
37
|
# array.sum(0)
|
|
38
38
|
# exit(true)
|
|
39
39
|
# exit!(false)
|
|
40
|
+
# string.to_i(10)
|
|
40
41
|
# string.split(" ")
|
|
41
42
|
# "first\nsecond".split(" ")
|
|
42
43
|
# string.chomp("\n")
|
|
@@ -49,6 +50,7 @@ module RuboCop
|
|
|
49
50
|
# array.sum
|
|
50
51
|
# exit
|
|
51
52
|
# exit!
|
|
53
|
+
# string.to_i
|
|
52
54
|
# string.split
|
|
53
55
|
# "first second".split
|
|
54
56
|
# string.chomp
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for the instantiation of array using redundant `Array` constructor.
|
|
7
|
-
# Autocorrect replaces
|
|
6
|
+
# Checks for the instantiation of an array using a redundant `Array` constructor.
|
|
7
|
+
# Autocorrect replaces it with an array literal which is the simplest and fastest.
|
|
8
8
|
#
|
|
9
9
|
# @example
|
|
10
10
|
#
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for redundant `begin` blocks.
|
|
7
|
-
#
|
|
8
|
-
#
|
|
6
|
+
# Checks for redundant `begin` blocks. A `begin` block is redundant
|
|
7
|
+
# when the `rescue`/`ensure` can be handled by the enclosing method
|
|
8
|
+
# or block definition directly, avoiding unnecessary indentation.
|
|
9
9
|
#
|
|
10
10
|
# @example
|
|
11
11
|
#
|
|
@@ -85,6 +85,29 @@ module RuboCop
|
|
|
85
85
|
end
|
|
86
86
|
alias on_defs on_def
|
|
87
87
|
|
|
88
|
+
def on_if(node)
|
|
89
|
+
return if node.modifier_form?
|
|
90
|
+
|
|
91
|
+
inspect_branches(node)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def on_case(node)
|
|
95
|
+
inspect_branches(node)
|
|
96
|
+
end
|
|
97
|
+
alias on_case_match on_case
|
|
98
|
+
|
|
99
|
+
def on_while(node)
|
|
100
|
+
return if node.modifier_form?
|
|
101
|
+
|
|
102
|
+
body = node.body
|
|
103
|
+
|
|
104
|
+
return unless body&.kwbegin_type?
|
|
105
|
+
return if body.rescue_node || body.ensure_node
|
|
106
|
+
|
|
107
|
+
register_offense(body)
|
|
108
|
+
end
|
|
109
|
+
alias on_until on_while
|
|
110
|
+
|
|
88
111
|
def on_block(node)
|
|
89
112
|
return if target_ruby_version < 2.5
|
|
90
113
|
return if node.send_node.lambda_literal?
|
|
@@ -180,6 +203,8 @@ module RuboCop
|
|
|
180
203
|
end
|
|
181
204
|
|
|
182
205
|
def begin_block_has_multiline_statements?(node)
|
|
206
|
+
return false unless node.parent
|
|
207
|
+
|
|
183
208
|
node.children.count >= 2
|
|
184
209
|
end
|
|
185
210
|
|
|
@@ -199,6 +224,15 @@ module RuboCop
|
|
|
199
224
|
def valid_begin_assignment?(node)
|
|
200
225
|
node.parent&.assignment? && !node.children.one?
|
|
201
226
|
end
|
|
227
|
+
|
|
228
|
+
def inspect_branches(node)
|
|
229
|
+
node.branches.each do |branch|
|
|
230
|
+
next unless branch&.kwbegin_type?
|
|
231
|
+
next if branch.rescue_node || branch.ensure_node
|
|
232
|
+
|
|
233
|
+
register_offense(branch)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
202
236
|
end
|
|
203
237
|
end
|
|
204
238
|
end
|
|
@@ -58,7 +58,10 @@ module RuboCop
|
|
|
58
58
|
# # good
|
|
59
59
|
# a.nil? || a
|
|
60
60
|
#
|
|
61
|
-
# @example AllowedMethods: ['nonzero?'] (default)
|
|
61
|
+
# @example AllowedMethods: ['infinite?', 'nonzero?'] (default)
|
|
62
|
+
# # good
|
|
63
|
+
# num.infinite? ? true : false
|
|
64
|
+
#
|
|
62
65
|
# # good
|
|
63
66
|
# num.nonzero? ? true : false
|
|
64
67
|
#
|
|
@@ -200,7 +203,7 @@ module RuboCop
|
|
|
200
203
|
end
|
|
201
204
|
|
|
202
205
|
def asgn_type?(node)
|
|
203
|
-
node.type?(:lvasgn, :ivasgn, :cvasgn, :gvasgn)
|
|
206
|
+
node.type?(:lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn)
|
|
204
207
|
end
|
|
205
208
|
|
|
206
209
|
def branches_have_method?(node)
|
|
@@ -247,7 +250,7 @@ module RuboCop
|
|
|
247
250
|
"#{if_branch.receiver.source} #{if_branch.method_name} (#{argument_source}"
|
|
248
251
|
elsif if_branch.true_type?
|
|
249
252
|
condition = if_branch.parent.condition
|
|
250
|
-
return condition.source if condition.arguments.empty?
|
|
253
|
+
return condition.source if condition.arguments.empty? || condition.parenthesized?
|
|
251
254
|
|
|
252
255
|
wrap_arguments_with_parens(condition)
|
|
253
256
|
else
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Avoid redundant `::` prefix on constant.
|
|
6
|
+
# Avoid redundant `::` prefix on a constant.
|
|
7
7
|
#
|
|
8
|
-
# How Ruby searches
|
|
8
|
+
# How Ruby searches constants is a bit complicated, and it can often be difficult to
|
|
9
9
|
# understand from the code whether the `::` is intended or not. Where `Module.nesting`
|
|
10
10
|
# is empty, there is no need to prepend `::`, so it would be nice to consistently
|
|
11
11
|
# avoid such meaningless `::` prefix to avoid confusion.
|
|
12
12
|
#
|
|
13
|
-
# NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled
|
|
14
|
-
# conflicting rules.
|
|
15
|
-
# `Lint/ConstantResolution` cop which is disabled by default.
|
|
13
|
+
# NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled,
|
|
14
|
+
# to prevent conflicting rules. This is because it respects user configurations
|
|
15
|
+
# that want to enable `Lint/ConstantResolution` cop which is disabled by default.
|
|
16
16
|
#
|
|
17
17
|
# @example
|
|
18
18
|
# # bad
|
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
|
64
64
|
def redundant_each_method(node)
|
|
65
65
|
return if node.last_argument&.block_pass_type?
|
|
66
66
|
|
|
67
|
-
if node.method?(:each) && !node.parent&.
|
|
67
|
+
if node.method?(:each) && !node.parent&.any_block_type?
|
|
68
68
|
ancestor_node = node.each_ancestor(:call).detect do |ancestor|
|
|
69
69
|
ancestor.receiver == node &&
|
|
70
70
|
(RESTRICT_ON_SEND.include?(ancestor.method_name) || ancestor.method?(:reverse_each))
|
|
@@ -74,8 +74,8 @@ module RuboCop
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
return unless (prev_method = node.children.first)
|
|
77
|
-
return if !prev_method.
|
|
78
|
-
prev_method.
|
|
77
|
+
return if !prev_method.call_type? || prev_method.parent.any_block_type? ||
|
|
78
|
+
prev_method.last_argument&.block_pass_type?
|
|
79
79
|
|
|
80
80
|
detected = prev_method.method_name.to_s.start_with?('each_') unless node.method?(:each)
|
|
81
81
|
|
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
|
52
52
|
${nil? basic_literal? const_type?})
|
|
53
53
|
PATTERN
|
|
54
54
|
|
|
55
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
55
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
56
56
|
redundant_fetch_block_candidate?(node) do |send, body|
|
|
57
57
|
return if should_not_check?(send, body)
|
|
58
58
|
|
|
@@ -89,7 +89,7 @@ module RuboCop
|
|
|
89
89
|
|
|
90
90
|
def on_send(node)
|
|
91
91
|
format_without_additional_args?(node) do |value|
|
|
92
|
-
replacement = value.source
|
|
92
|
+
replacement = escape_control_chars(value.source)
|
|
93
93
|
|
|
94
94
|
add_offense(node, message: message(node, replacement)) do |corrector|
|
|
95
95
|
corrector.replace(node, replacement)
|
|
@@ -134,6 +134,7 @@ module RuboCop
|
|
|
134
134
|
end
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
137
138
|
def all_fields_literal?(string, arguments)
|
|
138
139
|
count = 0
|
|
139
140
|
sequences = RuboCop::Cop::Utils::FormatString.new(string).format_sequences
|
|
@@ -141,29 +142,44 @@ module RuboCop
|
|
|
141
142
|
|
|
142
143
|
sequences.each do |sequence|
|
|
143
144
|
next if sequence.percent?
|
|
145
|
+
next if unknown_variable_width?(sequence, arguments)
|
|
144
146
|
|
|
145
147
|
hash = arguments.detect(&:hash_type?)
|
|
146
148
|
next unless (argument = find_argument(sequence, arguments, hash))
|
|
147
149
|
next unless matching_argument?(sequence, argument)
|
|
150
|
+
next if (sequence.width || sequence.precision) && argument.dstr_type?
|
|
148
151
|
|
|
149
152
|
count += 1
|
|
150
153
|
end
|
|
151
154
|
|
|
152
155
|
sequences.size == count
|
|
153
156
|
end
|
|
157
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
154
158
|
|
|
159
|
+
# If the sequence has a variable (`*`) width, it cannot be autocorrected
|
|
160
|
+
# if the width is not given as a numeric literal argument
|
|
161
|
+
def unknown_variable_width?(sequence, arguments)
|
|
162
|
+
return false unless sequence.variable_width?
|
|
163
|
+
|
|
164
|
+
argument = arguments[sequence.variable_width_argument_number - 1]
|
|
165
|
+
!numeric?(argument)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# rubocop:disable Metrics/AbcSize
|
|
155
169
|
def find_argument(sequence, arguments, hash)
|
|
156
170
|
if hash && (sequence.annotated? || sequence.template?)
|
|
157
171
|
find_hash_value_node(hash, sequence.name.to_sym).first
|
|
172
|
+
elsif sequence.variable_width?
|
|
173
|
+
# If the specifier contains `*`, the argument for the width can be ignored.
|
|
174
|
+
arguments.delete_at(sequence.variable_width_argument_number - 1)
|
|
175
|
+
arguments.shift
|
|
158
176
|
elsif sequence.arg_number
|
|
159
177
|
arguments[sequence.arg_number.to_i - 1]
|
|
160
178
|
else
|
|
161
|
-
# If the specifier contains `*`, the following arguments will be used
|
|
162
|
-
# to specify the width and can be ignored.
|
|
163
|
-
(sequence.arity - 1).times { arguments.shift }
|
|
164
179
|
arguments.shift
|
|
165
180
|
end
|
|
166
181
|
end
|
|
182
|
+
# rubocop:enable Metrics/AbcSize
|
|
167
183
|
|
|
168
184
|
def matching_argument?(sequence, argument)
|
|
169
185
|
# Template specifiers don't give a type, any acceptable literal type is ok.
|
|
@@ -214,7 +230,12 @@ module RuboCop
|
|
|
214
230
|
end
|
|
215
231
|
end
|
|
216
232
|
|
|
217
|
-
"#{start_delimiter}#{string}#{end_delimiter}"
|
|
233
|
+
"#{start_delimiter}#{escape_control_chars(string)}#{end_delimiter}"
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Escape any control characters in the string (eg. `\t` or `\n` become `\\t` or `\\n`)
|
|
237
|
+
def escape_control_chars(string)
|
|
238
|
+
string.gsub(/\p{Cc}/) { |s| s.dump[1..-2] }
|
|
218
239
|
end
|
|
219
240
|
|
|
220
241
|
def argument_values(arguments)
|
|
@@ -49,9 +49,10 @@ module RuboCop
|
|
|
49
49
|
def on_dstr(node)
|
|
50
50
|
return unless single_interpolation?(node)
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
embedded_node = node.children.first
|
|
53
|
+
return if use_match_pattern?(embedded_node)
|
|
54
54
|
|
|
55
|
+
add_offense(node) do |corrector|
|
|
55
56
|
if variable_interpolation?(embedded_node)
|
|
56
57
|
autocorrect_variable_interpolation(corrector, embedded_node, node)
|
|
57
58
|
elsif single_variable_interpolation?(embedded_node)
|
|
@@ -71,6 +72,14 @@ module RuboCop
|
|
|
71
72
|
!embedded_in_percent_array?(node)
|
|
72
73
|
end
|
|
73
74
|
|
|
75
|
+
def use_match_pattern?(node)
|
|
76
|
+
return false if target_ruby_version <= 2.7
|
|
77
|
+
|
|
78
|
+
node.children.any? do |child|
|
|
79
|
+
child.respond_to?(:match_pattern_type?) && child.match_pattern_type?
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
74
83
|
def single_variable_interpolation?(node)
|
|
75
84
|
return false unless node.children.one?
|
|
76
85
|
|
|
@@ -15,6 +15,9 @@ module RuboCop
|
|
|
15
15
|
# # bad
|
|
16
16
|
# "#{foo} bar".dup
|
|
17
17
|
#
|
|
18
|
+
# # bad
|
|
19
|
+
# String.new("#{foo} bar")
|
|
20
|
+
#
|
|
18
21
|
# # good
|
|
19
22
|
# "#{foo} bar"
|
|
20
23
|
#
|
|
@@ -25,19 +28,32 @@ module RuboCop
|
|
|
25
28
|
|
|
26
29
|
MSG = "Don't unfreeze interpolated strings as they are already unfrozen."
|
|
27
30
|
|
|
28
|
-
RESTRICT_ON_SEND = %i[+@ dup].freeze
|
|
29
|
-
|
|
30
31
|
minimum_target_ruby_version 3.0
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
# @!method redundant_unfreeze?(node)
|
|
34
|
+
def_node_matcher :redundant_unfreeze?, <<~PATTERN
|
|
35
|
+
{
|
|
36
|
+
(send dstr_type? {:+@ :dup})
|
|
37
|
+
(send (const nil? :String) :new dstr_type?)
|
|
38
|
+
}
|
|
39
|
+
PATTERN
|
|
40
|
+
|
|
41
|
+
def on_dstr(node)
|
|
42
|
+
return if uninterpolated_string?(node) || uninterpolated_heredoc?(node)
|
|
43
|
+
return unless redundant_unfreeze?(node.parent)
|
|
44
|
+
|
|
45
|
+
add_offense(offense_range(node.parent)) do |corrector|
|
|
46
|
+
corrector.replace(node.parent, node.source)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
37
51
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
52
|
+
def offense_range(node)
|
|
53
|
+
if node.method?(:new)
|
|
54
|
+
node.source_range.begin.join(node.loc.selector)
|
|
55
|
+
else
|
|
56
|
+
node.loc.selector
|
|
41
57
|
end
|
|
42
58
|
end
|
|
43
59
|
end
|
|
@@ -82,6 +82,7 @@ module RuboCop
|
|
|
82
82
|
tIDENTIFIER kBREAK kNEXT kRETURN kSUPER kYIELD
|
|
83
83
|
].freeze
|
|
84
84
|
ARITHMETIC_OPERATOR_TOKENS = %i[tDIVIDE tDSTAR tMINUS tPERCENT tPLUS tSTAR2].freeze
|
|
85
|
+
STRING_LITERAL_BEGIN_TOKENS = %i[tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tSYMBEG].freeze
|
|
85
86
|
|
|
86
87
|
def on_new_investigation
|
|
87
88
|
return unless processed_source.ast
|
|
@@ -105,6 +106,7 @@ module RuboCop
|
|
|
105
106
|
string_concatenation?(range.source_line) ||
|
|
106
107
|
start_with_arithmetic_operator?(range) ||
|
|
107
108
|
inside_string_literal_or_method_with_argument?(range) ||
|
|
109
|
+
inside_string_literal_with_interpolation?(range) ||
|
|
108
110
|
leading_dot_method_chain_with_blank_line?(range)
|
|
109
111
|
end
|
|
110
112
|
|
|
@@ -132,6 +134,20 @@ module RuboCop
|
|
|
132
134
|
end
|
|
133
135
|
end
|
|
134
136
|
|
|
137
|
+
def inside_string_literal_with_interpolation?(range)
|
|
138
|
+
string_depth = 0
|
|
139
|
+
processed_source.tokens.each do |token|
|
|
140
|
+
break if token.pos.begin_pos >= range.begin_pos
|
|
141
|
+
|
|
142
|
+
if STRING_LITERAL_BEGIN_TOKENS.include?(token.type)
|
|
143
|
+
string_depth += 1
|
|
144
|
+
elsif token.type == :tSTRING_END
|
|
145
|
+
string_depth -= 1
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
string_depth.positive?
|
|
149
|
+
end
|
|
150
|
+
|
|
135
151
|
def leading_dot_method_chain_with_blank_line?(range)
|
|
136
152
|
return false unless range.source_line.strip.start_with?('.', '&.')
|
|
137
153
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Identifies places where `max_by { ... }`, `min_by { ... }`, or
|
|
7
|
+
# `minmax_by { ... }` can be replaced by `max`, `min`, or `minmax`.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# # bad
|
|
11
|
+
# array.max_by { |x| x }
|
|
12
|
+
# array.min_by { |x| x }
|
|
13
|
+
# array.minmax_by { |x| x }
|
|
14
|
+
#
|
|
15
|
+
# # good
|
|
16
|
+
# array.max
|
|
17
|
+
# array.min
|
|
18
|
+
# array.minmax
|
|
19
|
+
class RedundantMinMaxBy < Base
|
|
20
|
+
include RangeHelp
|
|
21
|
+
extend AutoCorrector
|
|
22
|
+
|
|
23
|
+
MSG_BLOCK = 'Use `%<replacement>s` instead of `%<original>s { |%<var>s| %<var>s }`.'
|
|
24
|
+
MSG_NUMBLOCK = 'Use `%<replacement>s` instead of `%<original>s { _1 }`.'
|
|
25
|
+
MSG_ITBLOCK = 'Use `%<replacement>s` instead of `%<original>s { it }`.'
|
|
26
|
+
|
|
27
|
+
REPLACEMENTS = { max_by: 'max', min_by: 'min', minmax_by: 'minmax' }.freeze
|
|
28
|
+
|
|
29
|
+
def on_block(node)
|
|
30
|
+
redundant_minmax_by_block(node) do |send, var_name|
|
|
31
|
+
register_offense(send, node, message_block(send, var_name))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def on_numblock(node)
|
|
36
|
+
redundant_minmax_by_numblock(node) do |send|
|
|
37
|
+
register_offense(send, node, message_numblock(send))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def on_itblock(node)
|
|
42
|
+
redundant_minmax_by_itblock(node) do |send|
|
|
43
|
+
register_offense(send, node, message_itblock(send))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
# @!method redundant_minmax_by_block(node)
|
|
50
|
+
def_node_matcher :redundant_minmax_by_block, <<~PATTERN
|
|
51
|
+
(block $(call _ {:max_by :min_by :minmax_by}) (args (arg $_x)) (lvar _x))
|
|
52
|
+
PATTERN
|
|
53
|
+
|
|
54
|
+
# @!method redundant_minmax_by_numblock(node)
|
|
55
|
+
def_node_matcher :redundant_minmax_by_numblock, <<~PATTERN
|
|
56
|
+
(numblock $(call _ {:max_by :min_by :minmax_by}) 1 (lvar :_1))
|
|
57
|
+
PATTERN
|
|
58
|
+
|
|
59
|
+
# @!method redundant_minmax_by_itblock(node)
|
|
60
|
+
def_node_matcher :redundant_minmax_by_itblock, <<~PATTERN
|
|
61
|
+
(itblock $(call _ {:max_by :min_by :minmax_by}) _ (lvar :it))
|
|
62
|
+
PATTERN
|
|
63
|
+
|
|
64
|
+
def register_offense(send, node, message)
|
|
65
|
+
range = offense_range(send, node)
|
|
66
|
+
|
|
67
|
+
add_offense(range, message: message) do |corrector|
|
|
68
|
+
corrector.replace(range, REPLACEMENTS[send.method_name])
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def offense_range(send, node)
|
|
73
|
+
range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def message_block(send, var_name)
|
|
77
|
+
method = send.method_name
|
|
78
|
+
format(MSG_BLOCK, replacement: REPLACEMENTS[method], original: method, var: var_name)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def message_numblock(send)
|
|
82
|
+
method = send.method_name
|
|
83
|
+
format(MSG_NUMBLOCK, replacement: REPLACEMENTS[method], original: method)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def message_itblock(send)
|
|
87
|
+
method = send.method_name
|
|
88
|
+
format(MSG_ITBLOCK, replacement: REPLACEMENTS[method], original: method)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -24,9 +24,6 @@ module RuboCop
|
|
|
24
24
|
(send `{(send _recv _msg) str array hash const #variable?} :[] ...)
|
|
25
25
|
PATTERN
|
|
26
26
|
|
|
27
|
-
# @!method method_node_and_args(node)
|
|
28
|
-
def_node_matcher :method_node_and_args, '$(call _recv _msg $...)'
|
|
29
|
-
|
|
30
27
|
# @!method rescue?(node)
|
|
31
28
|
def_node_matcher :rescue?, '{^resbody ^^resbody}'
|
|
32
29
|
|
|
@@ -117,7 +114,7 @@ module RuboCop
|
|
|
117
114
|
def first_arg_begins_with_hash_literal?(node)
|
|
118
115
|
# Don't flag `method ({key: value})` or `method ({key: value}.method)`
|
|
119
116
|
hash_literal = method_chain_begins_with_hash_literal(node.children.first)
|
|
120
|
-
if (root_method = node.each_ancestor(:
|
|
117
|
+
if (root_method = node.each_ancestor(:call).to_a.last)
|
|
121
118
|
parenthesized = root_method.parenthesized_call?
|
|
122
119
|
end
|
|
123
120
|
hash_literal && first_argument?(node) && !parentheses?(hash_literal) && !parenthesized
|
|
@@ -142,6 +139,8 @@ module RuboCop
|
|
|
142
139
|
node = begin_node.children.first
|
|
143
140
|
|
|
144
141
|
if (message = find_offense_message(begin_node, node))
|
|
142
|
+
return offense(begin_node, message) if message == 'block body'
|
|
143
|
+
|
|
145
144
|
if node.range_type? && !argument_of_parenthesized_method_call?(begin_node, node)
|
|
146
145
|
begin_node = begin_node.parent
|
|
147
146
|
end
|
|
@@ -158,6 +157,8 @@ module RuboCop
|
|
|
158
157
|
return 'a literal' if node.literal? && disallowed_literal?(begin_node, node)
|
|
159
158
|
return 'a variable' if node.variable?
|
|
160
159
|
return 'a constant' if node.const_type?
|
|
160
|
+
return 'block body' if begin_node.parent&.any_block_type? || body_range?(begin_node, node)
|
|
161
|
+
|
|
161
162
|
if node.assignment? && (begin_node.parent.nil? || begin_node.parent.begin_type?)
|
|
162
163
|
return 'an assignment'
|
|
163
164
|
end
|
|
@@ -205,6 +206,7 @@ module RuboCop
|
|
|
205
206
|
return false unless node.rescue_type?
|
|
206
207
|
return false unless (parent = begin_node.parent)
|
|
207
208
|
return false if parent.if_type? && parent.ternary?
|
|
209
|
+
return false if parent.conditional? && parent.condition == begin_node
|
|
208
210
|
|
|
209
211
|
!parent.type?(:call, :array, :pair)
|
|
210
212
|
end
|
|
@@ -220,7 +222,7 @@ module RuboCop
|
|
|
220
222
|
end
|
|
221
223
|
|
|
222
224
|
def call_node?(node)
|
|
223
|
-
node.call_type? || (node.any_block_type? && !node.lambda_or_proc?)
|
|
225
|
+
node.call_type? || (node.any_block_type? && node.braces? && !node.lambda_or_proc?)
|
|
224
226
|
end
|
|
225
227
|
|
|
226
228
|
def check_send(begin_node, node)
|
|
@@ -228,7 +230,7 @@ module RuboCop
|
|
|
228
230
|
|
|
229
231
|
return check_unary(begin_node, node) if node.unary_operation?
|
|
230
232
|
|
|
231
|
-
return unless method_call_with_redundant_parentheses?(node)
|
|
233
|
+
return unless method_call_with_redundant_parentheses?(begin_node, node)
|
|
232
234
|
return if call_chain_starts_with_int?(begin_node, node) ||
|
|
233
235
|
do_end_block_in_method_chain?(begin_node, node)
|
|
234
236
|
|
|
@@ -239,8 +241,7 @@ module RuboCop
|
|
|
239
241
|
return if begin_node.chained?
|
|
240
242
|
|
|
241
243
|
node = node.children.first while suspect_unary?(node)
|
|
242
|
-
|
|
243
|
-
return if node.send_type? && !method_call_with_redundant_parentheses?(node)
|
|
244
|
+
return unless method_call_with_redundant_parentheses?(begin_node, node)
|
|
244
245
|
|
|
245
246
|
offense(begin_node, 'a unary operation')
|
|
246
247
|
end
|
|
@@ -269,6 +270,18 @@ module RuboCop
|
|
|
269
270
|
end
|
|
270
271
|
end
|
|
271
272
|
|
|
273
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
274
|
+
def body_range?(begin_node, node)
|
|
275
|
+
return false if begin_node.chained?
|
|
276
|
+
return false unless node.range_type?
|
|
277
|
+
return false unless (parent = begin_node.parent)
|
|
278
|
+
return false unless parent.begin_type?
|
|
279
|
+
|
|
280
|
+
(node.begin.nil? && begin_node == parent.children.first) ||
|
|
281
|
+
(node.end.nil? && begin_node == parent.children.last)
|
|
282
|
+
end
|
|
283
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
284
|
+
|
|
272
285
|
def disallowed_one_line_pattern_matching?(begin_node, node)
|
|
273
286
|
if (parent = begin_node.parent)
|
|
274
287
|
return false if parent.any_def_type? && parent.endless?
|
|
@@ -302,13 +315,19 @@ module RuboCop
|
|
|
302
315
|
end
|
|
303
316
|
end
|
|
304
317
|
|
|
305
|
-
def method_call_with_redundant_parentheses?(node)
|
|
306
|
-
return false unless node.
|
|
318
|
+
def method_call_with_redundant_parentheses?(begin_node, node)
|
|
319
|
+
return false unless node.type?(:call, :super, :yield, :defined?)
|
|
307
320
|
return false if node.prefix_not?
|
|
321
|
+
return true if singular_parenthesized_parent?(begin_node)
|
|
322
|
+
|
|
323
|
+
node.arguments.empty? || parentheses?(node) || square_brackets?(node)
|
|
324
|
+
end
|
|
308
325
|
|
|
309
|
-
|
|
326
|
+
def singular_parenthesized_parent?(begin_node)
|
|
327
|
+
return true unless (parent = begin_node.parent)
|
|
328
|
+
return false if parent.type?(:splat, :kwsplat)
|
|
310
329
|
|
|
311
|
-
|
|
330
|
+
parent.children.one?
|
|
312
331
|
end
|
|
313
332
|
|
|
314
333
|
def only_begin_arg?(args)
|
|
@@ -316,28 +335,15 @@ module RuboCop
|
|
|
316
335
|
end
|
|
317
336
|
|
|
318
337
|
def first_argument?(node)
|
|
319
|
-
if
|
|
320
|
-
first_super_argument?(node) ||
|
|
321
|
-
first_yield_argument?(node)
|
|
322
|
-
return true
|
|
323
|
-
end
|
|
338
|
+
return true if first_call_argument?(node)
|
|
324
339
|
|
|
325
340
|
node.each_ancestor.any? { |ancestor| first_argument?(ancestor) }
|
|
326
341
|
end
|
|
327
342
|
|
|
328
|
-
# @!method
|
|
329
|
-
def_node_matcher :
|
|
330
|
-
^(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
# @!method first_super_argument?(node)
|
|
334
|
-
def_node_matcher :first_super_argument?, <<~PATTERN
|
|
335
|
-
^(super equal?(%0) ...)
|
|
336
|
-
PATTERN
|
|
337
|
-
|
|
338
|
-
# @!method first_yield_argument?(node)
|
|
339
|
-
def_node_matcher :first_yield_argument?, <<~PATTERN
|
|
340
|
-
^(yield equal?(%0) ...)
|
|
343
|
+
# @!method first_call_argument?(node)
|
|
344
|
+
def_node_matcher :first_call_argument?, <<~PATTERN
|
|
345
|
+
{^(call _ _ equal?(%0) ...)
|
|
346
|
+
^({super yield} equal?(%0) ...)}
|
|
341
347
|
PATTERN
|
|
342
348
|
|
|
343
349
|
def call_chain_starts_with_int?(begin_node, send_node)
|
|
@@ -80,8 +80,7 @@ module RuboCop
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
def string_literal?(node)
|
|
83
|
-
node.loc
|
|
84
|
-
node.loc.begin && node.loc.end
|
|
83
|
+
node.loc?(:begin) && node.loc?(:end)
|
|
85
84
|
end
|
|
86
85
|
|
|
87
86
|
def start_with_percent_q_variant?(string)
|
|
@@ -91,7 +90,10 @@ module RuboCop
|
|
|
91
90
|
def acceptable_q?(node)
|
|
92
91
|
src = node.source
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
# If the string contains interpolation-like syntax and would be
|
|
94
|
+
# converted to a double-quoted string (because it contains single
|
|
95
|
+
# quotes), the replacement would activate interpolation.
|
|
96
|
+
return true if STRING_INTERPOLATION_REGEXP.match?(src) && src.include?(SINGLE_QUOTE)
|
|
95
97
|
|
|
96
98
|
src.scan(/\\./).any?(ESCAPED_NON_BACKSLASH)
|
|
97
99
|
end
|
|
@@ -66,6 +66,7 @@ module RuboCop
|
|
|
66
66
|
DETERMINISTIC_REGEX.match?(regexp_node.source)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# rubocop:disable Metrics/MethodLength
|
|
69
70
|
def preferred_argument(regexp_node)
|
|
70
71
|
new_argument = replacement(regexp_node)
|
|
71
72
|
|
|
@@ -73,6 +74,13 @@ module RuboCop
|
|
|
73
74
|
new_argument.gsub!("'", "\\\\'")
|
|
74
75
|
new_argument.gsub!('\"', '"')
|
|
75
76
|
quote = "'"
|
|
77
|
+
elsif new_argument.include?("\\'")
|
|
78
|
+
# Add a backslash before single quotes preceded by an even number of backslashes.
|
|
79
|
+
# An even number (including zero) of backslashes before a quote means the quote itself
|
|
80
|
+
# is not escaped.
|
|
81
|
+
# Otherwise an odd number means the quote is already escaped so this doesn't touch it.
|
|
82
|
+
new_argument.gsub!(/(?<!\\)((?:\\\\)*)'/) { "#{::Regexp.last_match(1)}\\'" }
|
|
83
|
+
quote = "'"
|
|
76
84
|
elsif new_argument.include?('\'')
|
|
77
85
|
new_argument.gsub!("'", "\\\\'")
|
|
78
86
|
quote = "'"
|
|
@@ -84,6 +92,7 @@ module RuboCop
|
|
|
84
92
|
|
|
85
93
|
"#{quote}#{new_argument}#{quote}"
|
|
86
94
|
end
|
|
95
|
+
# rubocop:enable Metrics/MethodLength
|
|
87
96
|
|
|
88
97
|
def replacement(regexp_node)
|
|
89
98
|
regexp_content = regexp_node.content
|