rubocop 1.71.1 → 1.88.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +23 -19
- data/config/default.yml +513 -149
- data/config/internal_affairs.yml +20 -0
- data/config/obsoletion.yml +38 -4
- 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 +8 -2
- data/lib/rubocop/cli.rb +48 -11
- data/lib/rubocop/comment_config.rb +60 -18
- data/lib/rubocop/config.rb +53 -16
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +65 -49
- data/lib/rubocop/config_loader_resolver.rb +44 -19
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +6 -3
- data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
- data/lib/rubocop/config_obsoletion.rb +46 -2
- data/lib/rubocop/config_store.rb +7 -2
- data/lib/rubocop/config_validator.rb +7 -6
- data/lib/rubocop/cop/autocorrect_logic.rb +27 -14
- data/lib/rubocop/cop/base.rb +38 -12
- data/lib/rubocop/cop/bundler/gem_comment.rb +5 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -3
- data/lib/rubocop/cop/commissioner.rb +13 -11
- 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/each_to_for_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -1
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +36 -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/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +49 -17
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -3
- data/lib/rubocop/cop/gemspec/require_mfa.rb +22 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
- data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
- 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 +142 -0
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +13 -13
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/internal_affairs.rb +3 -16
- 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 +60 -4
- data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +56 -10
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
- data/lib/rubocop/cop/layout/comment_indentation.rb +9 -2
- data/lib/rubocop/cop/layout/condition_position.rb +13 -3
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +2 -2
- data/lib/rubocop/cop/layout/else_alignment.rb +2 -15
- data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +28 -9
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +46 -21
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +13 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +17 -3
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -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 +35 -2
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +20 -15
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- data/lib/rubocop/cop/layout/hash_alignment.rb +5 -8
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +3 -3
- 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 +152 -7
- data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +62 -15
- 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 +3 -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 +236 -41
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +12 -6
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +15 -7
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -3
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +18 -3
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -39
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +12 -3
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
- 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/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +13 -1
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -8
- 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 +90 -0
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/debugger.rb +13 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/duplicate_methods.rb +219 -32
- 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 +20 -65
- data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
- 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 -8
- data/lib/rubocop/cop/lint/float_comparison.rb +33 -10
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- 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 +129 -11
- 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/mixed_case_range.rb +2 -2
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- 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 +4 -4
- 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 +11 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
- 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 +30 -11
- 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_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -23
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +134 -11
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +12 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +268 -0
- data/lib/rubocop/cop/lint/redundant_with_index.rb +4 -1
- data/lib/rubocop/cop/lint/redundant_with_object.rb +8 -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 +3 -2
- 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 +2 -2
- data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +22 -4
- 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 +63 -6
- 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 +27 -1
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +14 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +123 -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 +36 -3
- data/lib/rubocop/cop/lint/to_json.rb +20 -17
- 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 +36 -10
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +17 -9
- data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -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_access_modifier.rb +30 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +55 -25
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +92 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +11 -10
- data/lib/rubocop/cop/lint/useless_or.rb +111 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +11 -7
- 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 +147 -0
- data/lib/rubocop/cop/lint/void.rb +50 -21
- data/lib/rubocop/cop/message_annotator.rb +7 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +2 -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 +3 -2
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +38 -7
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
- data/lib/rubocop/cop/migration/department_name.rb +12 -1
- data/lib/rubocop/cop/mixin/alignment.rb +3 -3
- data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -5
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +4 -4
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -7
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +20 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
- data/lib/rubocop/cop/mixin/hash_subset.rb +27 -4
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +32 -78
- data/lib/rubocop/cop/mixin/line_length_help.rb +45 -10
- data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
- data/lib/rubocop/cop/mixin/range_help.rb +15 -3
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -7
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +25 -6
- 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_forwarding.rb +3 -3
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +6 -5
- data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -2
- data/lib/rubocop/cop/naming/method_name.rb +187 -15
- data/lib/rubocop/cop/naming/predicate_method.rb +330 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +48 -4
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +10 -4
- data/lib/rubocop/cop/naming/variable_name.rb +51 -6
- data/lib/rubocop/cop/offense.rb +17 -1
- data/lib/rubocop/cop/registry.rb +66 -39
- data/lib/rubocop/cop/security/eval.rb +17 -3
- data/lib/rubocop/cop/security/io_methods.rb +2 -2
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/security/marshal_load.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +45 -12
- data/lib/rubocop/cop/style/accessor_grouping.rb +46 -8
- 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 +46 -31
- data/lib/rubocop/cop/style/array_first_last.rb +12 -1
- data/lib/rubocop/cop/style/array_intersect.rb +117 -38
- 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 +42 -34
- data/lib/rubocop/cop/style/case_equality.rb +29 -15
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +67 -12
- data/lib/rubocop/cop/style/class_equality_comparison.rb +22 -14
- data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -5
- data/lib/rubocop/cop/style/collection_compact.rb +37 -17
- data/lib/rubocop/cop/style/collection_methods.rb +1 -0
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
- data/lib/rubocop/cop/style/combinable_loops.rb +6 -0
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
- data/lib/rubocop/cop/style/comparable_between.rb +78 -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 +33 -24
- data/lib/rubocop/cop/style/constant_visibility.rb +20 -12
- data/lib/rubocop/cop/style/copyright.rb +22 -11
- data/lib/rubocop/cop/style/data_inheritance.rb +11 -0
- data/lib/rubocop/cop/style/date_time.rb +4 -4
- data/lib/rubocop/cop/style/def_with_parentheses.rb +22 -5
- data/lib/rubocop/cop/style/dig_chain.rb +6 -1
- data/lib/rubocop/cop/style/dir_empty.rb +4 -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 +12 -8
- data/lib/rubocop/cop/style/double_negation.rb +3 -3
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +4 -3
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +12 -2
- data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
- data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +11 -2
- data/lib/rubocop/cop/style/empty_method.rb +0 -6
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +110 -0
- 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 +181 -18
- data/lib/rubocop/cop/style/env_home.rb +4 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/even_odd.rb +11 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -1
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
- data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
- data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
- data/lib/rubocop/cop/style/fetch_env_var.rb +33 -7
- data/lib/rubocop/cop/style/file_null.rb +4 -2
- 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 +4 -0
- data/lib/rubocop/cop/style/format_string.rb +17 -4
- data/lib/rubocop/cop/style/format_string_token.rb +85 -14
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
- data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +29 -23
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -12
- data/lib/rubocop/cop/style/hash_each_methods.rb +3 -2
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
- data/lib/rubocop/cop/style/hash_lookup_method.rb +102 -0
- data/lib/rubocop/cop/style/hash_slice.rb +16 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -1
- data/lib/rubocop/cop/style/hash_transform_keys.rb +19 -9
- data/lib/rubocop/cop/style/hash_transform_values.rb +19 -9
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +26 -20
- data/lib/rubocop/cop/style/if_unless_modifier.rb +83 -16
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +16 -19
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -6
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inline_comment.rb +5 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +10 -6
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +27 -7
- data/lib/rubocop/cop/style/ip_addresses.rb +3 -4
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +20 -10
- data/lib/rubocop/cop/style/lambda.rb +8 -1
- data/lib/rubocop/cop/style/lambda_call.rb +26 -10
- data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
- data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
- data/lib/rubocop/cop/style/map_into_array.rb +5 -2
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +12 -3
- data/lib/rubocop/cop/style/map_to_set.rb +1 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +9 -8
- 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 +33 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -5
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -5
- data/lib/rubocop/cop/style/min_max_comparison.rb +17 -6
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +10 -7
- data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
- data/lib/rubocop/cop/style/module_function.rb +4 -2
- data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
- data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
- data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +13 -16
- 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/next.rb +44 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
- data/lib/rubocop/cop/style/nil_lambda.rb +9 -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/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +1 -0
- 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/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
- data/lib/rubocop/cop/style/option_hash.rb +1 -1
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +57 -25
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +4 -0
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
- 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 +4 -2
- data/lib/rubocop/cop/style/raise_args.rb +9 -9
- 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_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +38 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +61 -1
- data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +26 -4
- data/lib/rubocop/cop/style/redundant_each.rb +3 -3
- data/lib/rubocop/cop/style/redundant_exception.rb +7 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +2 -10
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +312 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +28 -7
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +111 -37
- 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 +12 -0
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self.rb +20 -7
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
- 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_sort_by.rb +17 -1
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +32 -3
- data/lib/rubocop/cop/style/rescue_modifier.rb +6 -3
- data/lib/rubocop/cop/style/return_nil.rb +2 -2
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +67 -20
- 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 +53 -20
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +45 -12
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +21 -6
- data/lib/rubocop/cop/style/single_line_methods.rb +13 -8
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +77 -101
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +18 -15
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +24 -2
- data/lib/rubocop/cop/style/super_arguments.rb +3 -4
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +10 -7
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +11 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +18 -19
- data/lib/rubocop/cop/style/trivial_accessors.rb +2 -2
- 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 -1
- 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 +105 -40
- data/lib/rubocop/cop/util.rb +4 -5
- data/lib/rubocop/cop/utils/format_string.rb +20 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
- data/lib/rubocop/cop/variable_force/branch.rb +30 -6
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +10 -3
- data/lib/rubocop/cop/variable_force.rb +26 -9
- data/lib/rubocop/cops_documentation_generator.rb +23 -7
- data/lib/rubocop/directive_comment.rb +80 -3
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- 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 -13
- data/lib/rubocop/formatter/formatter_set.rb +2 -2
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +2 -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 +22 -37
- data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
- data/lib/rubocop/lsp/routes.rb +47 -11
- data/lib/rubocop/lsp/runtime.rb +19 -8
- data/lib/rubocop/lsp/server.rb +0 -2
- data/lib/rubocop/lsp/stdin_runner.rb +11 -18
- data/lib/rubocop/magic_comment.rb +28 -0
- data/lib/rubocop/mcp/server.rb +200 -0
- data/lib/rubocop/options.rb +60 -14
- data/lib/rubocop/path_util.rb +18 -2
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
- data/lib/rubocop/plugin/load_error.rb +26 -0
- data/lib/rubocop/plugin/loader.rb +100 -0
- data/lib/rubocop/plugin/not_supported_error.rb +29 -0
- data/lib/rubocop/plugin.rb +46 -0
- data/lib/rubocop/project_index_loader.rb +66 -0
- data/lib/rubocop/rake_task.rb +5 -2
- data/lib/rubocop/remote_config.rb +10 -8
- data/lib/rubocop/result_cache.rb +72 -47
- data/lib/rubocop/rspec/cop_helper.rb +21 -1
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/rspec/shared_contexts.rb +71 -3
- data/lib/rubocop/rspec/support.rb +4 -0
- data/lib/rubocop/runner.rb +188 -65
- data/lib/rubocop/server/cache.rb +56 -41
- data/lib/rubocop/server/cli.rb +2 -2
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/server/core.rb +8 -0
- data/lib/rubocop/target_finder.rb +21 -10
- data/lib/rubocop/target_ruby.rb +31 -14
- data/lib/rubocop/version.rb +50 -10
- data/lib/rubocop.rb +47 -96
- data/lib/ruby_lsp/rubocop/addon.rb +29 -17
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
- metadata +86 -16
- data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
- data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +0 -50
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for calls to `Kernel#format` or `Kernel#sprintf` that are redundant.
|
|
7
|
+
#
|
|
8
|
+
# Calling `format` with only a single string or constant argument is redundant,
|
|
9
|
+
# as it can be replaced by the string or constant itself.
|
|
10
|
+
#
|
|
11
|
+
# Also looks for `format` calls where the arguments are literals that can be
|
|
12
|
+
# inlined into a string easily. This applies to the `%s`, `%d`, `%i`, `%u`, and
|
|
13
|
+
# `%f` format specifiers.
|
|
14
|
+
#
|
|
15
|
+
# @safety
|
|
16
|
+
# This cop's autocorrection is unsafe because string object returned by
|
|
17
|
+
# `format` and `sprintf` are never frozen. If `format('string')` is autocorrected to
|
|
18
|
+
# `'string'`, `FrozenError` may occur when calling a destructive method like `String#<<`.
|
|
19
|
+
# Consider using `'string'.dup` instead of `format('string')`.
|
|
20
|
+
# Additionally, since the necessity of `dup` cannot be determined automatically,
|
|
21
|
+
# this autocorrection is inherently unsafe.
|
|
22
|
+
#
|
|
23
|
+
# [source,ruby]
|
|
24
|
+
# ----
|
|
25
|
+
# # frozen_string_literal: true
|
|
26
|
+
#
|
|
27
|
+
# format('template').frozen? # => false
|
|
28
|
+
# 'template'.frozen? # => true
|
|
29
|
+
# ----
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
#
|
|
33
|
+
# # bad
|
|
34
|
+
# format('the quick brown fox jumps over the lazy dog.')
|
|
35
|
+
# sprintf('the quick brown fox jumps over the lazy dog.')
|
|
36
|
+
#
|
|
37
|
+
# # good
|
|
38
|
+
# 'the quick brown fox jumps over the lazy dog.'
|
|
39
|
+
#
|
|
40
|
+
# # bad
|
|
41
|
+
# format(MESSAGE)
|
|
42
|
+
# sprintf(MESSAGE)
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# MESSAGE
|
|
46
|
+
#
|
|
47
|
+
# # bad
|
|
48
|
+
# format('%s %s', 'foo', 'bar')
|
|
49
|
+
# sprintf('%s %s', 'foo', 'bar')
|
|
50
|
+
#
|
|
51
|
+
# # good
|
|
52
|
+
# 'foo bar'
|
|
53
|
+
#
|
|
54
|
+
class RedundantFormat < Base
|
|
55
|
+
extend AutoCorrector
|
|
56
|
+
|
|
57
|
+
MSG = 'Use `%<prefer>s` directly instead of `%<method_name>s`.'
|
|
58
|
+
|
|
59
|
+
RESTRICT_ON_SEND = %i[format sprintf].to_set.freeze
|
|
60
|
+
ACCEPTABLE_LITERAL_TYPES = %i[str dstr sym dsym numeric boolean nil].freeze
|
|
61
|
+
|
|
62
|
+
# @!method format_without_additional_args?(node)
|
|
63
|
+
def_node_matcher :format_without_additional_args?, <<~PATTERN
|
|
64
|
+
(send {(const {nil? cbase} :Kernel) nil?} %RESTRICT_ON_SEND ${str dstr const})
|
|
65
|
+
PATTERN
|
|
66
|
+
|
|
67
|
+
# @!method rational_number?(node)
|
|
68
|
+
def_node_matcher :rational_number?, <<~PATTERN
|
|
69
|
+
{rational (send int :/ rational) (begin rational) (begin (send int :/ rational))}
|
|
70
|
+
PATTERN
|
|
71
|
+
|
|
72
|
+
# @!method complex_number?(node)
|
|
73
|
+
def_node_matcher :complex_number?, <<~PATTERN
|
|
74
|
+
{complex (send int :+ complex) (begin complex) (begin (send int :+ complex))}
|
|
75
|
+
PATTERN
|
|
76
|
+
|
|
77
|
+
# @!method find_hash_value_node(node, name)
|
|
78
|
+
def_node_search :find_hash_value_node, <<~PATTERN
|
|
79
|
+
(pair (sym %1) $_)
|
|
80
|
+
PATTERN
|
|
81
|
+
|
|
82
|
+
# @!method splatted_arguments?(node)
|
|
83
|
+
def_node_matcher :splatted_arguments?, <<~PATTERN
|
|
84
|
+
(send _ %RESTRICT_ON_SEND <{
|
|
85
|
+
splat
|
|
86
|
+
(hash <kwsplat ...>)
|
|
87
|
+
} ...>)
|
|
88
|
+
PATTERN
|
|
89
|
+
|
|
90
|
+
def on_send(node)
|
|
91
|
+
format_without_additional_args?(node) do |value|
|
|
92
|
+
next if string_with_format_sequence?(value)
|
|
93
|
+
|
|
94
|
+
replacement = escape_control_chars(value.source)
|
|
95
|
+
|
|
96
|
+
add_offense(node, message: message(node, replacement)) do |corrector|
|
|
97
|
+
corrector.replace(node, replacement)
|
|
98
|
+
end
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
detect_unnecessary_fields(node)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
# A single-argument `format` whose string still contains a format sequence is
|
|
108
|
+
# not redundant: `format('%s')` raises at runtime, and `format('%%')` returns
|
|
109
|
+
# `'%'`, so replacing it with the literal would change behavior.
|
|
110
|
+
def string_with_format_sequence?(node)
|
|
111
|
+
string = static_string_value(node)
|
|
112
|
+
return false unless string
|
|
113
|
+
|
|
114
|
+
RuboCop::Cop::Utils::FormatString.new(string).format_sequences.any?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def static_string_value(node)
|
|
118
|
+
if node.str_type?
|
|
119
|
+
node.value
|
|
120
|
+
elsif node.dstr_type?
|
|
121
|
+
node.children.select(&:str_type?).map(&:value).join
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def message(node, prefer)
|
|
126
|
+
format(MSG, prefer: prefer, method_name: node.method_name)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def detect_unnecessary_fields(node)
|
|
130
|
+
return unless node.first_argument&.str_type?
|
|
131
|
+
return if node.first_argument.heredoc?
|
|
132
|
+
|
|
133
|
+
string = node.first_argument.value
|
|
134
|
+
arguments = node.arguments[1..]
|
|
135
|
+
|
|
136
|
+
return unless string && arguments.any?
|
|
137
|
+
return if splatted_arguments?(node)
|
|
138
|
+
|
|
139
|
+
register_all_fields_literal(node, string, arguments)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def register_all_fields_literal(node, string, arguments)
|
|
143
|
+
return unless all_fields_literal?(string, arguments.dup)
|
|
144
|
+
|
|
145
|
+
format_arguments = argument_values(arguments)
|
|
146
|
+
begin
|
|
147
|
+
formatted_string = format(string, *format_arguments)
|
|
148
|
+
rescue ArgumentError
|
|
149
|
+
return
|
|
150
|
+
end
|
|
151
|
+
replacement = quote(formatted_string, node)
|
|
152
|
+
|
|
153
|
+
add_offense(node, message: message(node, replacement)) do |corrector|
|
|
154
|
+
corrector.replace(node, replacement)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
159
|
+
def all_fields_literal?(string, arguments)
|
|
160
|
+
count = 0
|
|
161
|
+
sequences = RuboCop::Cop::Utils::FormatString.new(string).format_sequences
|
|
162
|
+
return false unless sequences.any?
|
|
163
|
+
|
|
164
|
+
sequences.each do |sequence|
|
|
165
|
+
next if sequence.percent?
|
|
166
|
+
next if unknown_variable_width?(sequence, arguments)
|
|
167
|
+
|
|
168
|
+
hash = arguments.detect(&:hash_type?)
|
|
169
|
+
next unless (argument = find_argument(sequence, arguments, hash))
|
|
170
|
+
next unless matching_argument?(sequence, argument)
|
|
171
|
+
next if (sequence.width || sequence.precision) && argument.dstr_type?
|
|
172
|
+
|
|
173
|
+
count += 1
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
sequences.size == count
|
|
177
|
+
end
|
|
178
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
179
|
+
|
|
180
|
+
# If the sequence has a variable (`*`) width, it cannot be autocorrected
|
|
181
|
+
# if the width is not given as a numeric literal argument
|
|
182
|
+
def unknown_variable_width?(sequence, arguments)
|
|
183
|
+
return false unless sequence.variable_width?
|
|
184
|
+
|
|
185
|
+
argument = arguments[sequence.variable_width_argument_number - 1]
|
|
186
|
+
!numeric?(argument)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# rubocop:disable Metrics/AbcSize
|
|
190
|
+
def find_argument(sequence, arguments, hash)
|
|
191
|
+
if hash && (sequence.annotated? || sequence.template?)
|
|
192
|
+
find_hash_value_node(hash, sequence.name.to_sym).first
|
|
193
|
+
elsif sequence.variable_width?
|
|
194
|
+
# If the specifier contains `*`, the argument for the width can be ignored.
|
|
195
|
+
arguments.delete_at(sequence.variable_width_argument_number - 1)
|
|
196
|
+
arguments.shift
|
|
197
|
+
elsif sequence.arg_number
|
|
198
|
+
arguments[sequence.arg_number.to_i - 1]
|
|
199
|
+
else
|
|
200
|
+
arguments.shift
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
# rubocop:enable Metrics/AbcSize
|
|
204
|
+
|
|
205
|
+
def matching_argument?(sequence, argument)
|
|
206
|
+
# Template specifiers don't give a type, any acceptable literal type is ok.
|
|
207
|
+
return argument.type?(*ACCEPTABLE_LITERAL_TYPES) if sequence.template?
|
|
208
|
+
|
|
209
|
+
# An argument matches a specifier if it can be easily converted
|
|
210
|
+
# to that type.
|
|
211
|
+
case sequence.type
|
|
212
|
+
when 's'
|
|
213
|
+
argument.type?(*ACCEPTABLE_LITERAL_TYPES)
|
|
214
|
+
when 'd', 'i', 'u'
|
|
215
|
+
integer?(argument)
|
|
216
|
+
when 'f'
|
|
217
|
+
float?(argument)
|
|
218
|
+
else
|
|
219
|
+
false
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def numeric?(argument)
|
|
224
|
+
argument.type?(:numeric, :str) ||
|
|
225
|
+
rational_number?(argument) ||
|
|
226
|
+
complex_number?(argument)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def integer?(argument)
|
|
230
|
+
numeric?(argument) && Integer(argument_value(argument), exception: false)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def float?(argument)
|
|
234
|
+
numeric?(argument) && Float(argument_value(argument), exception: false)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Add correct quotes to the formatted string, preferring retaining the existing
|
|
238
|
+
# quotes if possible.
|
|
239
|
+
def quote(string, node)
|
|
240
|
+
str_node = node.first_argument
|
|
241
|
+
start_delimiter = str_node.loc.begin.source
|
|
242
|
+
end_delimiter = str_node.loc.end.source
|
|
243
|
+
|
|
244
|
+
# If there is any interpolation, the delimiters need to be changed potentially
|
|
245
|
+
if node.each_descendant(:dstr, :dsym).any?
|
|
246
|
+
case start_delimiter
|
|
247
|
+
when "'"
|
|
248
|
+
start_delimiter = end_delimiter = '"'
|
|
249
|
+
when /\A%q(.)/
|
|
250
|
+
start_delimiter = "%Q#{Regexp.last_match[1]}"
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
"#{start_delimiter}#{escape_control_chars(string)}#{end_delimiter}"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Escape any control characters in the string (eg. `\t` or `\n` become `\\t` or `\\n`)
|
|
258
|
+
def escape_control_chars(string)
|
|
259
|
+
string.gsub(/\p{Cc}/) { |s| s.dump[1..-2] }
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def argument_values(arguments)
|
|
263
|
+
arguments.map { |argument| argument_value(argument) }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def argument_value(argument)
|
|
267
|
+
argument = argument.children.first if argument.begin_type?
|
|
268
|
+
|
|
269
|
+
# `nil` formats to an empty string (`format('%s', nil) == ''`), not the
|
|
270
|
+
# literal `'nil'` that `argument.source` would return.
|
|
271
|
+
return if argument.nil_type?
|
|
272
|
+
|
|
273
|
+
typed_argument_value(argument)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def typed_argument_value(argument)
|
|
277
|
+
if argument.dsym_type?
|
|
278
|
+
dsym_value(argument)
|
|
279
|
+
elsif argument.hash_type?
|
|
280
|
+
hash_value(argument)
|
|
281
|
+
elsif rational_number?(argument)
|
|
282
|
+
rational_value(argument)
|
|
283
|
+
elsif complex_number?(argument)
|
|
284
|
+
complex_value(argument)
|
|
285
|
+
elsif argument.respond_to?(:value)
|
|
286
|
+
argument.value
|
|
287
|
+
else
|
|
288
|
+
argument.source
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def dsym_value(dsym_node)
|
|
293
|
+
dsym_node.children.first.source
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def hash_value(hash_node)
|
|
297
|
+
hash_node.each_pair.with_object({}) do |pair, hash|
|
|
298
|
+
hash[pair.key.value] = argument_value(pair.value)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def rational_value(rational_node)
|
|
303
|
+
rational_node.source.to_r
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def complex_value(complex_node)
|
|
307
|
+
Complex(complex_node.source)
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
#
|
|
6
|
+
# Checks for uses of `Object#freeze` on immutable objects.
|
|
7
7
|
#
|
|
8
8
|
# NOTE: `Regexp` and `Range` literals are frozen objects since Ruby 3.0.
|
|
9
9
|
#
|
|
@@ -60,7 +60,7 @@ module RuboCop
|
|
|
60
60
|
(begin (send !{(str _) array} {:+ :- :* :** :/ :%} {float int}))
|
|
61
61
|
(begin (send _ {:== :=== :!= :<= :>= :< :>} _))
|
|
62
62
|
(send _ {:count :length :size} ...)
|
|
63
|
-
(
|
|
63
|
+
(any_block (send _ {:count :length :size} ...) ...)
|
|
64
64
|
}
|
|
65
65
|
PATTERN
|
|
66
66
|
end
|
|
@@ -48,8 +48,13 @@ module RuboCop
|
|
|
48
48
|
def need_heredoc_delimiter_quotes?(node)
|
|
49
49
|
heredoc_delimiter = node.source.delete(heredoc_type(node))
|
|
50
50
|
return true unless heredoc_delimiter.start_with?("'", '"')
|
|
51
|
+
return true if node.loc.heredoc_end.source.strip.match?(/\W/)
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
# A double-quoted delimiter interpolates exactly like an unquoted one,
|
|
54
|
+
# so its quotes are always redundant. A single-quoted delimiter is
|
|
55
|
+
# required when the body contains interpolation or escapes that would
|
|
56
|
+
# otherwise be evaluated.
|
|
57
|
+
heredoc_delimiter.start_with?("'") &&
|
|
53
58
|
node.loc.heredoc_body.source.match?(STRING_INTERPOLATION_OR_ESCAPED_CHARACTER_PATTERN)
|
|
54
59
|
end
|
|
55
60
|
end
|
|
@@ -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
|
|
|
@@ -130,7 +139,7 @@ module RuboCop
|
|
|
130
139
|
end
|
|
131
140
|
|
|
132
141
|
def require_parentheses?(node)
|
|
133
|
-
node.send_type? &&
|
|
142
|
+
node.send_type? && node.arguments.any? && !node.parenthesized_call?
|
|
134
143
|
end
|
|
135
144
|
end
|
|
136
145
|
end
|
|
@@ -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
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
#
|
|
6
|
+
# Checks for redundant line continuation.
|
|
7
7
|
#
|
|
8
8
|
# This cop marks a line continuation as redundant if removing the backslash
|
|
9
9
|
# does not result in a syntax error.
|
|
@@ -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
|
|
|
@@ -149,11 +165,11 @@ module RuboCop
|
|
|
149
165
|
end
|
|
150
166
|
|
|
151
167
|
def inspect_end_of_ruby_code_line_continuation
|
|
152
|
-
|
|
168
|
+
last_line_number = processed_source.ast.last_line
|
|
169
|
+
last_line = processed_source.lines[last_line_number - 1]
|
|
153
170
|
return unless code_ends_with_continuation?(last_line)
|
|
154
171
|
|
|
155
|
-
|
|
156
|
-
line_continuation_range = range_between(last_column - 1, last_column)
|
|
172
|
+
line_continuation_range = trailing_line_continuation_range(last_line_number)
|
|
157
173
|
|
|
158
174
|
add_offense(line_continuation_range) do |corrector|
|
|
159
175
|
corrector.remove_trailing(line_continuation_range, 1)
|
|
@@ -166,6 +182,14 @@ module RuboCop
|
|
|
166
182
|
last_line.end_with?(LINE_CONTINUATION)
|
|
167
183
|
end
|
|
168
184
|
|
|
185
|
+
# The backslash is the last character of the line; locate it by the line's
|
|
186
|
+
# position in the buffer rather than treating the column as an absolute offset
|
|
187
|
+
# (which corrupts an earlier line in multi-line files).
|
|
188
|
+
def trailing_line_continuation_range(line_number)
|
|
189
|
+
line_range = processed_source.buffer.line_range(line_number)
|
|
190
|
+
range_between(line_range.end_pos - 1, line_range.end_pos)
|
|
191
|
+
end
|
|
192
|
+
|
|
169
193
|
def inside_string_literal?(range, token)
|
|
170
194
|
ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
|
|
171
195
|
end
|
|
@@ -181,9 +205,7 @@ module RuboCop
|
|
|
181
205
|
ARGUMENT_TYPES.include?(next_token.type)
|
|
182
206
|
end
|
|
183
207
|
|
|
184
|
-
# rubocop:disable Metrics/AbcSize
|
|
185
208
|
def argument_newline?(node)
|
|
186
|
-
node = node.to_a.last if node.assignment?
|
|
187
209
|
return false if node.parenthesized_call?
|
|
188
210
|
|
|
189
211
|
node = node.children.first if node.root? && node.begin_type?
|
|
@@ -196,7 +218,6 @@ module RuboCop
|
|
|
196
218
|
node.loc.selector.line != node.first_argument.loc.line
|
|
197
219
|
end
|
|
198
220
|
end
|
|
199
|
-
# rubocop:enable Metrics/AbcSize
|
|
200
221
|
|
|
201
222
|
def find_node_for_line(last_line)
|
|
202
223
|
processed_source.ast.each_node do |node|
|
|
@@ -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
|