rubocop 1.79.2 → 1.88.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 +259 -90
- data/config/obsoletion.yml +30 -1
- data/exe/rubocop +1 -8
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +36 -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 +25 -4
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -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/redundant_let_rubocop_config_new.rb +5 -3
- 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/block_alignment.rb +41 -4
- 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_assignment.rb +1 -11
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +1 -10
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +45 -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 -3
- data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
- 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 +4 -4
- 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/ensure_return.rb +19 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -2
- data/lib/rubocop/cop/lint/float_comparison.rb +2 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +25 -5
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +9 -12
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -10
- 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 +20 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +19 -10
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +3 -0
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/raise_exception.rb +1 -1
- data/lib/rubocop/cop/lint/rand_one.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -10
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +6 -12
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +15 -4
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +36 -12
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +12 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +10 -3
- data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_with_object.rb +5 -0
- data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
- data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +2 -1
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +18 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
- data/lib/rubocop/cop/lint/script_permission.rb +5 -1
- data/lib/rubocop/cop/lint/self_assignment.rb +39 -7
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
- 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/shadowing_outer_local_variable.rb +14 -0
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +12 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +21 -4
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +28 -1
- data/lib/rubocop/cop/lint/to_json.rb +12 -16
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +4 -2
- 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 +53 -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 +8 -4
- data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -1
- data/lib/rubocop/cop/lint/useless_times.rb +22 -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/collection_literal_length.rb +1 -1
- 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 +15 -3
- data/lib/rubocop/cop/style/and_or.rb +2 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
- data/lib/rubocop/cop/style/array_first_last.rb +12 -1
- data/lib/rubocop/cop/style/array_intersect.rb +50 -12
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +50 -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 +39 -32
- data/lib/rubocop/cop/style/case_equality.rb +29 -15
- 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/class_equality_comparison.rb +21 -13
- data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -5
- data/lib/rubocop/cop/style/collection_compact.rb +36 -16
- data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
- data/lib/rubocop/cop/style/combinable_loops.rb +5 -0
- data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +7 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +14 -19
- data/lib/rubocop/cop/style/constant_visibility.rb +20 -12
- data/lib/rubocop/cop/style/copyright.rb +22 -11
- data/lib/rubocop/cop/style/date_time.rb +4 -4
- data/lib/rubocop/cop/style/dig_chain.rb +5 -0
- 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/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/file_write.rb +21 -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_slice.rb +16 -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 +58 -18
- 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 +106 -12
- 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 +14 -3
- 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 +27 -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 +41 -8
- 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_do.rb +7 -0
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/word_array.rb +1 -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/style/zero_length_predicate.rb +6 -3
- 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 +38 -14
- 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 +8 -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
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for `each_with_object`, `inject`, and `reduce` calls that build
|
|
7
|
+
# a hash from an enumerable, where `to_h` with a block could be used instead.
|
|
8
|
+
#
|
|
9
|
+
# This cop complements `Style/HashTransformKeys` and `Style/HashTransformValues`,
|
|
10
|
+
# which handle hash-to-hash transformations with destructured key-value pairs.
|
|
11
|
+
# This cop targets the case where a hash is built from individual elements
|
|
12
|
+
# (non-destructured block parameter).
|
|
13
|
+
#
|
|
14
|
+
# @safety
|
|
15
|
+
# This cop is unsafe because it cannot guarantee that the receiver
|
|
16
|
+
# is an `Enumerable` by static analysis, so the correction may
|
|
17
|
+
# not be actually equivalent. Additionally, `each_with_object` returns
|
|
18
|
+
# the hash object while `to_h` returns a new hash, which could matter
|
|
19
|
+
# if the hash object identity is important.
|
|
20
|
+
#
|
|
21
|
+
# @example
|
|
22
|
+
# # bad
|
|
23
|
+
# array.each_with_object({}) { |elem, hash| hash[elem.id] = elem.name }
|
|
24
|
+
#
|
|
25
|
+
# # bad
|
|
26
|
+
# array.inject({}) { |hash, elem| hash[elem.id] = elem.name; hash }
|
|
27
|
+
#
|
|
28
|
+
# # bad
|
|
29
|
+
# array.reduce({}) { |hash, elem| hash[elem.id] = elem.name; hash }
|
|
30
|
+
#
|
|
31
|
+
# # bad
|
|
32
|
+
# array.each_with_object({}) { |elem, hash| hash[elem] = elem.to_s }
|
|
33
|
+
#
|
|
34
|
+
# # good
|
|
35
|
+
# array.to_h { |elem| [elem.id, elem.name] }
|
|
36
|
+
#
|
|
37
|
+
# # good
|
|
38
|
+
# array.to_h { |elem| [elem, elem.to_s] }
|
|
39
|
+
#
|
|
40
|
+
class ReduceToHash < Base
|
|
41
|
+
extend AutoCorrector
|
|
42
|
+
extend TargetRubyVersion
|
|
43
|
+
include RangeHelp
|
|
44
|
+
|
|
45
|
+
minimum_target_ruby_version 2.6
|
|
46
|
+
|
|
47
|
+
MSG = 'Use `to_h { ... }` instead of `%<method>s`.'
|
|
48
|
+
RESTRICT_ON_SEND = %i[each_with_object inject reduce].freeze
|
|
49
|
+
|
|
50
|
+
# each_with_object({}) { |elem, hash| hash[key] = value }
|
|
51
|
+
# @!method each_with_object_to_hash?(node)
|
|
52
|
+
def_node_matcher :each_with_object_to_hash?, <<~PATTERN
|
|
53
|
+
{
|
|
54
|
+
(block
|
|
55
|
+
(call _ :each_with_object (hash))
|
|
56
|
+
(args (arg _elem) (arg _hash))
|
|
57
|
+
(send (lvar _hash) :[]= $_key $_value))
|
|
58
|
+
(numblock
|
|
59
|
+
(call _ :each_with_object (hash))
|
|
60
|
+
2
|
|
61
|
+
(send (lvar :_2) :[]= $_key $_value))
|
|
62
|
+
}
|
|
63
|
+
PATTERN
|
|
64
|
+
|
|
65
|
+
# inject/reduce({}) { |hash, elem| hash[key] = value; hash }
|
|
66
|
+
# @!method inject_to_hash?(node)
|
|
67
|
+
def_node_matcher :inject_to_hash?, <<~PATTERN
|
|
68
|
+
{
|
|
69
|
+
(block
|
|
70
|
+
(call _ {:inject :reduce} (hash))
|
|
71
|
+
(args (arg _hash) (arg _elem))
|
|
72
|
+
(begin
|
|
73
|
+
(send (lvar _hash) :[]= $_key $_value)
|
|
74
|
+
(lvar _hash)))
|
|
75
|
+
(numblock
|
|
76
|
+
(call _ {:inject :reduce} (hash))
|
|
77
|
+
2
|
|
78
|
+
(begin
|
|
79
|
+
(send (lvar :_1) :[]= $_key $_value)
|
|
80
|
+
(lvar :_1)))
|
|
81
|
+
}
|
|
82
|
+
PATTERN
|
|
83
|
+
|
|
84
|
+
def on_send(node)
|
|
85
|
+
block_node = node.block_node
|
|
86
|
+
return unless block_node
|
|
87
|
+
|
|
88
|
+
check_offense(node, block_node)
|
|
89
|
+
end
|
|
90
|
+
alias on_csend on_send
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def check_offense(node, block_node)
|
|
95
|
+
key, value = if node.method?(:each_with_object)
|
|
96
|
+
each_with_object_to_hash?(block_node)
|
|
97
|
+
else
|
|
98
|
+
inject_to_hash?(block_node)
|
|
99
|
+
end
|
|
100
|
+
return unless key
|
|
101
|
+
return if accumulator_used_in_expressions?(block_node, key, value)
|
|
102
|
+
return if nested_match?(key) || nested_match?(value)
|
|
103
|
+
|
|
104
|
+
register_offense(node, block_node, key, value)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def accumulator_used_in_expressions?(block_node, key, value)
|
|
108
|
+
acc_name = accumulator_name(block_node)
|
|
109
|
+
references_variable?(key, acc_name) || references_variable?(value, acc_name)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def nested_match?(node)
|
|
113
|
+
node.each_node(:call).any? do |send_node|
|
|
114
|
+
next false unless RESTRICT_ON_SEND.include?(send_node.method_name)
|
|
115
|
+
|
|
116
|
+
inner_block = send_node.block_node
|
|
117
|
+
next false unless inner_block
|
|
118
|
+
|
|
119
|
+
if send_node.method?(:each_with_object)
|
|
120
|
+
each_with_object_to_hash?(inner_block)
|
|
121
|
+
else
|
|
122
|
+
inject_to_hash?(inner_block)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def accumulator_name(block_node)
|
|
128
|
+
index = block_node.method?(:each_with_object) ? 1 : 0
|
|
129
|
+
block_node.argument_list[index].name
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def references_variable?(node, name)
|
|
133
|
+
node.each_node(:lvar).any? { |lvar| lvar.children.first == name }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def register_offense(send_node, block_node, key_expr, value_expr)
|
|
137
|
+
message = format(MSG, method: send_node.method_name)
|
|
138
|
+
|
|
139
|
+
add_offense(send_node.loc.selector, message: message) do |corrector|
|
|
140
|
+
corrector.replace(
|
|
141
|
+
replacement_range(send_node, block_node),
|
|
142
|
+
replacement(block_node, key_expr, value_expr)
|
|
143
|
+
)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def replacement(block_node, key_expr, value_expr)
|
|
148
|
+
key_source = adjusted_source(key_expr, block_node)
|
|
149
|
+
value_source = adjusted_source(value_expr, block_node)
|
|
150
|
+
body = "[#{key_source}, #{value_source}]"
|
|
151
|
+
|
|
152
|
+
if block_node.numblock_type?
|
|
153
|
+
block_node.braces? ? "to_h { #{body} }" : do_end_replacement(block_node, body)
|
|
154
|
+
else
|
|
155
|
+
named_block_replacement(block_node, body)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def named_block_replacement(block_node, body)
|
|
160
|
+
arg = element_arg_source(block_node)
|
|
161
|
+
if block_node.braces?
|
|
162
|
+
"to_h { |#{arg}| #{body} }"
|
|
163
|
+
else
|
|
164
|
+
do_end_replacement(block_node, body, arg)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def do_end_replacement(block_node, body, arg = nil)
|
|
169
|
+
args = arg ? " |#{arg}|" : ''
|
|
170
|
+
"to_h do#{args}\n#{indent(block_node)} #{body}\n#{indent(block_node)}end"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def replacement_range(send_node, block_node)
|
|
174
|
+
range_between(send_node.loc.selector.begin_pos, block_node.source_range.end_pos)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def element_arg_source(block_node)
|
|
178
|
+
if block_node.method?(:each_with_object)
|
|
179
|
+
block_node.first_argument.source
|
|
180
|
+
else
|
|
181
|
+
block_node.arguments[1].source
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def adjusted_source(expr_node, block_node)
|
|
186
|
+
source = expr_node.source
|
|
187
|
+
return source unless block_node.numblock_type?
|
|
188
|
+
return source if block_node.method?(:each_with_object)
|
|
189
|
+
|
|
190
|
+
# For inject/reduce numblocks, _2 is the element (becomes _1)
|
|
191
|
+
source.gsub('_2', '_1')
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def indent(node)
|
|
195
|
+
' ' * node.source_range.column
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -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)
|
|
@@ -108,6 +108,7 @@ module RuboCop
|
|
|
108
108
|
|
|
109
109
|
def detect_unnecessary_fields(node)
|
|
110
110
|
return unless node.first_argument&.str_type?
|
|
111
|
+
return if node.first_argument.heredoc?
|
|
111
112
|
|
|
112
113
|
string = node.first_argument.value
|
|
113
114
|
arguments = node.arguments[1..]
|
|
@@ -134,6 +135,7 @@ module RuboCop
|
|
|
134
135
|
end
|
|
135
136
|
end
|
|
136
137
|
|
|
138
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
137
139
|
def all_fields_literal?(string, arguments)
|
|
138
140
|
count = 0
|
|
139
141
|
sequences = RuboCop::Cop::Utils::FormatString.new(string).format_sequences
|
|
@@ -141,29 +143,44 @@ module RuboCop
|
|
|
141
143
|
|
|
142
144
|
sequences.each do |sequence|
|
|
143
145
|
next if sequence.percent?
|
|
146
|
+
next if unknown_variable_width?(sequence, arguments)
|
|
144
147
|
|
|
145
148
|
hash = arguments.detect(&:hash_type?)
|
|
146
149
|
next unless (argument = find_argument(sequence, arguments, hash))
|
|
147
150
|
next unless matching_argument?(sequence, argument)
|
|
151
|
+
next if (sequence.width || sequence.precision) && argument.dstr_type?
|
|
148
152
|
|
|
149
153
|
count += 1
|
|
150
154
|
end
|
|
151
155
|
|
|
152
156
|
sequences.size == count
|
|
153
157
|
end
|
|
158
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
154
159
|
|
|
160
|
+
# If the sequence has a variable (`*`) width, it cannot be autocorrected
|
|
161
|
+
# if the width is not given as a numeric literal argument
|
|
162
|
+
def unknown_variable_width?(sequence, arguments)
|
|
163
|
+
return false unless sequence.variable_width?
|
|
164
|
+
|
|
165
|
+
argument = arguments[sequence.variable_width_argument_number - 1]
|
|
166
|
+
!numeric?(argument)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# rubocop:disable Metrics/AbcSize
|
|
155
170
|
def find_argument(sequence, arguments, hash)
|
|
156
171
|
if hash && (sequence.annotated? || sequence.template?)
|
|
157
172
|
find_hash_value_node(hash, sequence.name.to_sym).first
|
|
173
|
+
elsif sequence.variable_width?
|
|
174
|
+
# If the specifier contains `*`, the argument for the width can be ignored.
|
|
175
|
+
arguments.delete_at(sequence.variable_width_argument_number - 1)
|
|
176
|
+
arguments.shift
|
|
158
177
|
elsif sequence.arg_number
|
|
159
178
|
arguments[sequence.arg_number.to_i - 1]
|
|
160
179
|
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
180
|
arguments.shift
|
|
165
181
|
end
|
|
166
182
|
end
|
|
183
|
+
# rubocop:enable Metrics/AbcSize
|
|
167
184
|
|
|
168
185
|
def matching_argument?(sequence, argument)
|
|
169
186
|
# Template specifiers don't give a type, any acceptable literal type is ok.
|
|
@@ -214,7 +231,12 @@ module RuboCop
|
|
|
214
231
|
end
|
|
215
232
|
end
|
|
216
233
|
|
|
217
|
-
"#{start_delimiter}#{string}#{end_delimiter}"
|
|
234
|
+
"#{start_delimiter}#{escape_control_chars(string)}#{end_delimiter}"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Escape any control characters in the string (eg. `\t` or `\n` become `\\t` or `\\n`)
|
|
238
|
+
def escape_control_chars(string)
|
|
239
|
+
string.gsub(/\p{Cc}/) { |s| s.dump[1..-2] }
|
|
218
240
|
end
|
|
219
241
|
|
|
220
242
|
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
|