rubocop 1.50.2 → 1.59.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/README.md +5 -3
- data/config/default.yml +153 -16
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
- data/lib/rubocop/cli/command/lsp.rb +19 -0
- data/lib/rubocop/cli.rb +4 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_finder.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +4 -3
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
- data/lib/rubocop/config_obsoletion.rb +13 -10
- data/lib/rubocop/cop/autocorrect_logic.rb +3 -1
- data/lib/rubocop/cop/base.rb +6 -2
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
- data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
- data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
- data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
- data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
- data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -21
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +7 -7
- data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +7 -0
- data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
- data/lib/rubocop/cop/layout/dot_position.rb +1 -5
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +7 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +6 -6
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
- data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -5
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
- data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +19 -5
- data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
- data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
- data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
- data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +78 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +34 -5
- data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +63 -4
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
- data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
- data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +5 -3
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +92 -11
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +8 -3
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
- data/lib/rubocop/cop/migration/department_name.rb +2 -2
- data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
- data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/string_help.rb +4 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
- data/lib/rubocop/cop/naming/constant_name.rb +2 -3
- data/lib/rubocop/cop/naming/file_name.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
- data/lib/rubocop/cop/naming/variable_name.rb +6 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
- data/lib/rubocop/cop/style/alias.rb +9 -8
- data/lib/rubocop/cop/style/arguments_forwarding.rb +342 -63
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/array_intersect.rb +13 -5
- data/lib/rubocop/cop/style/attr.rb +11 -1
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/begin_block.rb +1 -2
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
- data/lib/rubocop/cop/style/case_like_if.rb +4 -4
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
- data/lib/rubocop/cop/style/collection_compact.rb +22 -11
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
- data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
- data/lib/rubocop/cop/style/copyright.rb +5 -2
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/dir.rb +1 -1
- data/lib/rubocop/cop/style/dir_empty.rb +8 -14
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +8 -8
- data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/file_read.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
- data/lib/rubocop/cop/style/guard_clause.rb +28 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +84 -32
- data/lib/rubocop/cop/style/hash_except.rb +21 -9
- data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
- data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +31 -5
- data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -6
- data/lib/rubocop/cop/style/lambda.rb +3 -3
- data/lib/rubocop/cop/style/lambda_call.rb +5 -0
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
- data/lib/rubocop/cop/style/map_to_hash.rb +10 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
- data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
- data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +9 -3
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
- data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +9 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +54 -21
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/redundant_return.rb +8 -3
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
- data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
- data/lib/rubocop/cop/style/require_order.rb +11 -5
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
- data/lib/rubocop/cop/style/return_nil.rb +6 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
- data/lib/rubocop/cop/style/sample.rb +2 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +20 -4
- data/lib/rubocop/cop/style/signal_exception.rb +1 -1
- data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
- data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_array.rb +35 -15
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
- data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
- data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +1 -0
- data/lib/rubocop/cops_documentation_generator.rb +1 -1
- data/lib/rubocop/ext/regexp_parser.rb +4 -1
- data/lib/rubocop/file_finder.rb +4 -7
- data/lib/rubocop/formatter/html_formatter.rb +5 -4
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/lsp/logger.rb +22 -0
- data/lib/rubocop/lsp/routes.rb +246 -0
- data/lib/rubocop/lsp/runtime.rb +99 -0
- data/lib/rubocop/lsp/server.rb +68 -0
- data/lib/rubocop/lsp/severity.rb +27 -0
- data/lib/rubocop/magic_comment.rb +12 -10
- data/lib/rubocop/options.rb +11 -1
- data/lib/rubocop/result_cache.rb +5 -2
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts.rb +2 -3
- data/lib/rubocop/runner.rb +6 -4
- data/lib/rubocop/server/cache.rb +1 -0
- data/lib/rubocop/server/client_command/exec.rb +3 -2
- data/lib/rubocop/string_interpreter.rb +3 -3
- data/lib/rubocop/target_finder.rb +7 -3
- data/lib/rubocop/target_ruby.rb +12 -7
- data/lib/rubocop/version.rb +10 -6
- data/lib/rubocop.rb +19 -0
- metadata +54 -15
@@ -8,6 +8,21 @@ module RuboCop
|
|
8
8
|
# This cop identifies places where `do_something(*args, &block)`
|
9
9
|
# can be replaced by `do_something(...)`.
|
10
10
|
#
|
11
|
+
# In Ruby 3.2, anonymous args/kwargs forwarding has been added.
|
12
|
+
#
|
13
|
+
# This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
|
14
|
+
# replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
|
15
|
+
# by setting `UseAnonymousForwarding: false`.
|
16
|
+
#
|
17
|
+
# And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
|
18
|
+
# and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
|
19
|
+
# that are sufficient for anonymizing meaningless naming.
|
20
|
+
#
|
21
|
+
# Meaningless names that are commonly used can be anonymized by default:
|
22
|
+
# e.g., `*args`, `**options`, `&block`, and so on.
|
23
|
+
#
|
24
|
+
# Names not on this list are likely to be meaningful and are allowed by default.
|
25
|
+
#
|
11
26
|
# @example
|
12
27
|
# # bad
|
13
28
|
# def foo(*args, &block)
|
@@ -24,7 +39,27 @@ module RuboCop
|
|
24
39
|
# bar(...)
|
25
40
|
# end
|
26
41
|
#
|
27
|
-
# @example
|
42
|
+
# @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
|
43
|
+
# # bad
|
44
|
+
# def foo(*args, **kwargs)
|
45
|
+
# args_only(*args)
|
46
|
+
# kwargs_only(**kwargs)
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# # good
|
50
|
+
# def foo(*, **)
|
51
|
+
# args_only(*)
|
52
|
+
# kwargs_only(**)
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
|
56
|
+
# # good
|
57
|
+
# def foo(*args, **kwargs)
|
58
|
+
# args_only(*args)
|
59
|
+
# kwargs_only(**kwargs)
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
|
28
63
|
# # good
|
29
64
|
# def foo(*args)
|
30
65
|
# bar(*args)
|
@@ -34,7 +69,7 @@ module RuboCop
|
|
34
69
|
# bar(**kwargs)
|
35
70
|
# end
|
36
71
|
#
|
37
|
-
# @example AllowOnlyRestArgument: false
|
72
|
+
# @example AllowOnlyRestArgument: false (only relevant for Ruby < 3.2)
|
38
73
|
# # bad
|
39
74
|
# # The following code can replace the arguments with `...`,
|
40
75
|
# # but it will change the behavior. Because `...` forwards block also.
|
@@ -46,6 +81,38 @@ module RuboCop
|
|
46
81
|
# bar(**kwargs)
|
47
82
|
# end
|
48
83
|
#
|
84
|
+
# @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
|
85
|
+
# # bad
|
86
|
+
# def foo(*args)
|
87
|
+
# bar(*args)
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # good
|
91
|
+
# def foo(*)
|
92
|
+
# bar(*)
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
|
96
|
+
# # bad
|
97
|
+
# def foo(**kwargs)
|
98
|
+
# bar(**kwargs)
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# # good
|
102
|
+
# def foo(**)
|
103
|
+
# bar(**)
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
|
107
|
+
# # bad
|
108
|
+
# def foo(&block)
|
109
|
+
# bar(&block)
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# # good
|
113
|
+
# def foo(&)
|
114
|
+
# bar(&)
|
115
|
+
# end
|
49
116
|
class ArgumentsForwarding < Base
|
50
117
|
include RangeHelp
|
51
118
|
extend AutoCorrector
|
@@ -53,102 +120,314 @@ module RuboCop
|
|
53
120
|
|
54
121
|
minimum_target_ruby_version 2.7
|
55
122
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
(send _ _ (splat (lvar %1)))
|
67
|
-
(send _ _ (hash (kwsplat (lvar %1))))
|
68
|
-
}
|
69
|
-
PATTERN
|
70
|
-
|
71
|
-
# @!method forwarding_method_arguments?(node, rest_name, block_name, kwargs_name)
|
72
|
-
def_node_matcher :forwarding_method_arguments?, <<~PATTERN
|
73
|
-
{
|
74
|
-
(send _ _
|
75
|
-
(splat (lvar %1))
|
76
|
-
(block-pass {(lvar %2) nil?}))
|
77
|
-
(send _ _
|
78
|
-
(splat (lvar %1))
|
79
|
-
(hash (kwsplat (lvar %3)))
|
80
|
-
(block-pass {(lvar %2) nil?}))
|
81
|
-
}
|
82
|
-
PATTERN
|
123
|
+
FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
|
124
|
+
ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
|
125
|
+
|
126
|
+
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
127
|
+
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
128
|
+
KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
|
129
|
+
|
130
|
+
def self.autocorrect_incompatible_with
|
131
|
+
[Naming::BlockForwarding]
|
132
|
+
end
|
83
133
|
|
84
134
|
def on_def(node)
|
85
135
|
return unless node.body
|
86
|
-
return unless (rest_args_name, args = use_rest_arguments?(node.arguments))
|
87
|
-
return if args.any?(&:default?)
|
88
136
|
|
89
|
-
node.
|
90
|
-
|
137
|
+
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
138
|
+
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
139
|
+
send_nodes = node.each_descendant(:send).to_a
|
140
|
+
|
141
|
+
send_classifications = classify_send_nodes(
|
142
|
+
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
143
|
+
)
|
91
144
|
|
92
|
-
|
93
|
-
all_lvars_as_forwarding_method_arguments?(node, send_node)
|
145
|
+
return if send_classifications.empty?
|
94
146
|
|
95
|
-
|
96
|
-
|
147
|
+
if only_forwards_all?(send_classifications)
|
148
|
+
add_forward_all_offenses(node, send_classifications, forwardable_args)
|
149
|
+
elsif target_ruby_version >= 3.2
|
150
|
+
add_post_ruby_32_offenses(node, send_classifications, forwardable_args)
|
97
151
|
end
|
98
152
|
end
|
153
|
+
|
99
154
|
alias on_defs on_def
|
100
155
|
|
101
156
|
private
|
102
157
|
|
103
|
-
def
|
104
|
-
|
105
|
-
block_arg_name = args.last.source.delete('&') if args.last&.blockarg_type?
|
106
|
-
|
107
|
-
[kwargs_name, block_arg_name].map { |name| name&.to_sym }
|
158
|
+
def extract_forwardable_args(args)
|
159
|
+
[args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
|
108
160
|
end
|
109
161
|
|
110
|
-
def
|
111
|
-
|
162
|
+
def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
163
|
+
restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
|
164
|
+
kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
|
165
|
+
blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
|
112
166
|
|
113
|
-
|
167
|
+
[restarg_node, kwrestarg_node, blockarg_node]
|
114
168
|
end
|
115
169
|
|
116
|
-
def
|
117
|
-
|
170
|
+
def only_forwards_all?(send_classifications)
|
171
|
+
send_classifications.all? { |_, c, _, _| c == :all }
|
172
|
+
end
|
118
173
|
|
119
|
-
|
120
|
-
|
174
|
+
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
175
|
+
send_classifications.each do |send_node, _c, forward_rest, _forward_kwrest|
|
176
|
+
register_forward_all_offense(send_node, send_node, forward_rest)
|
177
|
+
end
|
121
178
|
|
122
|
-
|
179
|
+
rest_arg, _kwrest_arg, _block_arg = *forwardable_args
|
180
|
+
register_forward_all_offense(node, node.arguments, rest_arg)
|
123
181
|
end
|
124
182
|
|
125
|
-
def
|
126
|
-
|
127
|
-
begin_pos = forwarding_method.loc.selector&.end_pos || forwarding_method.loc.dot.end_pos
|
128
|
-
range = range_between(begin_pos, forwarding_method.source_range.end_pos)
|
183
|
+
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
184
|
+
return unless use_anonymous_forwarding?
|
129
185
|
|
130
|
-
|
186
|
+
rest_arg, kwrest_arg, _block_arg = *forwardable_args
|
187
|
+
|
188
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
|
189
|
+
if forward_rest
|
190
|
+
register_forward_args_offense(def_node.arguments, rest_arg)
|
191
|
+
register_forward_args_offense(send_node, forward_rest)
|
192
|
+
end
|
193
|
+
|
194
|
+
if forward_kwrest
|
195
|
+
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
196
|
+
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
197
|
+
end
|
131
198
|
end
|
132
199
|
end
|
133
200
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
137
|
-
|
201
|
+
def non_splat_or_block_pass_lvar_references(body)
|
202
|
+
body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
|
203
|
+
parent = lvar.parent
|
204
|
+
|
205
|
+
next if lvar.lvar_type? && FORWARDING_LVAR_TYPES.include?(parent.type)
|
206
|
+
|
207
|
+
lvar.children.first
|
208
|
+
end.uniq
|
209
|
+
end
|
210
|
+
|
211
|
+
def classify_send_nodes(def_node, send_nodes, referenced_lvars, forwardable_args)
|
212
|
+
send_nodes.filter_map do |send_node|
|
213
|
+
classification_and_forwards = classification_and_forwards(
|
214
|
+
def_node,
|
215
|
+
send_node,
|
216
|
+
referenced_lvars,
|
217
|
+
forwardable_args
|
138
218
|
)
|
139
|
-
|
219
|
+
|
220
|
+
next unless classification_and_forwards
|
221
|
+
|
222
|
+
[send_node, *classification_and_forwards]
|
140
223
|
end
|
141
224
|
end
|
142
225
|
|
143
|
-
def
|
144
|
-
|
226
|
+
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
227
|
+
classifier = SendNodeClassifier.new(
|
228
|
+
def_node,
|
229
|
+
send_node,
|
230
|
+
referenced_lvars,
|
231
|
+
forwardable_args,
|
232
|
+
target_ruby_version: target_ruby_version,
|
233
|
+
allow_only_rest_arguments: allow_only_rest_arguments?
|
234
|
+
)
|
145
235
|
|
146
|
-
|
236
|
+
classification = classifier.classification
|
237
|
+
|
238
|
+
return unless classification
|
239
|
+
|
240
|
+
[classification, classifier.forwarded_rest_arg, classifier.forwarded_kwrest_arg]
|
241
|
+
end
|
242
|
+
|
243
|
+
def redundant_named_arg(arg, config_name, keyword)
|
244
|
+
return nil unless arg
|
245
|
+
|
246
|
+
redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
|
247
|
+
"#{keyword}#{redundant_arg_name}"
|
248
|
+
end << keyword
|
249
|
+
|
250
|
+
redundant_arg_names.include?(arg.source) ? arg : nil
|
251
|
+
end
|
252
|
+
|
253
|
+
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
254
|
+
add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
|
255
|
+
add_parens_if_missing(def_arguments_or_send, corrector)
|
256
|
+
|
257
|
+
corrector.replace(rest_arg_or_splat, '*')
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat)
|
262
|
+
add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector|
|
263
|
+
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
264
|
+
|
265
|
+
corrector.replace(kwrest_arg_or_splat, '**')
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
|
270
|
+
arg_range = arguments_range(def_or_send, rest_or_splat)
|
271
|
+
|
272
|
+
add_offense(arg_range, message: FORWARDING_MSG) do |corrector|
|
273
|
+
add_parens_if_missing(send_or_arguments, corrector)
|
274
|
+
|
275
|
+
corrector.replace(arg_range, '...')
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def arguments_range(node, first_node)
|
280
|
+
arguments = node.arguments.reject { |arg| ADDITIONAL_ARG_TYPES.include?(arg.type) }
|
281
|
+
|
282
|
+
start_node = first_node || arguments.first
|
283
|
+
|
284
|
+
range_between(start_node.source_range.begin_pos, arguments.last.source_range.end_pos)
|
147
285
|
end
|
148
286
|
|
149
287
|
def allow_only_rest_arguments?
|
150
288
|
cop_config.fetch('AllowOnlyRestArgument', true)
|
151
289
|
end
|
290
|
+
|
291
|
+
def use_anonymous_forwarding?
|
292
|
+
cop_config.fetch('UseAnonymousForwarding', false)
|
293
|
+
end
|
294
|
+
|
295
|
+
def add_parens_if_missing(node, corrector)
|
296
|
+
return if parentheses?(node)
|
297
|
+
|
298
|
+
add_parentheses(node, corrector)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
|
302
|
+
class SendNodeClassifier
|
303
|
+
extend NodePattern::Macros
|
304
|
+
|
305
|
+
# @!method forwarded_rest_arg?(node, rest_name)
|
306
|
+
def_node_matcher :forwarded_rest_arg?, '(splat (lvar %1))'
|
307
|
+
|
308
|
+
# @!method extract_forwarded_kwrest_arg(node, kwrest_name)
|
309
|
+
def_node_matcher :extract_forwarded_kwrest_arg, '(hash <$(kwsplat (lvar %1)) ...>)'
|
310
|
+
|
311
|
+
# @!method forwarded_block_arg?(node, block_name)
|
312
|
+
def_node_matcher :forwarded_block_arg?, '(block_pass {(lvar %1) nil?})'
|
313
|
+
|
314
|
+
def initialize(def_node, send_node, referenced_lvars, forwardable_args, **config)
|
315
|
+
@def_node = def_node
|
316
|
+
@send_node = send_node
|
317
|
+
@referenced_lvars = referenced_lvars
|
318
|
+
@rest_arg, @kwrest_arg, @block_arg = *forwardable_args
|
319
|
+
@rest_arg_name, @kwrest_arg_name, @block_arg_name =
|
320
|
+
*forwardable_args.map { |a| a&.name }
|
321
|
+
@config = config
|
322
|
+
end
|
323
|
+
|
324
|
+
def forwarded_rest_arg
|
325
|
+
return nil if referenced_rest_arg?
|
326
|
+
|
327
|
+
arguments.find { |arg| forwarded_rest_arg?(arg, @rest_arg_name) }
|
328
|
+
end
|
329
|
+
|
330
|
+
def forwarded_kwrest_arg
|
331
|
+
return nil if referenced_kwrest_arg?
|
332
|
+
|
333
|
+
arguments.filter_map { |arg| extract_forwarded_kwrest_arg(arg, @kwrest_arg_name) }.first
|
334
|
+
end
|
335
|
+
|
336
|
+
def forwarded_block_arg
|
337
|
+
return nil if referenced_block_arg?
|
338
|
+
|
339
|
+
arguments.find { |arg| forwarded_block_arg?(arg, @block_arg_name) }
|
340
|
+
end
|
341
|
+
|
342
|
+
def classification
|
343
|
+
return nil unless forwarded_rest_arg || forwarded_kwrest_arg
|
344
|
+
|
345
|
+
if can_forward_all?
|
346
|
+
:all
|
347
|
+
else
|
348
|
+
:rest_or_kwrest
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
private
|
353
|
+
|
354
|
+
def can_forward_all?
|
355
|
+
return false if any_arg_referenced?
|
356
|
+
return false if ruby_32_missing_rest_or_kwest?
|
357
|
+
return false unless offensive_block_forwarding?
|
358
|
+
return false if additional_kwargs_or_forwarded_kwargs?
|
359
|
+
|
360
|
+
no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
|
361
|
+
end
|
362
|
+
|
363
|
+
def ruby_32_missing_rest_or_kwest?
|
364
|
+
target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args
|
365
|
+
end
|
366
|
+
|
367
|
+
def offensive_block_forwarding?
|
368
|
+
@block_arg ? forwarded_block_arg : allow_offense_for_no_block?
|
369
|
+
end
|
370
|
+
|
371
|
+
def forwarded_rest_and_kwrest_args
|
372
|
+
forwarded_rest_arg && forwarded_kwrest_arg
|
373
|
+
end
|
374
|
+
|
375
|
+
def arguments
|
376
|
+
@send_node.arguments
|
377
|
+
end
|
378
|
+
|
379
|
+
def referenced_rest_arg?
|
380
|
+
@referenced_lvars.include?(@rest_arg_name)
|
381
|
+
end
|
382
|
+
|
383
|
+
def referenced_kwrest_arg?
|
384
|
+
@referenced_lvars.include?(@kwrest_arg_name)
|
385
|
+
end
|
386
|
+
|
387
|
+
def referenced_block_arg?
|
388
|
+
@referenced_lvars.include?(@block_arg_name)
|
389
|
+
end
|
390
|
+
|
391
|
+
def any_arg_referenced?
|
392
|
+
referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?
|
393
|
+
end
|
394
|
+
|
395
|
+
def target_ruby_version
|
396
|
+
@config.fetch(:target_ruby_version)
|
397
|
+
end
|
398
|
+
|
399
|
+
def no_post_splat_args?
|
400
|
+
return true unless (splat_index = arguments.index(forwarded_rest_arg))
|
401
|
+
|
402
|
+
arg_after_splat = arguments[splat_index + 1]
|
403
|
+
[nil, :hash, :block_pass].include?(arg_after_splat&.type)
|
404
|
+
end
|
405
|
+
|
406
|
+
def additional_kwargs_or_forwarded_kwargs?
|
407
|
+
additional_kwargs? || forward_additional_kwargs?
|
408
|
+
end
|
409
|
+
|
410
|
+
def additional_kwargs?
|
411
|
+
@def_node.arguments.any? { |a| a.kwarg_type? || a.kwoptarg_type? }
|
412
|
+
end
|
413
|
+
|
414
|
+
def forward_additional_kwargs?
|
415
|
+
return false unless forwarded_kwrest_arg
|
416
|
+
|
417
|
+
!forwarded_kwrest_arg.parent.children.one?
|
418
|
+
end
|
419
|
+
|
420
|
+
def allow_offense_for_no_block?
|
421
|
+
!@config.fetch(:allow_only_rest_arguments)
|
422
|
+
end
|
423
|
+
|
424
|
+
def no_additional_args?
|
425
|
+
forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
|
426
|
+
|
427
|
+
@def_node.arguments.size == forwardable_count &&
|
428
|
+
@send_node.arguments.size == forwardable_count
|
429
|
+
end
|
430
|
+
end
|
152
431
|
end
|
153
432
|
end
|
154
433
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
|
7
|
+
# them to use `arr.first` and `arr.last` instead.
|
8
|
+
#
|
9
|
+
# The cop is disabled by default due to safety concerns.
|
10
|
+
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
|
13
|
+
# which returns a value for `0` or `-1` key, but changing these to use
|
14
|
+
# `.first` or `.last` will return first/last tuple instead. Also, String
|
15
|
+
# does not implement `first`/`last` methods.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# arr[0]
|
20
|
+
# arr[-1]
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# arr.first
|
24
|
+
# arr.last
|
25
|
+
# arr[0] = 2
|
26
|
+
# arr[0][-2]
|
27
|
+
#
|
28
|
+
class ArrayFirstLast < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Use `%<preferred>s`.'
|
32
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
33
|
+
|
34
|
+
# rubocop:disable Metrics/AbcSize
|
35
|
+
def on_send(node)
|
36
|
+
return unless node.arguments.size == 1 && node.first_argument.int_type?
|
37
|
+
|
38
|
+
value = node.first_argument.value
|
39
|
+
return unless [0, -1].include?(value)
|
40
|
+
|
41
|
+
node = innermost_braces_node(node)
|
42
|
+
return if node.parent && brace_method?(node.parent)
|
43
|
+
|
44
|
+
preferred = (value.zero? ? 'first' : 'last')
|
45
|
+
add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
|
46
|
+
corrector.replace(node.loc.selector, ".#{preferred}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/AbcSize
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def innermost_braces_node(node)
|
54
|
+
node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
|
55
|
+
node
|
56
|
+
end
|
57
|
+
|
58
|
+
def brace_method?(node)
|
59
|
+
node.send_type? && (node.method?(:[]) || node.method?(:[]=))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -11,6 +11,15 @@ module RuboCop
|
|
11
11
|
# The `array1.intersect?(array2)` method is faster than
|
12
12
|
# `(array1 & array2).any?` and is more readable.
|
13
13
|
#
|
14
|
+
# In cases like the following, compatibility is not ensured,
|
15
|
+
# so it will not be detected when using block argument.
|
16
|
+
#
|
17
|
+
# [source,ruby]
|
18
|
+
# ----
|
19
|
+
# ([1] & [1,2]).any? { |x| false } # => false
|
20
|
+
# [1].intersect?([1,2]) { |x| false } # => true
|
21
|
+
# ----
|
22
|
+
#
|
14
23
|
# @safety
|
15
24
|
# This cop cannot guarantee that `array1` and `array2` are
|
16
25
|
# actually arrays while method `intersect?` is for arrays only.
|
@@ -68,16 +77,15 @@ module RuboCop
|
|
68
77
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
69
78
|
|
70
79
|
def on_send(node)
|
80
|
+
return if (parent = node.parent) && (parent.block_type? || parent.numblock_type?)
|
71
81
|
return unless (receiver, argument, method_name = bad_intersection_check?(node))
|
72
82
|
|
73
83
|
message = message(receiver.source, argument.source, method_name)
|
74
84
|
|
75
85
|
add_offense(node, message: message) do |corrector|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
corrector.replace(node, "!#{receiver.source}.intersect?(#{argument.source})")
|
80
|
-
end
|
86
|
+
bang = straight?(method_name) ? '' : '!'
|
87
|
+
|
88
|
+
corrector.replace(node, "#{bang}#{receiver.source}.intersect?(#{argument.source})")
|
81
89
|
end
|
82
90
|
end
|
83
91
|
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
def on_send(node)
|
25
25
|
return unless node.command?(:attr) && node.arguments?
|
26
26
|
# check only for method definitions in class/module body
|
27
|
-
return if
|
27
|
+
return if allowed_context?(node)
|
28
28
|
|
29
29
|
message = message(node)
|
30
30
|
add_offense(node.loc.selector, message: message) do |corrector|
|
@@ -34,6 +34,16 @@ module RuboCop
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
+
def allowed_context?(node)
|
38
|
+
return false unless (class_node = node.each_ancestor(:class, :block).first)
|
39
|
+
|
40
|
+
(!class_node.class_type? && !class_eval?(class_node)) || define_attr_method?(class_node)
|
41
|
+
end
|
42
|
+
|
43
|
+
def define_attr_method?(node)
|
44
|
+
node.each_descendant(:def).any? { |def_node| def_node.method?(:attr) }
|
45
|
+
end
|
46
|
+
|
37
47
|
def autocorrect(corrector, node)
|
38
48
|
attr_name, setter = *node.arguments
|
39
49
|
|
@@ -16,31 +16,38 @@ module RuboCop
|
|
16
16
|
# File.open('file') do |f|
|
17
17
|
# # ...
|
18
18
|
# end
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# f = Tempfile.open('temp')
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# Tempfile.open('temp') do |f|
|
25
|
+
# # ...
|
26
|
+
# end
|
19
27
|
class AutoResourceCleanup < Base
|
20
|
-
MSG = 'Use the block version of `%<
|
21
|
-
|
22
|
-
TARGET_METHODS = { File: :open }.freeze
|
28
|
+
MSG = 'Use the block version of `%<current>s`.'
|
29
|
+
RESTRICT_ON_SEND = %i[open].freeze
|
23
30
|
|
24
|
-
|
31
|
+
# @!method file_open_method?(node)
|
32
|
+
def_node_matcher :file_open_method?, <<~PATTERN
|
33
|
+
(send (const {nil? cbase} {:File :Tempfile}) :open ...)
|
34
|
+
PATTERN
|
25
35
|
|
26
36
|
def on_send(node)
|
27
|
-
|
28
|
-
next if node.method_name != target_method
|
37
|
+
return if !file_open_method?(node) || cleanup?(node)
|
29
38
|
|
30
|
-
|
31
|
-
next if node.receiver != target_receiver
|
39
|
+
current = node.receiver.source_range.begin.join(node.selector.end).source
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
add_offense(node, message: format(MSG, class: target_class, method: target_method))
|
36
|
-
end
|
41
|
+
add_offense(node, message: format(MSG, current: current))
|
37
42
|
end
|
38
43
|
|
39
44
|
private
|
40
45
|
|
41
46
|
def cleanup?(node)
|
42
|
-
|
43
|
-
|
47
|
+
return true if node.block_argument?
|
48
|
+
return false unless (parent = node.parent)
|
49
|
+
|
50
|
+
parent.block_type? || !parent.lvasgn_type?
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
def on_class(class_node)
|
34
34
|
@macros_to_rewrite[class_node] = Set.new
|
35
35
|
|
36
|
-
find_macros(class_node.body).
|
36
|
+
find_macros(class_node.body).each_value do |macros|
|
37
37
|
bisected = find_bisection(macros)
|
38
38
|
next unless bisected.any?
|
39
39
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
def find_macros(class_def)
|
75
75
|
# Find all the macros (`attr_reader`, `attr_writer`, etc.) in the class body
|
76
76
|
# and turn them into `Macro` objects so that they can be processed.
|
77
|
-
return
|
77
|
+
return {} if !class_def || class_def.def_type?
|
78
78
|
|
79
79
|
send_nodes =
|
80
80
|
if class_def.send_type?
|