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,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks that each source file defines at most one top-level class or module.
|
|
7
|
+
#
|
|
8
|
+
# Keeping one class or module per file makes it easier to find and navigate
|
|
9
|
+
# code, and follows the convention used by most Ruby projects.
|
|
10
|
+
#
|
|
11
|
+
# Classes and modules listed in `AllowedClasses` are not counted toward the
|
|
12
|
+
# limit. This is useful for small ancillary classes like custom exception
|
|
13
|
+
# classes that logically belong with the main class.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# # bad - Multiple top-level classes
|
|
17
|
+
# class Foo
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# class Bar
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# # bad - Multiple top-level modules
|
|
24
|
+
# module Foo
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# module Bar
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# # bad - A top-level class and a top-level module
|
|
31
|
+
# class Foo
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# module Bar
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# # good - A single top-level class
|
|
38
|
+
# class Foo
|
|
39
|
+
# end
|
|
40
|
+
#
|
|
41
|
+
# # good - A single top-level module
|
|
42
|
+
# module Foo
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# # good - Nested classes within a single top-level class
|
|
46
|
+
# class Foo
|
|
47
|
+
# class Bar
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# # good - Multiple classes within a single top-level module
|
|
52
|
+
# module Foo
|
|
53
|
+
# class Bar
|
|
54
|
+
# end
|
|
55
|
+
#
|
|
56
|
+
# class Baz
|
|
57
|
+
# end
|
|
58
|
+
# end
|
|
59
|
+
#
|
|
60
|
+
# @example AllowedClasses: ['AllowedClass']
|
|
61
|
+
# # good
|
|
62
|
+
# class Foo
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
65
|
+
# class AllowedClass
|
|
66
|
+
# end
|
|
67
|
+
#
|
|
68
|
+
class OneClassPerFile < Base
|
|
69
|
+
include RangeHelp
|
|
70
|
+
|
|
71
|
+
MSG = 'Do not define multiple classes/modules at the top level in a single file.'
|
|
72
|
+
|
|
73
|
+
def on_new_investigation
|
|
74
|
+
@top_level_definitions = []
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def on_class(node)
|
|
78
|
+
check_top_level(node)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def on_module(node)
|
|
82
|
+
check_top_level(node)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def check_top_level(node)
|
|
88
|
+
return unless top_level_definition?(node)
|
|
89
|
+
return if allowed_class?(node)
|
|
90
|
+
|
|
91
|
+
@top_level_definitions << node
|
|
92
|
+
return unless @top_level_definitions.length > 1
|
|
93
|
+
|
|
94
|
+
add_offense(range_between(node.source_range.begin_pos, node.loc.name.end_pos))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def top_level_definition?(node)
|
|
98
|
+
if node.parent&.begin_type?
|
|
99
|
+
node.parent.root?
|
|
100
|
+
else
|
|
101
|
+
node.root?
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def allowed_class?(node)
|
|
106
|
+
allowed_classes.include?(node.identifier.short_name)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def allowed_classes
|
|
110
|
+
@allowed_classes ||= cop_config.fetch('AllowedClasses', []).map(&:intern)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for uses of if/then/else/end constructs on a single line.
|
|
7
|
-
#
|
|
8
|
-
#
|
|
6
|
+
# Checks for uses of `if/then/else/end` constructs on a single line.
|
|
7
|
+
# A ternary operator (`?:`) or multi-line `if` is more readable.
|
|
8
|
+
# `AlwaysCorrectToMultiline` config option can be set to `true` to autocorrect all offenses to
|
|
9
|
+
# multi-line constructs. When `AlwaysCorrectToMultiline` is `false` (default case) the
|
|
9
10
|
# autocorrect will first try converting them to ternary operators.
|
|
10
11
|
#
|
|
11
12
|
# @example
|
|
@@ -55,19 +56,21 @@ module RuboCop
|
|
|
55
56
|
include OnNormalIfUnless
|
|
56
57
|
extend AutoCorrector
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
MSG_SUFFIX = 'over single-line `%<keyword>s/then/else/end` constructs.'
|
|
60
|
+
MSG_TERNARY = "Favor the ternary operator (`?:`) #{MSG_SUFFIX}"
|
|
61
|
+
MSG_MULTILINE = "Favor multi-line `%<keyword>s` #{MSG_SUFFIX}"
|
|
60
62
|
|
|
61
63
|
def on_normal_if_unless(node)
|
|
62
64
|
return unless node.single_line?
|
|
63
65
|
return unless node.else_branch
|
|
64
66
|
return if node.elsif? || node.if_branch&.begin_type?
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
multiline = multiline?(node)
|
|
69
|
+
|
|
70
|
+
add_offense(node, message: message(node, multiline)) do |corrector|
|
|
68
71
|
next if part_of_ignored_node?(node)
|
|
69
72
|
|
|
70
|
-
autocorrect(corrector, node)
|
|
73
|
+
autocorrect(corrector, node, multiline)
|
|
71
74
|
|
|
72
75
|
ignore_node(node)
|
|
73
76
|
end
|
|
@@ -75,12 +78,18 @@ module RuboCop
|
|
|
75
78
|
|
|
76
79
|
private
|
|
77
80
|
|
|
78
|
-
def
|
|
79
|
-
|
|
81
|
+
def multiline?(node)
|
|
82
|
+
always_multiline? || cannot_replace_to_ternary?(node)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def message(node, multiline)
|
|
86
|
+
template = multiline ? MSG_MULTILINE : MSG_TERNARY
|
|
87
|
+
|
|
88
|
+
format(template, keyword: node.keyword)
|
|
80
89
|
end
|
|
81
90
|
|
|
82
|
-
def autocorrect(corrector, node)
|
|
83
|
-
if
|
|
91
|
+
def autocorrect(corrector, node, multiline)
|
|
92
|
+
if multiline
|
|
84
93
|
IfThenCorrector.new(node, indentation: configured_indentation_width).call(corrector)
|
|
85
94
|
else
|
|
86
95
|
corrector.replace(node, ternary_correction(node))
|
|
@@ -26,9 +26,10 @@ module RuboCop
|
|
|
26
26
|
splat kwsplat forwarded_args forwarded_restarg forwarded_kwrestarg block_pass
|
|
27
27
|
].freeze
|
|
28
28
|
|
|
29
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
29
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
30
30
|
def on_send(node)
|
|
31
31
|
return unless (dot = node.loc.dot)
|
|
32
|
+
return if unary_method_no_operator?(node)
|
|
32
33
|
return if node.receiver.const_type? || !node.arguments.one?
|
|
33
34
|
|
|
34
35
|
return unless (rhs = node.first_argument)
|
|
@@ -43,10 +44,18 @@ module RuboCop
|
|
|
43
44
|
corrector.insert_after(selector, ' ') if insert_space_after?(node)
|
|
44
45
|
end
|
|
45
46
|
end
|
|
46
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
47
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
47
48
|
|
|
48
49
|
private
|
|
49
50
|
|
|
51
|
+
# `foo.~@` and `foo.!@` call the method `~` and `!` respectively. While those
|
|
52
|
+
# are operator methods, we don't want to actually consider them as such.
|
|
53
|
+
def unary_method_no_operator?(node)
|
|
54
|
+
return false unless node.nonmutating_unary_operator_method?
|
|
55
|
+
|
|
56
|
+
node.method_name.to_s != node.selector.source
|
|
57
|
+
end
|
|
58
|
+
|
|
50
59
|
# Checks for an acceptable case of `foo.+(bar).baz`.
|
|
51
60
|
def method_call_with_parenthesized_arg?(argument)
|
|
52
61
|
return false unless argument.parent.parent&.send_type?
|
|
@@ -4,6 +4,10 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for simple usages of parallel assignment.
|
|
7
|
+
# Parallel assignment is less readable than individual
|
|
8
|
+
# assignments and makes it harder to follow what each
|
|
9
|
+
# variable is being set to.
|
|
10
|
+
#
|
|
7
11
|
# This will only complain when the number of variables
|
|
8
12
|
# being assigned matched the number of assigning variables.
|
|
9
13
|
#
|
|
@@ -14,7 +18,7 @@ module RuboCop
|
|
|
14
18
|
#
|
|
15
19
|
# # good
|
|
16
20
|
# one, two = *foo
|
|
17
|
-
# a, b = foo
|
|
21
|
+
# a, b = foo
|
|
18
22
|
# a, b = b, a
|
|
19
23
|
#
|
|
20
24
|
# a = 1
|
|
@@ -34,7 +38,7 @@ module RuboCop
|
|
|
34
38
|
rhs_elements = Array(rhs).compact # edge case for one constant
|
|
35
39
|
|
|
36
40
|
return if allowed_lhs?(node.assignments) || allowed_rhs?(rhs) ||
|
|
37
|
-
allowed_masign?(node.assignments, rhs_elements)
|
|
41
|
+
allowed_masign?(node.assignments, rhs_elements) || contains_heredoc?(rhs)
|
|
38
42
|
|
|
39
43
|
range = node.source_range.begin.join(rhs.source_range.end)
|
|
40
44
|
|
|
@@ -73,6 +77,13 @@ module RuboCop
|
|
|
73
77
|
!node.array_type? || elements.any?(&:splat_type?)
|
|
74
78
|
end
|
|
75
79
|
|
|
80
|
+
# Autocorrection splits the assignment into single assignments on
|
|
81
|
+
# consecutive lines, which would put following assignments into the
|
|
82
|
+
# heredoc body unless the heredoc bodies were moved along.
|
|
83
|
+
def contains_heredoc?(node)
|
|
84
|
+
node.each_descendant(:any_str).any?(&:heredoc?)
|
|
85
|
+
end
|
|
86
|
+
|
|
76
87
|
def assignment_corrector(node, rhs, order)
|
|
77
88
|
if node.parent&.rescue_type?
|
|
78
89
|
_assignment, modifier = *node.parent
|
|
@@ -223,7 +234,7 @@ module RuboCop
|
|
|
223
234
|
# __FILE__ is treated as a StrNode but has no begin
|
|
224
235
|
if node.str_type? && loc.respond_to?(:begin) && loc.begin.nil?
|
|
225
236
|
"'#{node.source}'"
|
|
226
|
-
elsif node.sym_type? && loc
|
|
237
|
+
elsif node.sym_type? && !node.loc?(:begin)
|
|
227
238
|
":#{node.source}"
|
|
228
239
|
else
|
|
229
240
|
node.source
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for consecutive calls to `select`/`filter`/`find_all` and `reject`
|
|
7
|
+
# on the same receiver with the same block body, where `partition` could be
|
|
8
|
+
# used instead. Also detects two `select` or two `reject` calls where one
|
|
9
|
+
# block negates the other with `!`. Using `partition` reduces two collection
|
|
10
|
+
# traversals to one.
|
|
11
|
+
#
|
|
12
|
+
# @safety
|
|
13
|
+
# This cop is unsafe because:
|
|
14
|
+
#
|
|
15
|
+
# * `Hash#select` and `Hash#reject` return hashes, but `Hash#partition`
|
|
16
|
+
# returns nested arrays.
|
|
17
|
+
# * When the receiver has side effects, calling it once (with `partition`)
|
|
18
|
+
# versus twice (with `select` + `reject`) may produce different results.
|
|
19
|
+
# * Custom classes may override `select`/`reject` without providing a
|
|
20
|
+
# compatible `partition` method.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# # bad
|
|
24
|
+
# positives = array.select { |x| x > 0 }
|
|
25
|
+
# negatives = array.reject { |x| x > 0 }
|
|
26
|
+
#
|
|
27
|
+
# # bad
|
|
28
|
+
# positives = array.filter { |x| x > 0 }
|
|
29
|
+
# negatives = array.reject { |x| x > 0 }
|
|
30
|
+
#
|
|
31
|
+
# # bad
|
|
32
|
+
# negatives = array.reject { |x| x > 0 }
|
|
33
|
+
# positives = array.select { |x| x > 0 }
|
|
34
|
+
#
|
|
35
|
+
# # bad
|
|
36
|
+
# positives = array.select(&:positive?)
|
|
37
|
+
# negatives = array.reject(&:positive?)
|
|
38
|
+
#
|
|
39
|
+
# # bad
|
|
40
|
+
# positives = array.select(&:positive?)
|
|
41
|
+
# negatives = array.reject { |x| x.positive? }
|
|
42
|
+
#
|
|
43
|
+
# # bad
|
|
44
|
+
# positives = array.select { |x| x.positive? }
|
|
45
|
+
# non_positives = array.select { |x| !x.positive? }
|
|
46
|
+
#
|
|
47
|
+
# # good
|
|
48
|
+
# positives, negatives = array.partition { |x| x > 0 }
|
|
49
|
+
#
|
|
50
|
+
# # good
|
|
51
|
+
# positives, non_positives = array.partition { |x| x.positive? }
|
|
52
|
+
#
|
|
53
|
+
# # good
|
|
54
|
+
# positives, negatives = array.partition(&:positive?)
|
|
55
|
+
#
|
|
56
|
+
class PartitionInsteadOfDoubleSelect < Base
|
|
57
|
+
include RangeHelp
|
|
58
|
+
extend AutoCorrector
|
|
59
|
+
|
|
60
|
+
MSG = 'Use `partition` instead of consecutive `%<first>s` and `%<second>s` calls.'
|
|
61
|
+
|
|
62
|
+
SELECT_METHODS = %i[select filter find_all].freeze
|
|
63
|
+
CANDIDATE_METHODS = (SELECT_METHODS + %i[reject]).to_set.freeze
|
|
64
|
+
RESTRICT_ON_SEND = (SELECT_METHODS + %i[reject]).freeze
|
|
65
|
+
|
|
66
|
+
# @!method symbol_proc_method?(node)
|
|
67
|
+
def_node_matcher :symbol_proc_method?, <<~PATTERN
|
|
68
|
+
(block _ (args (arg _name)) (send (lvar _name) $_method_name))
|
|
69
|
+
PATTERN
|
|
70
|
+
|
|
71
|
+
def on_block(node)
|
|
72
|
+
return unless CANDIDATE_METHODS.include?(node.method_name)
|
|
73
|
+
|
|
74
|
+
find_and_register_offense(node)
|
|
75
|
+
end
|
|
76
|
+
alias on_numblock on_block
|
|
77
|
+
alias on_itblock on_block
|
|
78
|
+
|
|
79
|
+
def on_send(node)
|
|
80
|
+
return unless node.last_argument&.block_pass_type?
|
|
81
|
+
|
|
82
|
+
find_and_register_offense(node)
|
|
83
|
+
end
|
|
84
|
+
alias on_csend on_send
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def find_and_register_offense(node)
|
|
89
|
+
container = node_container(node)
|
|
90
|
+
return unless container
|
|
91
|
+
|
|
92
|
+
sibling_container = container.left_sibling
|
|
93
|
+
sibling = find_matching_candidate(node, sibling_container)
|
|
94
|
+
return unless sibling
|
|
95
|
+
|
|
96
|
+
register_offense(node, sibling, container, sibling_container)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def node_container(node)
|
|
100
|
+
parent = node.parent
|
|
101
|
+
if parent&.begin_type?
|
|
102
|
+
node
|
|
103
|
+
elsif parent&.assignment? && parent.parent&.begin_type?
|
|
104
|
+
parent
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def find_matching_candidate(node, sibling_container)
|
|
109
|
+
return unless sibling_container
|
|
110
|
+
|
|
111
|
+
sibling = extract_candidate(sibling_container)
|
|
112
|
+
return unless sibling
|
|
113
|
+
return unless node.receiver == sibling.receiver
|
|
114
|
+
return unless matching_pair?(node, sibling)
|
|
115
|
+
|
|
116
|
+
sibling
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def matching_pair?(node, sibling)
|
|
120
|
+
(complementary_pair?(node, sibling) && equivalent_predicate?(node, sibling)) ||
|
|
121
|
+
(node.method?(sibling.method_name) && negated_predicate?(node, sibling))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def extract_candidate(container)
|
|
125
|
+
extract_block(container) || extract_block_pass_send(container)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def extract_block(container)
|
|
129
|
+
if container.any_block_type?
|
|
130
|
+
container
|
|
131
|
+
elsif container.assignment?
|
|
132
|
+
rhs = container.children.last
|
|
133
|
+
rhs if rhs&.any_block_type?
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def extract_block_pass_send(container)
|
|
138
|
+
node = container.assignment? ? container.children.last : container
|
|
139
|
+
return unless node&.type?(:call)
|
|
140
|
+
return unless node.last_argument&.block_pass_type?
|
|
141
|
+
|
|
142
|
+
node
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def complementary_pair?(node1, node2)
|
|
146
|
+
m1 = node1.method_name
|
|
147
|
+
m2 = node2.method_name
|
|
148
|
+
(SELECT_METHODS.include?(m1) && m2 == :reject) ||
|
|
149
|
+
(m1 == :reject && SELECT_METHODS.include?(m2))
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def equivalent_predicate?(node1, node2)
|
|
153
|
+
if node1.any_block_type? && node2.any_block_type?
|
|
154
|
+
same_block_contents?(node1, node2)
|
|
155
|
+
elsif node1.any_block_type?
|
|
156
|
+
block_matches_block_pass?(node1, node2)
|
|
157
|
+
elsif node2.any_block_type?
|
|
158
|
+
block_matches_block_pass?(node2, node1)
|
|
159
|
+
else
|
|
160
|
+
node1.last_argument == node2.last_argument
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def same_block_contents?(block1, block2)
|
|
165
|
+
return false unless block1.type == block2.type
|
|
166
|
+
|
|
167
|
+
if block1.block_type?
|
|
168
|
+
block1.arguments == block2.arguments &&
|
|
169
|
+
block1.body == block2.body
|
|
170
|
+
else
|
|
171
|
+
block1.body == block2.body
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def block_matches_block_pass?(block_node, send_node)
|
|
176
|
+
method_name = symbol_proc_method?(block_node)
|
|
177
|
+
return false unless method_name
|
|
178
|
+
|
|
179
|
+
sym_node = send_node.last_argument.children.first
|
|
180
|
+
sym_node.sym_type? && sym_node.children.first == method_name
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def negated_predicate?(node1, node2)
|
|
184
|
+
return false unless node1.any_block_type? && node2.any_block_type?
|
|
185
|
+
return false unless node1.type == node2.type
|
|
186
|
+
return false if node1.block_type? && node1.arguments != node2.arguments
|
|
187
|
+
|
|
188
|
+
negated_body?(node1.body, node2.body) || negated_body?(node2.body, node1.body)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def negated_body?(body1, body2)
|
|
192
|
+
body1&.send_type? && body1.method?(:!) && body1.receiver == body2
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def register_offense(node, sibling, container, sibling_container)
|
|
196
|
+
message = format(MSG, first: sibling.method_name, second: node.method_name)
|
|
197
|
+
|
|
198
|
+
add_offense(container, message: message) do |corrector|
|
|
199
|
+
next unless both_lvasgn?(container, sibling_container)
|
|
200
|
+
|
|
201
|
+
autocorrect(corrector, node, sibling, container, sibling_container)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def both_lvasgn?(container, sibling_container)
|
|
206
|
+
container.lvasgn_type? && sibling_container.lvasgn_type?
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def autocorrect(corrector, node, sibling, container, sibling_container)
|
|
210
|
+
if complementary_pair?(node, sibling)
|
|
211
|
+
select_var, reject_var =
|
|
212
|
+
complementary_variable_order(sibling, container, sibling_container)
|
|
213
|
+
partition_node = select_node_for(sibling, container)
|
|
214
|
+
else
|
|
215
|
+
select_var, reject_var, partition_node =
|
|
216
|
+
negation_partition_args(node, sibling, container, sibling_container)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
partition_call = build_partition_call(partition_node)
|
|
220
|
+
replacement = "#{select_var}, #{reject_var} = #{partition_call}"
|
|
221
|
+
|
|
222
|
+
corrector.replace(sibling_container, replacement)
|
|
223
|
+
range = range_by_whole_lines(container.source_range, include_final_newline: true)
|
|
224
|
+
corrector.remove(range)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def complementary_variable_order(sibling, container, sibling_container)
|
|
228
|
+
if SELECT_METHODS.include?(sibling.method_name)
|
|
229
|
+
[sibling_container.children.first, container.children.first]
|
|
230
|
+
else
|
|
231
|
+
[container.children.first, sibling_container.children.first]
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def negation_partition_args(node, sibling, container, sibling_container)
|
|
236
|
+
node_is_negated = negated_body?(node.body, sibling.body)
|
|
237
|
+
is_select = SELECT_METHODS.include?(node.method_name)
|
|
238
|
+
# For select: non-negated is truthy (first). For reject: negated is truthy (first).
|
|
239
|
+
node_is_truthy = is_select != node_is_negated
|
|
240
|
+
partition_node = node_is_negated ? sibling : node
|
|
241
|
+
|
|
242
|
+
if node_is_truthy
|
|
243
|
+
[container.children.first, sibling_container.children.first, partition_node]
|
|
244
|
+
else
|
|
245
|
+
[sibling_container.children.first, container.children.first, partition_node]
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def select_node_for(sibling, container)
|
|
250
|
+
if SELECT_METHODS.include?(sibling.method_name)
|
|
251
|
+
sibling
|
|
252
|
+
else
|
|
253
|
+
container.children.last
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def build_partition_call(node)
|
|
258
|
+
source = node.source
|
|
259
|
+
send_node = node.any_block_type? ? node.send_node : node
|
|
260
|
+
selector = send_node.loc.selector
|
|
261
|
+
offset = node.source_range.begin_pos
|
|
262
|
+
method_start = selector.begin_pos - offset
|
|
263
|
+
method_end = selector.end_pos - offset
|
|
264
|
+
|
|
265
|
+
"#{source[0...method_start]}partition#{source[method_end..]}"
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
@@ -4,6 +4,8 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Enforces the consistent usage of `%`-literal delimiters.
|
|
7
|
+
# Using consistent delimiters across the codebase reduces
|
|
8
|
+
# cognitive load when reading `%`-literals.
|
|
7
9
|
#
|
|
8
10
|
# Specify the 'default' key to set all preferred delimiters at once. You
|
|
9
11
|
# can continue to specify individual preferred delimiters to override the
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Looks for uses of `any?`, `all?`, `none?`, or `one?` with a block
|
|
7
|
+
# containing only an `is_a?`, `kind_of?`, or `instance_of?` check, and
|
|
8
|
+
# suggests using the predicate method with the class argument directly.
|
|
9
|
+
#
|
|
10
|
+
# @safety
|
|
11
|
+
# This cop is unsafe because `instance_of?` checks for an exact class
|
|
12
|
+
# match, while the pattern argument uses `===` which also matches
|
|
13
|
+
# subclasses. For `is_a?` and `kind_of?`, the behavior is equivalent.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# # bad
|
|
17
|
+
# array.any? { |x| x.is_a?(Integer) }
|
|
18
|
+
# array.all? { |x| x.kind_of?(String) }
|
|
19
|
+
# array.none? { |x| x.is_a?(Float) }
|
|
20
|
+
# array.one? { |x| x.instance_of?(Symbol) }
|
|
21
|
+
#
|
|
22
|
+
# # good
|
|
23
|
+
# array.any?(Integer)
|
|
24
|
+
# array.all?(String)
|
|
25
|
+
# array.none?(Float)
|
|
26
|
+
# array.one?(Symbol)
|
|
27
|
+
class PredicateWithKind < Base
|
|
28
|
+
extend AutoCorrector
|
|
29
|
+
include RangeHelp
|
|
30
|
+
|
|
31
|
+
MSG = 'Prefer `%<replacement>s` to `%<original>s` with a kind check.'
|
|
32
|
+
RESTRICT_ON_SEND = %i[any? all? none? one?].freeze
|
|
33
|
+
KIND_METHODS = %i[is_a? kind_of? instance_of?].to_set.freeze
|
|
34
|
+
|
|
35
|
+
# @!method kind_check?(node)
|
|
36
|
+
def_node_matcher :kind_check?, <<~PATTERN
|
|
37
|
+
{
|
|
38
|
+
(block call (args (arg $_)) $(send (lvar _) %KIND_METHODS _))
|
|
39
|
+
(numblock call $1 $(send (lvar _) %KIND_METHODS _))
|
|
40
|
+
(itblock call $_ $(send (lvar _) %KIND_METHODS _))
|
|
41
|
+
}
|
|
42
|
+
PATTERN
|
|
43
|
+
|
|
44
|
+
# @!method kind_call?(node, name)
|
|
45
|
+
def_node_matcher :kind_call?, <<~PATTERN
|
|
46
|
+
(send (lvar %1) %KIND_METHODS _)
|
|
47
|
+
PATTERN
|
|
48
|
+
|
|
49
|
+
def on_send(node)
|
|
50
|
+
return unless (block_node = node.block_node)
|
|
51
|
+
return if block_node.body&.begin_type?
|
|
52
|
+
return unless (kind_check_node = extract_send_node(block_node))
|
|
53
|
+
|
|
54
|
+
klass = kind_check_node.first_argument
|
|
55
|
+
replacement = "#{node.method_name}(#{klass.source})"
|
|
56
|
+
|
|
57
|
+
register_offense(node, block_node, klass, replacement)
|
|
58
|
+
end
|
|
59
|
+
alias on_csend on_send
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def extract_send_node(block_node)
|
|
64
|
+
return unless (block_arg_name, kind_check_node = kind_check?(block_node))
|
|
65
|
+
|
|
66
|
+
block_arg_name = :"_#{block_arg_name}" if block_node.numblock_type?
|
|
67
|
+
block_arg_name = :it if block_node.type?(:itblock)
|
|
68
|
+
|
|
69
|
+
kind_check_node if kind_call?(kind_check_node, block_arg_name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def register_offense(node, block_node, klass, replacement)
|
|
73
|
+
original = "#{node.method_name} { ... }"
|
|
74
|
+
message = format(MSG, replacement: replacement, original: original)
|
|
75
|
+
|
|
76
|
+
add_offense(block_node, message: message) do |corrector|
|
|
77
|
+
range = range_between(node.loc.selector.begin_pos, block_node.loc.end.end_pos)
|
|
78
|
+
corrector.replace(range, "#{node.method_name}(#{klass.source})")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -14,22 +14,22 @@ module RuboCop
|
|
|
14
14
|
# is a `Hash` or responds to the replacement methods.
|
|
15
15
|
#
|
|
16
16
|
# @example EnforcedStyle: short (default)
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
17
|
+
# # bad
|
|
18
|
+
# Hash#has_key?
|
|
19
|
+
# Hash#has_value?
|
|
20
20
|
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
21
|
+
# # good
|
|
22
|
+
# Hash#key?
|
|
23
|
+
# Hash#value?
|
|
24
24
|
#
|
|
25
25
|
# @example EnforcedStyle: verbose
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
26
|
+
# # bad
|
|
27
|
+
# Hash#key?
|
|
28
|
+
# Hash#value?
|
|
29
29
|
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
30
|
+
# # good
|
|
31
|
+
# Hash#has_key?
|
|
32
|
+
# Hash#has_value?
|
|
33
33
|
class PreferredHashMethods < Base
|
|
34
34
|
include ConfigurableEnforcedStyle
|
|
35
35
|
extend AutoCorrector
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for uses of Proc.new where Kernel#proc
|
|
7
|
-
# would be more appropriate.
|
|
6
|
+
# Checks for uses of `Proc.new` where `Kernel#proc`
|
|
7
|
+
# would be more appropriate. `proc` is the shorter and
|
|
8
|
+
# more idiomatic way to create procs in Ruby.
|
|
8
9
|
#
|
|
9
10
|
# @example
|
|
10
11
|
# # bad
|
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
|
51
51
|
EXPLODED_MSG = 'Provide an exception class and message as arguments to `%<method>s`.'
|
|
52
52
|
COMPACT_MSG = 'Provide an exception object as an argument to `%<method>s`.'
|
|
53
53
|
ACCEPTABLE_ARG_TYPES = %i[
|
|
54
|
-
hash forwarded_restarg splat
|
|
54
|
+
hash forwarded_restarg splat forwarded_kwrestarg forwarded_args
|
|
55
55
|
].freeze
|
|
56
56
|
|
|
57
57
|
RESTRICT_ON_SEND = %i[raise fail].freeze
|