rubocop 1.79.2 → 1.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +185 -20
- data/config/obsoletion.yml +9 -0
- data/exe/rubocop +1 -8
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +30 -4
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/lsp.rb +1 -1
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli/command/show_cops.rb +2 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +35 -9
- data/lib/rubocop/comment_config.rb +59 -17
- data/lib/rubocop/config.rb +14 -10
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +37 -23
- data/lib/rubocop/config_loader_resolver.rb +20 -10
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_store.rb +7 -2
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/base.rb +8 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +26 -7
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/documentation.rb +2 -3
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +5 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +14 -7
- data/lib/rubocop/cop/layout/dot_position.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +26 -7
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +10 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- data/lib/rubocop/cop/layout/hash_alignment.rb +3 -6
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +123 -7
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -9
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +229 -39
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +4 -2
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +93 -11
- data/lib/rubocop/cop/lint/constant_resolution.rb +6 -6
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -12
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/else_layout.rb +19 -0
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
- data/lib/rubocop/cop/lint/empty_when.rb +8 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -9
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
- data/lib/rubocop/cop/lint/number_conversion.rb +6 -6
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -11
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- data/lib/rubocop/cop/lint/self_assignment.rb +15 -6
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/to_json.rb +12 -16
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +7 -5
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +48 -25
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +37 -11
- data/lib/rubocop/cop/lint/void.rb +39 -12
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +12 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +4 -6
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
- data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
- data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
- data/lib/rubocop/cop/mixin.rb +86 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_method.rb +32 -8
- data/lib/rubocop/cop/naming/predicate_prefix.rb +12 -12
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +17 -1
- data/lib/rubocop/cop/registry.rb +62 -38
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +15 -4
- data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
- data/lib/rubocop/cop/style/alias.rb +14 -2
- data/lib/rubocop/cop/style/and_or.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
- data/lib/rubocop/cop/style/array_intersect.rb +46 -12
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +5 -2
- data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
- data/lib/rubocop/cop/style/begin_block.rb +3 -1
- data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +27 -34
- data/lib/rubocop/cop/style/case_equality.rb +15 -13
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -2
- data/lib/rubocop/cop/style/collection_compact.rb +36 -16
- data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +8 -18
- data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
- data/lib/rubocop/cop/style/copyright.rb +22 -11
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/documentation.rb +6 -6
- data/lib/rubocop/cop/style/documentation_method.rb +8 -8
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -0
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_class_definition.rb +119 -0
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +0 -6
- data/lib/rubocop/cop/style/encoding.rb +7 -1
- data/lib/rubocop/cop/style/end_block.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +23 -5
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/file_write.rb +18 -16
- data/lib/rubocop/cop/style/float_division.rb +15 -1
- data/lib/rubocop/cop/style/for.rb +3 -0
- data/lib/rubocop/cop/style/format_string.rb +4 -3
- data/lib/rubocop/cop/style/format_string_token.rb +49 -5
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +27 -22
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
- data/lib/rubocop/cop/style/hash_lookup_method.rb +106 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
- data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
- data/lib/rubocop/cop/style/if_unless_modifier.rb +57 -17
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inline_comment.rb +4 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/lambda_call.rb +8 -8
- data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
- data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
- data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
- data/lib/rubocop/cop/style/not.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +21 -12
- data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +6 -2
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
- data/lib/rubocop/cop/style/proc.rb +3 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +37 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +6 -3
- data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
- data/lib/rubocop/cop/style/redundant_each.rb +3 -3
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +26 -5
- data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +36 -30
- data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
- data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +25 -8
- data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
- data/lib/rubocop/cop/style/select_by_range.rb +197 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +25 -7
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +12 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
- data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
- data/lib/rubocop/cop/style/super_arguments.rb +2 -2
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
- data/lib/rubocop/cop/team.rb +87 -36
- data/lib/rubocop/cop/util.rb +2 -3
- data/lib/rubocop/cop/utils/format_string.rb +10 -0
- data/lib/rubocop/cop/variable_force/branch.rb +30 -6
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +9 -7
- data/lib/rubocop/cops_documentation_generator.rb +4 -4
- data/lib/rubocop/directive_comment.rb +48 -4
- data/lib/rubocop/file_patterns.rb +9 -1
- data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +24 -7
- data/lib/rubocop/formatter/formatter_set.rb +2 -2
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
- data/lib/rubocop/formatter/tap_formatter.rb +5 -2
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +22 -21
- data/lib/rubocop/lsp/diagnostic.rb +18 -33
- data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
- data/lib/rubocop/lsp/routes.rb +43 -7
- data/lib/rubocop/lsp/runtime.rb +13 -4
- data/lib/rubocop/lsp/stdin_runner.rb +8 -17
- data/lib/rubocop/magic_comment.rb +20 -0
- data/lib/rubocop/mcp/server.rb +200 -0
- data/lib/rubocop/options.rb +35 -4
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/project_index_loader.rb +66 -0
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +10 -8
- data/lib/rubocop/result_cache.rb +61 -38
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/shared_contexts.rb +39 -5
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +134 -57
- data/lib/rubocop/server/cache.rb +6 -29
- data/lib/rubocop/server/core.rb +2 -0
- data/lib/rubocop/target_finder.rb +17 -10
- data/lib/rubocop/target_ruby.rb +31 -14
- data/lib/rubocop/version.rb +21 -3
- data/lib/rubocop.rb +28 -96
- data/lib/ruby_lsp/rubocop/addon.rb +23 -8
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +38 -9
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for usage of `Module` methods returning arrays that can be replaced
|
|
7
|
+
# with equivalent predicates.
|
|
8
|
+
#
|
|
9
|
+
# Calling a method returning an array then checking if an element is inside
|
|
10
|
+
# it is much slower than using an equivalent predicate method. For example,
|
|
11
|
+
# `instance_methods.include?` will return an array of all public and protected
|
|
12
|
+
# instance methods in the module, then check if a given method is inside that
|
|
13
|
+
# array, while `method_defined?` will do direct method lookup, which is much
|
|
14
|
+
# faster and consumes less memory.
|
|
15
|
+
#
|
|
16
|
+
# NOTE: `constants.include?` is not handled by this cop because
|
|
17
|
+
# `Module#const_defined?` has different lookup behavior than
|
|
18
|
+
# `Module#constants` - `const_defined?` searches up to `Object`
|
|
19
|
+
# (top-level constants like `String`, `Integer`, etc.) while
|
|
20
|
+
# `constants` does not, which can cause behavior changes after autocorrection.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# # bad
|
|
24
|
+
# Array.instance_methods.include?(:size)
|
|
25
|
+
# Array.instance_methods.member?(:size)
|
|
26
|
+
# Array.instance_methods(true).include?(:size)
|
|
27
|
+
#
|
|
28
|
+
# Array.instance_methods(false).include?(:find)
|
|
29
|
+
#
|
|
30
|
+
# # good
|
|
31
|
+
# Array.method_defined?(:size)
|
|
32
|
+
#
|
|
33
|
+
# Array.method_defined?(:find, false)
|
|
34
|
+
#
|
|
35
|
+
# # bad
|
|
36
|
+
# Array.class_variables.include?(:foo)
|
|
37
|
+
# Array.private_instance_methods.include?(:foo)
|
|
38
|
+
# Array.protected_instance_methods.include?(:foo)
|
|
39
|
+
# Array.public_instance_methods.include?(:foo)
|
|
40
|
+
#
|
|
41
|
+
# # good
|
|
42
|
+
# Array.class_variable_defined?(:foo)
|
|
43
|
+
# Array.private_method_defined?(:foo)
|
|
44
|
+
# Array.protected_method_defined?(:foo)
|
|
45
|
+
# Array.public_method_defined?(:foo)
|
|
46
|
+
#
|
|
47
|
+
class ModuleMemberExistenceCheck < Base
|
|
48
|
+
extend AutoCorrector
|
|
49
|
+
|
|
50
|
+
MSG = 'Use `%<replacement>s` instead.'
|
|
51
|
+
|
|
52
|
+
# @!method module_member_inclusion?(node)
|
|
53
|
+
def_node_matcher :module_member_inclusion?, <<~PATTERN
|
|
54
|
+
(call
|
|
55
|
+
{(call _ %METHODS_WITH_INHERIT_PARAM _?) (call _ %METHODS_WITHOUT_INHERIT_PARAM)}
|
|
56
|
+
{:include? :member?}
|
|
57
|
+
_)
|
|
58
|
+
PATTERN
|
|
59
|
+
|
|
60
|
+
METHOD_REPLACEMENTS = {
|
|
61
|
+
class_variables: :class_variable_defined?,
|
|
62
|
+
instance_methods: :method_defined?,
|
|
63
|
+
private_instance_methods: :private_method_defined?,
|
|
64
|
+
protected_instance_methods: :protected_method_defined?,
|
|
65
|
+
public_instance_methods: :public_method_defined?
|
|
66
|
+
}.freeze
|
|
67
|
+
|
|
68
|
+
METHODS_WITHOUT_INHERIT_PARAM = Set[:class_variables].freeze
|
|
69
|
+
METHODS_WITH_INHERIT_PARAM =
|
|
70
|
+
(METHOD_REPLACEMENTS.keys.to_set - METHODS_WITHOUT_INHERIT_PARAM).freeze
|
|
71
|
+
|
|
72
|
+
RESTRICT_ON_SEND = METHOD_REPLACEMENTS.keys.freeze
|
|
73
|
+
|
|
74
|
+
def on_send(node)
|
|
75
|
+
return unless (parent = node.parent)
|
|
76
|
+
return unless module_member_inclusion?(parent)
|
|
77
|
+
return unless simple_method_argument?(node) && simple_method_argument?(parent)
|
|
78
|
+
|
|
79
|
+
offense_range = node.location.selector.join(parent.source_range.end)
|
|
80
|
+
replacement = replacement_for(node, parent)
|
|
81
|
+
|
|
82
|
+
add_offense(offense_range, message: format(MSG, replacement: replacement)) do |corrector|
|
|
83
|
+
corrector.replace(offense_range, replacement)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
alias on_csend on_send
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def replacement_for(node, parent)
|
|
91
|
+
replacement_method = METHOD_REPLACEMENTS.fetch(node.method_name)
|
|
92
|
+
without_inherit_param = METHODS_WITHOUT_INHERIT_PARAM.include?(node.method_name)
|
|
93
|
+
|
|
94
|
+
if without_inherit_param || node.first_argument.nil? || node.first_argument.true_type?
|
|
95
|
+
"#{replacement_method}(#{parent.first_argument.source})"
|
|
96
|
+
else
|
|
97
|
+
"#{replacement_method}(#{parent.first_argument.source}, #{node.first_argument.source})"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def simple_method_argument?(node)
|
|
102
|
+
return false if node.splat_argument? || node.block_argument?
|
|
103
|
+
return false if node.first_argument&.hash_type?
|
|
104
|
+
|
|
105
|
+
true
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for uses of the `then` keyword in multi-line if statements.
|
|
6
|
+
# Checks for uses of the `then` keyword in multi-line `if` statements.
|
|
7
|
+
# In multi-line `if` statements, `then` is redundant because the newline
|
|
8
|
+
# already separates the condition from the body.
|
|
7
9
|
#
|
|
8
10
|
# @example
|
|
9
11
|
# # bad
|
|
@@ -21,8 +23,6 @@ module RuboCop
|
|
|
21
23
|
include RangeHelp
|
|
22
24
|
extend AutoCorrector
|
|
23
25
|
|
|
24
|
-
NON_MODIFIER_THEN = /then\s*(#.*)?$/.freeze
|
|
25
|
-
|
|
26
26
|
MSG = 'Do not use `then` for multi-line `%<keyword>s`.'
|
|
27
27
|
|
|
28
28
|
def on_normal_if_unless(node)
|
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
|
36
36
|
private
|
|
37
37
|
|
|
38
38
|
def non_modifier_then?(node)
|
|
39
|
-
|
|
39
|
+
node.then? && node.loc.begin.line != node.if_branch&.loc&.line
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
end
|
|
@@ -75,6 +75,8 @@ module RuboCop
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def correction_exceeds_max_line_length?(node)
|
|
78
|
+
return false unless max_line_length
|
|
79
|
+
|
|
78
80
|
indentation_width(node) + definition_width(node) > max_line_length
|
|
79
81
|
end
|
|
80
82
|
|
|
@@ -85,10 +87,6 @@ module RuboCop
|
|
|
85
87
|
def definition_width(node)
|
|
86
88
|
node.source_range.begin.join(node.arguments.source_range.end).length
|
|
87
89
|
end
|
|
88
|
-
|
|
89
|
-
def max_line_length
|
|
90
|
-
config.for_cop('Layout/LineLength')['Max'] || 120
|
|
91
|
-
end
|
|
92
90
|
end
|
|
93
91
|
end
|
|
94
92
|
end
|
|
@@ -125,7 +125,7 @@ module RuboCop
|
|
|
125
125
|
MSG = 'Freeze mutable objects assigned to constants.'
|
|
126
126
|
|
|
127
127
|
def on_casgn(node)
|
|
128
|
-
if node.expression.nil? # This is only the case for `CONST += ...` or
|
|
128
|
+
if node.expression.nil? # This is only the case for `CONST += ...` or similar
|
|
129
129
|
parent = node.parent
|
|
130
130
|
return unless parent.or_asgn_type? # We only care about `CONST ||= ...`
|
|
131
131
|
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Identifies usages of `arr[arr.length - n]`, `arr[arr.size - n]`, or
|
|
7
|
+
# `arr[arr.count - n]` and suggests to change them to use `arr[-n]` instead.
|
|
8
|
+
# Also handles range patterns like `arr[0..(arr.length - n)]`.
|
|
9
|
+
#
|
|
10
|
+
# The cop recognizes preserving methods (`sort`, `reverse`, `shuffle`, `rotate`)
|
|
11
|
+
# and their combinations, allowing safe replacement when the receiver matches.
|
|
12
|
+
# It works with variables, instance variables, class variables, and constants.
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# # bad
|
|
16
|
+
# arr[arr.count - 2]
|
|
17
|
+
# arr[0..(arr.length - 2)]
|
|
18
|
+
# arr[0...(arr.length - 4)]
|
|
19
|
+
# arr.sort[arr.reverse.length - 2]
|
|
20
|
+
# arr.sort.reverse[arr.sort.size - 2]
|
|
21
|
+
#
|
|
22
|
+
# # good
|
|
23
|
+
# arr[-2]
|
|
24
|
+
# arr[0..-2]
|
|
25
|
+
# arr[0...-4]
|
|
26
|
+
# arr.sort[-2]
|
|
27
|
+
# arr.sort.reverse[-2]
|
|
28
|
+
#
|
|
29
|
+
class NegativeArrayIndex < Base
|
|
30
|
+
extend AutoCorrector
|
|
31
|
+
include RangeHelp
|
|
32
|
+
|
|
33
|
+
MSG = 'Use `%<receiver>s[-%<index>s]` instead of `%<current>s`.'
|
|
34
|
+
MSG_RANGE = 'Use `%<receiver>s[%<start>s%<range_op>s-%<index>s]` instead of `%<current>s`.'
|
|
35
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
|
36
|
+
|
|
37
|
+
LENGTH_METHODS = %i[length size count].freeze
|
|
38
|
+
|
|
39
|
+
PRESERVING_METHODS = %i[sort reverse shuffle rotate].freeze
|
|
40
|
+
|
|
41
|
+
# @!method length_subtraction?(node)
|
|
42
|
+
def_node_matcher :length_subtraction?, <<~PATTERN
|
|
43
|
+
(send
|
|
44
|
+
(send $_ {:length :size :count}) :-
|
|
45
|
+
(int $_))
|
|
46
|
+
PATTERN
|
|
47
|
+
|
|
48
|
+
def on_send(node)
|
|
49
|
+
return if node.arguments.empty?
|
|
50
|
+
|
|
51
|
+
index_arg = node.first_argument
|
|
52
|
+
range_node = extract_range_from_begin(index_arg)
|
|
53
|
+
if range_with_length_subtraction?(range_node, node.receiver)
|
|
54
|
+
receiver = node.receiver.source
|
|
55
|
+
return handle_range_pattern(receiver, range_node, index_arg)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
handle_simple_index_pattern(node, index_arg)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
alias on_csend on_send
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def handle_simple_index_pattern(node, index_arg)
|
|
66
|
+
length_receiver, negative_index = length_subtraction?(index_arg)
|
|
67
|
+
|
|
68
|
+
return unless negative_index&.positive?
|
|
69
|
+
return unless receivers_match?(length_receiver, node.receiver)
|
|
70
|
+
|
|
71
|
+
add_offense_for_subtraction(node, index_arg, negative_index)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def extract_range_from_begin(node)
|
|
75
|
+
node.begin_type? ? node.children.first : node
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def extract_inner_end(node)
|
|
79
|
+
node.children.size == 1 ? node.children.first : node
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def add_offense_for_subtraction(node, index_arg, negative_index)
|
|
83
|
+
receiver = node.receiver.source
|
|
84
|
+
offense_range = index_arg.source_range
|
|
85
|
+
current = "#{receiver}[#{index_arg.source}]"
|
|
86
|
+
|
|
87
|
+
message = format(MSG, receiver: receiver, index: negative_index, current: current)
|
|
88
|
+
|
|
89
|
+
add_offense(offense_range, message: message) do |corrector|
|
|
90
|
+
corrector.replace(offense_range, "-#{negative_index}")
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def range_with_length_subtraction?(range_node, array_receiver)
|
|
95
|
+
return false unless range_node.range_type?
|
|
96
|
+
|
|
97
|
+
range_end = range_node.end
|
|
98
|
+
range_start = range_node.begin
|
|
99
|
+
return false unless range_end && range_start
|
|
100
|
+
|
|
101
|
+
return false unless preserving_method?(range_start)
|
|
102
|
+
|
|
103
|
+
inner_end = extract_inner_end(range_end)
|
|
104
|
+
length_receiver, negative_index = length_subtraction?(inner_end)
|
|
105
|
+
|
|
106
|
+
return false unless negative_index&.positive?
|
|
107
|
+
|
|
108
|
+
receivers_match_strict?(length_receiver, array_receiver)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def handle_range_pattern(receiver, range_node, index_arg)
|
|
112
|
+
range_end = range_node.end
|
|
113
|
+
inner_end = extract_inner_end(range_end)
|
|
114
|
+
_length_receiver, negative_index = length_subtraction?(inner_end)
|
|
115
|
+
|
|
116
|
+
message, replacement = build_range_offense_data(
|
|
117
|
+
receiver, range_node, range_end, inner_end, negative_index, index_arg
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
add_offense(range_end, message: message) do |corrector|
|
|
121
|
+
corrector.replace(index_arg, replacement)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# rubocop:disable Metrics/ParameterLists
|
|
126
|
+
def build_range_offense_data(receiver, range_node, range_end, inner_end, negative_index,
|
|
127
|
+
index_arg)
|
|
128
|
+
range_op = range_node.erange_type? ? '...' : '..'
|
|
129
|
+
range_start = range_node.begin.source
|
|
130
|
+
|
|
131
|
+
range_without_parens =
|
|
132
|
+
build_range_without_parens(range_start, range_op, range_end, inner_end)
|
|
133
|
+
current_source = build_current_source(receiver, range_without_parens, index_arg)
|
|
134
|
+
start, index = format_range_message_parts(range_start, negative_index, index_arg)
|
|
135
|
+
|
|
136
|
+
message = build_message_for_range(receiver, start, range_op, index, current_source)
|
|
137
|
+
replacement = build_replacement_string(range_start, range_op, negative_index, index_arg)
|
|
138
|
+
|
|
139
|
+
[message, replacement]
|
|
140
|
+
end
|
|
141
|
+
# rubocop:enable Metrics/ParameterLists
|
|
142
|
+
|
|
143
|
+
def format_range_message_parts(range_start, negative_index, index_arg)
|
|
144
|
+
has_parentheses = index_arg.begin_type?
|
|
145
|
+
start = has_parentheses ? "(#{range_start}" : range_start
|
|
146
|
+
index = has_parentheses ? "#{negative_index})" : negative_index
|
|
147
|
+
|
|
148
|
+
[start, index]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def build_message_for_range(receiver, start, range_op, index, current)
|
|
152
|
+
format(
|
|
153
|
+
MSG_RANGE,
|
|
154
|
+
receiver: receiver, start: start, range_op: range_op, index: index, current: current
|
|
155
|
+
)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def build_replacement_string(range_start, range_op, negative_index, index_arg)
|
|
159
|
+
has_parentheses = index_arg.begin_type?
|
|
160
|
+
|
|
161
|
+
if has_parentheses
|
|
162
|
+
"(#{range_start}#{range_op}-#{negative_index})"
|
|
163
|
+
else
|
|
164
|
+
"#{range_start}#{range_op}-#{negative_index}"
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def build_current_source(receiver, range_without_parens, index_arg)
|
|
169
|
+
has_parentheses = index_arg.begin_type?
|
|
170
|
+
|
|
171
|
+
if has_parentheses
|
|
172
|
+
"#{receiver}[(#{range_without_parens})]"
|
|
173
|
+
else
|
|
174
|
+
"#{receiver}[#{range_without_parens}]"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def build_range_without_parens(range_start, range_op, range_end, inner_end)
|
|
179
|
+
end_expression = range_end.begin_type? ? range_end.source : inner_end.source
|
|
180
|
+
|
|
181
|
+
"#{range_start}#{range_op}#{end_expression}"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def receivers_match?(length_receiver, array_receiver)
|
|
185
|
+
return array_receiver.self_type? unless length_receiver
|
|
186
|
+
|
|
187
|
+
unless preserving_method?(array_receiver) && preserving_method?(length_receiver)
|
|
188
|
+
return false
|
|
189
|
+
end
|
|
190
|
+
return true if length_receiver.source == array_receiver.source
|
|
191
|
+
|
|
192
|
+
!extract_base_receiver(array_receiver).nil?
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def receivers_match_strict?(length_receiver, array_receiver)
|
|
196
|
+
preserving_method?(array_receiver) &&
|
|
197
|
+
length_receiver.source == array_receiver.source
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def extract_base_receiver(node)
|
|
201
|
+
receiver = node.receiver
|
|
202
|
+
|
|
203
|
+
return nil unless receiver
|
|
204
|
+
return receiver unless receiver.receiver
|
|
205
|
+
|
|
206
|
+
extract_base_receiver(receiver)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def preserving_method?(node)
|
|
210
|
+
return true if node.receiver.nil?
|
|
211
|
+
|
|
212
|
+
method_name = node.method_name
|
|
213
|
+
return false unless PRESERVING_METHODS.include?(method_name)
|
|
214
|
+
|
|
215
|
+
preserving_method?(node.receiver)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
@@ -4,9 +4,8 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for comparison of something with nil using `==` and
|
|
7
|
-
# `nil?`.
|
|
8
|
-
#
|
|
9
|
-
# Supported styles are: predicate, comparison.
|
|
7
|
+
# `nil?`. Enforcing a consistent style (either the `nil?`
|
|
8
|
+
# predicate or `==` comparison) improves readability.
|
|
10
9
|
#
|
|
11
10
|
# @example EnforcedStyle: predicate (default)
|
|
12
11
|
#
|
|
@@ -43,24 +42,26 @@ module RuboCop
|
|
|
43
42
|
# @!method nil_check?(node)
|
|
44
43
|
def_node_matcher :nil_check?, '(send _ :nil?)'
|
|
45
44
|
|
|
45
|
+
# rubocop:disable Metrics/AbcSize
|
|
46
46
|
def on_send(node)
|
|
47
47
|
return unless node.receiver
|
|
48
48
|
|
|
49
49
|
style_check?(node) do
|
|
50
50
|
add_offense(node.loc.selector) do |corrector|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
if prefer_comparison?
|
|
52
|
+
range = node.loc.dot.join(node.loc.selector.end)
|
|
53
|
+
corrector.replace(range, ' == nil')
|
|
54
|
+
else
|
|
55
|
+
range = node.receiver.source_range.end.join(node.source_range.end)
|
|
56
|
+
corrector.replace(range, '.nil?')
|
|
57
|
+
end
|
|
58
58
|
|
|
59
59
|
parent = node.parent
|
|
60
60
|
corrector.wrap(node, '(', ')') if parent.respond_to?(:method?) && parent.method?(:!)
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
|
+
# rubocop:enable Metrics/AbcSize
|
|
64
65
|
|
|
65
66
|
private
|
|
66
67
|
|
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
|
43
43
|
{ ({return next break} nil) (nil) }
|
|
44
44
|
PATTERN
|
|
45
45
|
|
|
46
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
46
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
47
47
|
return unless node.lambda_or_proc?
|
|
48
48
|
return unless nil_return?(node.body)
|
|
49
49
|
|
|
@@ -121,17 +121,11 @@ module RuboCop
|
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
def autocorrect_comparison(corrector, node)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
expr.sub(/^(\S*)\s*!=\s*nil/, '!\1.nil?')
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
return if expr == new_code
|
|
133
|
-
|
|
134
|
-
corrector.replace(node, new_code)
|
|
124
|
+
if include_semantic_changes?
|
|
125
|
+
corrector.replace(node, node.receiver.source)
|
|
126
|
+
else
|
|
127
|
+
corrector.replace(node, "!#{node.receiver.source}.nil?")
|
|
128
|
+
end
|
|
135
129
|
end
|
|
136
130
|
|
|
137
131
|
def autocorrect_non_nil(corrector, node, inner_node)
|
|
@@ -4,7 +4,8 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for big numeric literals without `_` between groups
|
|
7
|
-
# of digits in them.
|
|
7
|
+
# of digits in them. Underscores make large numbers easier to
|
|
8
|
+
# read by visually separating groups of digits.
|
|
8
9
|
#
|
|
9
10
|
# Additional allowed patterns can be added by adding regexps to
|
|
10
11
|
# the `AllowedPatterns` configuration. All regexps are treated
|
|
@@ -116,7 +117,7 @@ module RuboCop
|
|
|
116
117
|
end
|
|
117
118
|
|
|
118
119
|
def allowed_numbers
|
|
119
|
-
cop_config.fetch('AllowedNumbers', []).map(&:to_s)
|
|
120
|
+
@allowed_numbers ||= cop_config.fetch('AllowedNumbers', []).map(&:to_s).freeze
|
|
120
121
|
end
|
|
121
122
|
|
|
122
123
|
def allowed_patterns
|
|
@@ -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))
|