rubocop 1.80.2 → 1.86.1
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 +170 -19
- data/config/obsoletion.yml +9 -0
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +3 -3
- 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 +1 -1
- data/lib/rubocop/cli.rb +28 -6
- data/lib/rubocop/comment_config.rb +62 -17
- data/lib/rubocop/config.rb +14 -10
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +20 -21
- data/lib/rubocop/config_loader_resolver.rb +9 -7
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_store.rb +6 -1
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
- 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 +22 -6
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/documentation.rb +2 -3
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
- 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/case_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +13 -6
- data/lib/rubocop/cop/layout/dot_position.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +12 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- 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 +8 -1
- 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 +111 -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_indentation.rb +204 -39
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +6 -4
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -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_in_lambda_literal.rb +9 -8
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
- data/lib/rubocop/cop/lint/constant_reassignment.rb +59 -9
- data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
- 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_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/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/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 +16 -6
- 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 +3 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
- 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/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 +10 -2
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- 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/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
- 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/useless_assignment.rb +45 -17
- 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/utils/nil_receiver_checker.rb +24 -9
- data/lib/rubocop/cop/lint/void.rb +39 -12
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- 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/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/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/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +4 -2
- data/lib/rubocop/cop/naming/predicate_method.rb +27 -4
- data/lib/rubocop/cop/naming/predicate_prefix.rb +11 -11
- data/lib/rubocop/cop/offense.rb +9 -1
- data/lib/rubocop/cop/registry.rb +20 -13
- data/lib/rubocop/cop/security/eval.rb +15 -2
- 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 +4 -1
- 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 +2 -2
- 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/block_delimiters.rb +27 -34
- data/lib/rubocop/cop/style/case_equality.rb +15 -13
- data/lib/rubocop/cop/style/class_and_module_children.rb +11 -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 +1 -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/float_division.rb +15 -1
- data/lib/rubocop/cop/style/for.rb +3 -0
- 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_lookup_method.rb +101 -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 +1 -5
- 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/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 +2 -2
- 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/module_member_existence_check.rb +107 -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 +184 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
- 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 +26 -22
- 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_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
- data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
- 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/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 +8 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/super_arguments.rb +2 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +4 -3
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- 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/yoda_expression.rb +1 -1
- data/lib/rubocop/cop/team.rb +4 -4
- 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/cops_documentation_generator.rb +4 -4
- data/lib/rubocop/directive_comment.rb +48 -4
- data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
- 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 +12 -5
- data/lib/rubocop/lsp/runtime.rb +13 -3
- 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 +10 -1
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +10 -8
- data/lib/rubocop/result_cache.rb +60 -37
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/shared_contexts.rb +18 -5
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +12 -3
- data/lib/rubocop/server/cache.rb +6 -29
- data/lib/rubocop/server/core.rb +2 -0
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +31 -14
- data/lib/rubocop/version.rb +2 -2
- data/lib/rubocop.rb +20 -0
- data/lib/ruby_lsp/rubocop/addon.rb +23 -8
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +33 -9
|
@@ -6,18 +6,18 @@ module RuboCop
|
|
|
6
6
|
# Checks for use of the lambda.(args) syntax.
|
|
7
7
|
#
|
|
8
8
|
# @example EnforcedStyle: call (default)
|
|
9
|
-
#
|
|
10
|
-
#
|
|
9
|
+
# # bad
|
|
10
|
+
# lambda.(x, y)
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
12
|
+
# # good
|
|
13
|
+
# lambda.call(x, y)
|
|
14
14
|
#
|
|
15
15
|
# @example EnforcedStyle: braces
|
|
16
|
-
#
|
|
17
|
-
#
|
|
16
|
+
# # bad
|
|
17
|
+
# lambda.call(x, y)
|
|
18
18
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
19
|
+
# # good
|
|
20
|
+
# lambda.(x, y)
|
|
21
21
|
class LambdaCall < Base
|
|
22
22
|
include ConfigurableEnforcedStyle
|
|
23
23
|
extend AutoCorrector
|
|
@@ -176,7 +176,7 @@ module RuboCop
|
|
|
176
176
|
if first_non_comment_token
|
|
177
177
|
0...first_non_comment_token.line
|
|
178
178
|
else
|
|
179
|
-
|
|
179
|
+
0..
|
|
180
180
|
end
|
|
181
181
|
end
|
|
182
182
|
|
|
@@ -299,7 +299,7 @@ module RuboCop
|
|
|
299
299
|
end
|
|
300
300
|
|
|
301
301
|
def supported_capitalizations
|
|
302
|
-
cop_config['SupportedCapitalizations'].map(&:to_sym)
|
|
302
|
+
@supported_capitalizations ||= cop_config['SupportedCapitalizations'].map(&:to_sym).freeze
|
|
303
303
|
end
|
|
304
304
|
end
|
|
305
305
|
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for `map { |x| x.to_s }.join` and similar calls where the
|
|
7
|
+
# `map` is redundant because `Array#join` implicitly calls `#to_s` on
|
|
8
|
+
# each element.
|
|
9
|
+
#
|
|
10
|
+
# @safety
|
|
11
|
+
# This cop is unsafe because it cannot guarantee that the receiver
|
|
12
|
+
# is an `Array` by static analysis. If the receiver does not have
|
|
13
|
+
# an `Array#join`-compatible implementation (i.e. one that calls
|
|
14
|
+
# `#to_s` on elements), the correction may change behavior.
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# # bad
|
|
18
|
+
# array.map(&:to_s).join(', ')
|
|
19
|
+
#
|
|
20
|
+
# # bad
|
|
21
|
+
# array.map { |x| x.to_s }.join(', ')
|
|
22
|
+
#
|
|
23
|
+
# # bad
|
|
24
|
+
# array.collect(&:to_s).join
|
|
25
|
+
#
|
|
26
|
+
# # good
|
|
27
|
+
# array.join(', ')
|
|
28
|
+
#
|
|
29
|
+
# # good
|
|
30
|
+
# array.join
|
|
31
|
+
#
|
|
32
|
+
class MapJoin < Base
|
|
33
|
+
extend AutoCorrector
|
|
34
|
+
include RangeHelp
|
|
35
|
+
|
|
36
|
+
MSG = 'Remove redundant `%<method>s(&:to_s)` before `join`.'
|
|
37
|
+
RESTRICT_ON_SEND = %i[join].freeze
|
|
38
|
+
|
|
39
|
+
# map(&:to_s).join(...)
|
|
40
|
+
# @!method map_to_s_join?(node)
|
|
41
|
+
def_node_matcher :map_to_s_join?, <<~PATTERN
|
|
42
|
+
(call
|
|
43
|
+
$(call _ ${:map :collect} (block_pass (sym :to_s)))
|
|
44
|
+
:join ...)
|
|
45
|
+
PATTERN
|
|
46
|
+
|
|
47
|
+
# map { |x| x.to_s }.join(...)
|
|
48
|
+
# @!method map_to_s_block_join?(node)
|
|
49
|
+
def_node_matcher :map_to_s_block_join?, <<~PATTERN
|
|
50
|
+
(call
|
|
51
|
+
$(block
|
|
52
|
+
(call _ ${:map :collect})
|
|
53
|
+
(args (arg _x))
|
|
54
|
+
(send (lvar _x) :to_s))
|
|
55
|
+
:join ...)
|
|
56
|
+
PATTERN
|
|
57
|
+
|
|
58
|
+
# map { _1.to_s }.join(...)
|
|
59
|
+
# @!method map_to_s_numblock_join?(node)
|
|
60
|
+
def_node_matcher :map_to_s_numblock_join?, <<~PATTERN
|
|
61
|
+
(call
|
|
62
|
+
$(numblock
|
|
63
|
+
(call _ ${:map :collect})
|
|
64
|
+
1
|
|
65
|
+
(send (lvar :_1) :to_s))
|
|
66
|
+
:join ...)
|
|
67
|
+
PATTERN
|
|
68
|
+
|
|
69
|
+
# map { it.to_s }.join(...)
|
|
70
|
+
# @!method map_to_s_itblock_join?(node)
|
|
71
|
+
def_node_matcher :map_to_s_itblock_join?, <<~PATTERN
|
|
72
|
+
(call
|
|
73
|
+
$(itblock
|
|
74
|
+
(call _ ${:map :collect})
|
|
75
|
+
:it
|
|
76
|
+
(send (lvar :it) :to_s))
|
|
77
|
+
:join ...)
|
|
78
|
+
PATTERN
|
|
79
|
+
|
|
80
|
+
def on_send(node)
|
|
81
|
+
map_to_s_join?(node) { |m, n| register_offense(node, m, n) } ||
|
|
82
|
+
map_to_s_block_join?(node) { |m, n| register_offense(node, m, n) } ||
|
|
83
|
+
map_to_s_numblock_join?(node) { |m, n| register_offense(node, m, n) } ||
|
|
84
|
+
map_to_s_itblock_join?(node) { |m, n| register_offense(node, m, n) }
|
|
85
|
+
end
|
|
86
|
+
alias on_csend on_send
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def register_offense(join_node, map_node, method_name)
|
|
91
|
+
map_send = map_node.any_block_type? ? map_node.send_node : map_node
|
|
92
|
+
message = format(MSG, method: method_name)
|
|
93
|
+
|
|
94
|
+
add_offense(map_send.loc.selector, message: message) do |corrector|
|
|
95
|
+
remove_map_call(corrector, join_node, map_node, map_send)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def remove_map_call(corrector, join_node, map_node, map_send)
|
|
100
|
+
receiver = map_send.receiver
|
|
101
|
+
if receiver
|
|
102
|
+
corrector.replace(removal_range(receiver, map_node, map_send), '')
|
|
103
|
+
else
|
|
104
|
+
corrector.replace(no_receiver_range(map_node, join_node), '')
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def removal_range(receiver, map_node, map_send)
|
|
109
|
+
start_pos = if receiver.last_line < map_send.loc.dot.line
|
|
110
|
+
receiver.source_range.end_pos
|
|
111
|
+
else
|
|
112
|
+
map_send.loc.dot.begin_pos
|
|
113
|
+
end
|
|
114
|
+
range_between(start_pos, map_node.source_range.end_pos)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def no_receiver_range(map_node, join_node)
|
|
118
|
+
range_between(map_node.source_range.begin_pos, join_node.loc.dot.end_pos)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -33,13 +33,26 @@ module RuboCop
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def included_macros_list
|
|
36
|
-
cop_config.fetch('IncludedMacros', []).map(&:to_sym)
|
|
36
|
+
@included_macros_list ||= cop_config.fetch('IncludedMacros', []).map(&:to_sym).freeze
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def included_macro_patterns
|
|
40
|
+
@included_macro_patterns ||=
|
|
41
|
+
cop_config.fetch('IncludedMacroPatterns', [])
|
|
42
|
+
.map { |pattern| Regexp.new(pattern) }.freeze
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def matches_included_macro_pattern?(method_name)
|
|
46
|
+
included_macro_patterns.any? do |pattern|
|
|
47
|
+
pattern.match?(method_name.to_s)
|
|
48
|
+
end
|
|
37
49
|
end
|
|
38
50
|
|
|
39
51
|
def ignored_macro?(node)
|
|
40
52
|
cop_config['IgnoreMacros'] &&
|
|
41
53
|
node.macro? &&
|
|
42
|
-
!included_macros_list.include?(node.method_name)
|
|
54
|
+
!included_macros_list.include?(node.method_name) &&
|
|
55
|
+
!matches_included_macro_pattern?(node.method_name)
|
|
43
56
|
end
|
|
44
57
|
end
|
|
45
58
|
end
|
|
@@ -9,17 +9,20 @@ module RuboCop
|
|
|
9
9
|
# In the default style (require_parentheses), macro methods are allowed.
|
|
10
10
|
# Additional methods can be added to the `AllowedMethods` or
|
|
11
11
|
# `AllowedPatterns` list. These options are valid only in the default
|
|
12
|
-
# style. Macros can be included by either setting `IgnoreMacros` to false
|
|
13
|
-
#
|
|
12
|
+
# style. Macros can be included by either setting `IgnoreMacros` to false,
|
|
13
|
+
# adding specific macros to the `IncludedMacros` list, or using
|
|
14
|
+
# `IncludedMacroPatterns` for pattern-based matching.
|
|
14
15
|
#
|
|
15
16
|
# Precedence of options is as follows:
|
|
16
17
|
#
|
|
17
18
|
# 1. `AllowedMethods`
|
|
18
19
|
# 2. `AllowedPatterns`
|
|
19
20
|
# 3. `IncludedMacros`
|
|
21
|
+
# 4. `IncludedMacroPatterns`
|
|
20
22
|
#
|
|
21
|
-
# If a method is listed in both `IncludedMacros`
|
|
22
|
-
# then the latter takes precedence (that is, the
|
|
23
|
+
# If a method is listed in both `IncludedMacros`/`IncludedMacroPatterns`
|
|
24
|
+
# and `AllowedMethods`, then the latter takes precedence (that is, the
|
|
25
|
+
# method is allowed).
|
|
23
26
|
#
|
|
24
27
|
# In the alternative style (omit_parentheses), there are three additional
|
|
25
28
|
# options.
|
|
@@ -148,6 +151,16 @@ module RuboCop
|
|
|
148
151
|
# # still enforces parentheses on other methods
|
|
149
152
|
# array.delete(e)
|
|
150
153
|
#
|
|
154
|
+
# @example IncludedMacroPatterns: ["^assert", "^refute"]
|
|
155
|
+
#
|
|
156
|
+
# # bad
|
|
157
|
+
# assert_equal 'test', x
|
|
158
|
+
# refute_nil value
|
|
159
|
+
#
|
|
160
|
+
# # good
|
|
161
|
+
# assert_equal('test', x)
|
|
162
|
+
# refute_nil(value)
|
|
163
|
+
#
|
|
151
164
|
# @example AllowParenthesesInMultilineCall: false (default)
|
|
152
165
|
#
|
|
153
166
|
# # bad
|
|
@@ -103,8 +103,6 @@ module RuboCop
|
|
|
103
103
|
MSG_MISSING = 'Use def with parentheses when there are parameters.'
|
|
104
104
|
|
|
105
105
|
def on_def(node)
|
|
106
|
-
return if forced_parentheses?(node)
|
|
107
|
-
|
|
108
106
|
args = node.arguments
|
|
109
107
|
|
|
110
108
|
if require_parentheses?(args)
|
|
@@ -113,10 +111,10 @@ module RuboCop
|
|
|
113
111
|
else
|
|
114
112
|
correct_style_detected
|
|
115
113
|
end
|
|
114
|
+
elsif forced_parentheses?(node)
|
|
115
|
+
correct_style_detected
|
|
116
116
|
elsif parentheses?(args)
|
|
117
117
|
unwanted_parentheses(args)
|
|
118
|
-
else
|
|
119
|
-
correct_style_detected
|
|
120
118
|
end
|
|
121
119
|
end
|
|
122
120
|
alias on_defs on_def
|
|
@@ -0,0 +1,107 @@
|
|
|
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
|
+
# @example
|
|
17
|
+
# # bad
|
|
18
|
+
# Array.instance_methods.include?(:size)
|
|
19
|
+
# Array.instance_methods.member?(:size)
|
|
20
|
+
# Array.instance_methods(true).include?(:size)
|
|
21
|
+
#
|
|
22
|
+
# Array.instance_methods(false).include?(:find)
|
|
23
|
+
#
|
|
24
|
+
# # good
|
|
25
|
+
# Array.method_defined?(:size)
|
|
26
|
+
#
|
|
27
|
+
# Array.method_defined?(:find, false)
|
|
28
|
+
#
|
|
29
|
+
# # bad
|
|
30
|
+
# Array.class_variables.include?(:foo)
|
|
31
|
+
# Array.constants.include?(:foo)
|
|
32
|
+
# Array.private_instance_methods.include?(:foo)
|
|
33
|
+
# Array.protected_instance_methods.include?(:foo)
|
|
34
|
+
# Array.public_instance_methods.include?(:foo)
|
|
35
|
+
#
|
|
36
|
+
# # good
|
|
37
|
+
# Array.class_variable_defined?(:foo)
|
|
38
|
+
# Array.const_defined?(:foo)
|
|
39
|
+
# Array.private_method_defined?(:foo)
|
|
40
|
+
# Array.protected_method_defined?(:foo)
|
|
41
|
+
# Array.public_method_defined?(:foo)
|
|
42
|
+
#
|
|
43
|
+
class ModuleMemberExistenceCheck < Base
|
|
44
|
+
extend AutoCorrector
|
|
45
|
+
|
|
46
|
+
MSG = 'Use `%<replacement>s` instead.'
|
|
47
|
+
|
|
48
|
+
# @!method module_member_inclusion?(node)
|
|
49
|
+
def_node_matcher :module_member_inclusion?, <<~PATTERN
|
|
50
|
+
(call
|
|
51
|
+
{(call _ %METHODS_WITH_INHERIT_PARAM _?) (call _ %METHODS_WITHOUT_INHERIT_PARAM)}
|
|
52
|
+
{:include? :member?}
|
|
53
|
+
_)
|
|
54
|
+
PATTERN
|
|
55
|
+
|
|
56
|
+
METHOD_REPLACEMENTS = {
|
|
57
|
+
class_variables: :class_variable_defined?,
|
|
58
|
+
constants: :const_defined?,
|
|
59
|
+
instance_methods: :method_defined?,
|
|
60
|
+
private_instance_methods: :private_method_defined?,
|
|
61
|
+
protected_instance_methods: :protected_method_defined?,
|
|
62
|
+
public_instance_methods: :public_method_defined?
|
|
63
|
+
}.freeze
|
|
64
|
+
|
|
65
|
+
METHODS_WITHOUT_INHERIT_PARAM = Set[:class_variables].freeze
|
|
66
|
+
METHODS_WITH_INHERIT_PARAM =
|
|
67
|
+
(METHOD_REPLACEMENTS.keys.to_set - METHODS_WITHOUT_INHERIT_PARAM).freeze
|
|
68
|
+
|
|
69
|
+
RESTRICT_ON_SEND = METHOD_REPLACEMENTS.keys.freeze
|
|
70
|
+
|
|
71
|
+
def on_send(node)
|
|
72
|
+
return unless (parent = node.parent)
|
|
73
|
+
return unless module_member_inclusion?(parent)
|
|
74
|
+
return unless simple_method_argument?(node) && simple_method_argument?(parent)
|
|
75
|
+
|
|
76
|
+
offense_range = node.location.selector.join(parent.source_range.end)
|
|
77
|
+
replacement = replacement_for(node, parent)
|
|
78
|
+
|
|
79
|
+
add_offense(offense_range, message: format(MSG, replacement: replacement)) do |corrector|
|
|
80
|
+
corrector.replace(offense_range, replacement)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
alias on_csend on_send
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def replacement_for(node, parent)
|
|
88
|
+
replacement_method = METHOD_REPLACEMENTS.fetch(node.method_name)
|
|
89
|
+
without_inherit_param = METHODS_WITHOUT_INHERIT_PARAM.include?(node.method_name)
|
|
90
|
+
|
|
91
|
+
if without_inherit_param || node.first_argument.nil? || node.first_argument.true_type?
|
|
92
|
+
"#{replacement_method}(#{parent.first_argument.source})"
|
|
93
|
+
else
|
|
94
|
+
"#{replacement_method}(#{parent.first_argument.source}, #{node.first_argument.source})"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def simple_method_argument?(node)
|
|
99
|
+
return false if node.splat_argument? || node.block_argument?
|
|
100
|
+
return false if node.first_argument&.hash_type?
|
|
101
|
+
|
|
102
|
+
true
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
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
|