rubocop 1.69.2 → 1.72.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +66 -2
- data/lib/rubocop/cli/command/execute_runner.rb +3 -3
- data/lib/rubocop/cli/command/show_cops.rb +24 -2
- data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
- data/lib/rubocop/comment_config.rb +2 -2
- data/lib/rubocop/config.rb +17 -4
- data/lib/rubocop/config_loader.rb +48 -8
- data/lib/rubocop/config_loader_resolver.rb +33 -8
- data/lib/rubocop/config_validator.rb +18 -8
- data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
- data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
- data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
- data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
- data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
- data/lib/rubocop/cop/internal_affairs.rb +5 -16
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
- data/lib/rubocop/cop/layout/block_alignment.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +9 -9
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/line_length.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
- data/lib/rubocop/cop/layout/redundant_line_break.rb +7 -6
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
- data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
- data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
- data/lib/rubocop/cop/lint/debugger.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
- data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
- data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
- data/lib/rubocop/cop/lint/missing_super.rb +2 -2
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -4
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +231 -0
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/syntax.rb +4 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +5 -9
- data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +8 -1
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
- data/lib/rubocop/cop/mixin/alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +11 -11
- data/lib/rubocop/cop/mixin/comments_help.rb +4 -2
- data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
- data/lib/rubocop/cop/mixin/hash_subset.rb +188 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
- data/lib/rubocop/cop/mixin/range_help.rb +3 -3
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
- data/lib/rubocop/cop/mixin/string_help.rb +2 -2
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
- data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
- data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
- data/lib/rubocop/cop/security/compound_hash.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
- data/lib/rubocop/cop/style/array_first_last.rb +18 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +7 -20
- data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
- data/lib/rubocop/cop/style/collection_methods.rb +1 -1
- data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
- data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +3 -3
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -3
- data/lib/rubocop/cop/style/empty_else.rb +4 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
- data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/float_division.rb +8 -4
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +3 -6
- data/lib/rubocop/cop/style/hash_except.rb +24 -148
- data/lib/rubocop/cop/style/hash_slice.rb +80 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -6
- data/lib/rubocop/cop/style/it_assignment.rb +36 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +1 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
- data/lib/rubocop/cop/style/map_to_set.rb +3 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +19 -12
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_else.rb +2 -0
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
- data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +13 -15
- data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/proc.rb +1 -2
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +6 -4
- data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
- data/lib/rubocop/cop/style/redundant_each.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
- data/lib/rubocop/cop/style/redundant_format.rb +238 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
- data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
- data/lib/rubocop/cop/style/redundant_parentheses.rb +28 -14
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
- data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
- data/lib/rubocop/cop/style/return_nil.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -4
- data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/string_literals.rb +1 -1
- data/lib/rubocop/cop/style/string_methods.rb +1 -1
- data/lib/rubocop/cop/style/super_arguments.rb +65 -17
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
- data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
- data/lib/rubocop/cop/util.rb +12 -5
- data/lib/rubocop/cop/utils/format_string.rb +7 -5
- data/lib/rubocop/cop/variable_force/variable.rb +14 -2
- data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
- data/lib/rubocop/cops_documentation_generator.rb +13 -13
- data/lib/rubocop/directive_comment.rb +44 -10
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/lsp/diagnostic.rb +189 -0
- data/lib/rubocop/lsp/logger.rb +2 -2
- data/lib/rubocop/lsp/routes.rb +7 -23
- data/lib/rubocop/lsp/runtime.rb +17 -49
- data/lib/rubocop/lsp/server.rb +0 -2
- data/lib/rubocop/lsp/stdin_runner.rb +83 -0
- data/lib/rubocop/options.rb +28 -12
- data/lib/rubocop/path_util.rb +15 -8
- data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
- data/lib/rubocop/plugin/load_error.rb +26 -0
- data/lib/rubocop/plugin/loader.rb +100 -0
- data/lib/rubocop/plugin/not_supported_error.rb +29 -0
- data/lib/rubocop/plugin.rb +39 -0
- data/lib/rubocop/rake_task.rb +4 -1
- data/lib/rubocop/result_cache.rb +13 -13
- data/lib/rubocop/rspec/cop_helper.rb +9 -0
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/rspec/shared_contexts.rb +4 -1
- data/lib/rubocop/rspec/support.rb +1 -2
- data/lib/rubocop/runner.rb +5 -6
- data/lib/rubocop/server/cache.rb +35 -2
- data/lib/rubocop/server/cli.rb +2 -2
- data/lib/rubocop/target_finder.rb +1 -0
- data/lib/rubocop/target_ruby.rb +15 -0
- data/lib/rubocop/version.rb +17 -2
- data/lib/rubocop.rb +11 -0
- data/lib/ruby_lsp/rubocop/addon.rb +75 -0
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +47 -0
- metadata +53 -15
- data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for Style/HashExcept and Style/HashSlice cops.
|
6
|
+
# It registers an offense on methods with blocks that are equivalent
|
7
|
+
# to Hash#except or Hash#slice.
|
8
|
+
# rubocop:disable Metrics/ModuleLength
|
9
|
+
module HashSubset
|
10
|
+
include RangeHelp
|
11
|
+
extend NodePattern::Macros
|
12
|
+
|
13
|
+
RESTRICT_ON_SEND = %i[reject select filter].freeze
|
14
|
+
|
15
|
+
SUBSET_METHODS = %i[== != eql? include?].freeze
|
16
|
+
ACTIVE_SUPPORT_SUBSET_METHODS = (SUBSET_METHODS + %i[in? exclude?]).freeze
|
17
|
+
|
18
|
+
MSG = 'Use `%<prefer>s` instead.'
|
19
|
+
|
20
|
+
# @!method block_with_first_arg_check?(node)
|
21
|
+
def_node_matcher :block_with_first_arg_check?, <<~PATTERN
|
22
|
+
(block
|
23
|
+
(call _ _)
|
24
|
+
(args
|
25
|
+
$(arg _key)
|
26
|
+
(arg _))
|
27
|
+
{
|
28
|
+
$(send
|
29
|
+
{(lvar _key) $_ _ | _ $_ (lvar _key)})
|
30
|
+
(send
|
31
|
+
$(send
|
32
|
+
{(lvar _key) $_ _ | _ $_ (lvar _key)}) :!)
|
33
|
+
})
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_send(node)
|
37
|
+
offense_range, key_source = extract_offense(node)
|
38
|
+
|
39
|
+
return unless offense_range
|
40
|
+
return unless semantically_subset_method?(node)
|
41
|
+
|
42
|
+
preferred_method = "#{preferred_method_name}(#{key_source})"
|
43
|
+
add_offense(offense_range, message: format(MSG, prefer: preferred_method)) do |corrector|
|
44
|
+
corrector.replace(offense_range, preferred_method)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
alias on_csend on_send
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def semantically_subset_method?(node)
|
52
|
+
raise NotImplementedError
|
53
|
+
end
|
54
|
+
|
55
|
+
def preferred_method_name
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
def extract_offense(node)
|
60
|
+
block = node.parent
|
61
|
+
return unless extracts_hash_subset?(block)
|
62
|
+
|
63
|
+
except_key = except_key(block)
|
64
|
+
return if except_key.nil? || !safe_to_register_offense?(block, except_key)
|
65
|
+
|
66
|
+
[offense_range(node), except_key_source(except_key)]
|
67
|
+
end
|
68
|
+
|
69
|
+
def extracts_hash_subset?(block)
|
70
|
+
block_with_first_arg_check?(block) do |key_arg, send_node, method|
|
71
|
+
# Only consider methods that have one argument
|
72
|
+
return false unless send_node.arguments.one?
|
73
|
+
|
74
|
+
return false unless supported_subset_method?(method)
|
75
|
+
return false if range_include?(send_node)
|
76
|
+
|
77
|
+
case method
|
78
|
+
when :include?, :exclude?
|
79
|
+
send_node.first_argument.source == key_arg.source
|
80
|
+
when :in?
|
81
|
+
send_node.receiver.source == key_arg.source
|
82
|
+
else
|
83
|
+
true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def range_include?(send_node)
|
89
|
+
# When checking `include?`, `exclude?` and `in?` for offenses, if the receiver
|
90
|
+
# or first argument is a range, an offense should not be registered.
|
91
|
+
# ie. `(1..5).include?(k)` or `k.in?('a'..'z')`
|
92
|
+
|
93
|
+
return true if send_node.first_argument.range_type?
|
94
|
+
|
95
|
+
receiver = send_node.receiver
|
96
|
+
receiver = receiver.child_nodes.first while receiver.begin_type?
|
97
|
+
receiver.range_type?
|
98
|
+
end
|
99
|
+
|
100
|
+
def supported_subset_method?(method)
|
101
|
+
if active_support_extensions_enabled?
|
102
|
+
ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
|
103
|
+
else
|
104
|
+
SUBSET_METHODS.include?(method)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def semantically_except_method?(node)
|
109
|
+
block = node.parent
|
110
|
+
body, negated = extract_body_if_negated(block.body)
|
111
|
+
|
112
|
+
if node.method?('reject')
|
113
|
+
body.method?('==') || body.method?('eql?') || included?(body, negated)
|
114
|
+
else
|
115
|
+
body.method?('!=') || not_included?(body, negated)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def semantically_slice_method?(node)
|
120
|
+
!semantically_except_method?(node)
|
121
|
+
end
|
122
|
+
|
123
|
+
def included?(body, negated)
|
124
|
+
if negated
|
125
|
+
body.method?('exclude?')
|
126
|
+
else
|
127
|
+
body.method?('include?') || body.method?('in?')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def not_included?(body, negated)
|
132
|
+
included?(body, !negated)
|
133
|
+
end
|
134
|
+
|
135
|
+
def safe_to_register_offense?(block, except_key)
|
136
|
+
body = block.body
|
137
|
+
|
138
|
+
if body.method?('==') || body.method?('!=')
|
139
|
+
except_key.type?(:sym, :str)
|
140
|
+
else
|
141
|
+
true
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def extract_body_if_negated(body)
|
146
|
+
if body.method?('!')
|
147
|
+
[body.receiver, true]
|
148
|
+
else
|
149
|
+
[body, false]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def except_key_source(key)
|
154
|
+
if key.array_type?
|
155
|
+
key = if key.percent_literal?
|
156
|
+
key.each_value.map { |v| decorate_source(v) }
|
157
|
+
else
|
158
|
+
key.each_value.map(&:source)
|
159
|
+
end
|
160
|
+
return key.join(', ')
|
161
|
+
end
|
162
|
+
|
163
|
+
key.literal? ? key.source : "*#{key.source}"
|
164
|
+
end
|
165
|
+
|
166
|
+
def decorate_source(value)
|
167
|
+
return ":\"#{value.source}\"" if value.dsym_type?
|
168
|
+
return "\"#{value.source}\"" if value.dstr_type?
|
169
|
+
return ":#{value.source}" if value.sym_type?
|
170
|
+
|
171
|
+
"'#{value.source}'"
|
172
|
+
end
|
173
|
+
|
174
|
+
def except_key(node)
|
175
|
+
key_arg = node.argument_list.first.source
|
176
|
+
body, = extract_body_if_negated(node.body)
|
177
|
+
lhs, _method_name, rhs = *body
|
178
|
+
|
179
|
+
lhs.source == key_arg ? rhs : lhs
|
180
|
+
end
|
181
|
+
|
182
|
+
def offense_range(node)
|
183
|
+
range_between(node.loc.selector.begin_pos, node.parent.loc.end.end_pos)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
# rubocop:enable Metrics/ModuleLength
|
187
|
+
end
|
188
|
+
end
|
@@ -9,6 +9,80 @@ module RuboCop
|
|
9
9
|
|
10
10
|
RESTRICT_ON_SEND = %i[[] to_h].freeze
|
11
11
|
|
12
|
+
# Internal helper class to hold match data
|
13
|
+
Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
|
14
|
+
def noop_transformation?
|
15
|
+
transforming_body_expr.lvar_type? &&
|
16
|
+
transforming_body_expr.children == [transformed_argname]
|
17
|
+
end
|
18
|
+
|
19
|
+
def transformation_uses_both_args?
|
20
|
+
transforming_body_expr.descendants.include?(unchanged_body_expr)
|
21
|
+
end
|
22
|
+
|
23
|
+
def use_transformed_argname?
|
24
|
+
transforming_body_expr.each_descendant(:lvar).any? do |node|
|
25
|
+
node.source == transformed_argname.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Internal helper class to hold autocorrect data
|
31
|
+
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
32
|
+
def self.from_each_with_object(node, match)
|
33
|
+
new(match, node, 0, 0)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_hash_brackets_map(node, match)
|
37
|
+
new(match, node.children.last, 'Hash['.length, ']'.length)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.from_map_to_h(node, match)
|
41
|
+
if node.parent&.block_type? && node.parent.send_node == node
|
42
|
+
strip_trailing_chars = 0
|
43
|
+
else
|
44
|
+
map_range = node.children.first.source_range
|
45
|
+
node_range = node.source_range
|
46
|
+
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
47
|
+
end
|
48
|
+
|
49
|
+
new(match, node.children.first, 0, strip_trailing_chars)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.from_to_h(node, match)
|
53
|
+
new(match, node, 0, 0)
|
54
|
+
end
|
55
|
+
|
56
|
+
def strip_prefix_and_suffix(node, corrector)
|
57
|
+
expression = node.source_range
|
58
|
+
corrector.remove_leading(expression, leading)
|
59
|
+
corrector.remove_trailing(expression, trailing)
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_new_method_name(new_method_name, corrector)
|
63
|
+
range = block_node.send_node.loc.selector
|
64
|
+
if (send_end = block_node.send_node.loc.end)
|
65
|
+
# If there are arguments (only true in the `each_with_object`
|
66
|
+
# case)
|
67
|
+
range = range.begin.join(send_end)
|
68
|
+
end
|
69
|
+
corrector.replace(range, new_method_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_new_arg_name(transformed_argname, corrector)
|
73
|
+
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_new_body_expression(transforming_body_expr, corrector)
|
77
|
+
body_source = transforming_body_expr.source
|
78
|
+
if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
79
|
+
body_source = "{ #{body_source} }"
|
80
|
+
end
|
81
|
+
|
82
|
+
corrector.replace(block_node.body, body_source)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
12
86
|
# @!method array_receiver?(node)
|
13
87
|
def_node_matcher :array_receiver?, <<~PATTERN
|
14
88
|
{(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)}
|
@@ -113,80 +187,6 @@ module RuboCop
|
|
113
187
|
correction.set_new_arg_name(captures.transformed_argname, corrector)
|
114
188
|
correction.set_new_body_expression(captures.transforming_body_expr, corrector)
|
115
189
|
end
|
116
|
-
|
117
|
-
# Internal helper class to hold match data
|
118
|
-
Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
|
119
|
-
def noop_transformation?
|
120
|
-
transforming_body_expr.lvar_type? &&
|
121
|
-
transforming_body_expr.children == [transformed_argname]
|
122
|
-
end
|
123
|
-
|
124
|
-
def transformation_uses_both_args?
|
125
|
-
transforming_body_expr.descendants.include?(unchanged_body_expr)
|
126
|
-
end
|
127
|
-
|
128
|
-
def use_transformed_argname?
|
129
|
-
transforming_body_expr.each_descendant(:lvar).any? do |node|
|
130
|
-
node.source == transformed_argname.to_s
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# Internal helper class to hold autocorrect data
|
136
|
-
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
137
|
-
def self.from_each_with_object(node, match)
|
138
|
-
new(match, node, 0, 0)
|
139
|
-
end
|
140
|
-
|
141
|
-
def self.from_hash_brackets_map(node, match)
|
142
|
-
new(match, node.children.last, 'Hash['.length, ']'.length)
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.from_map_to_h(node, match)
|
146
|
-
if node.parent&.block_type? && node.parent.send_node == node
|
147
|
-
strip_trailing_chars = 0
|
148
|
-
else
|
149
|
-
map_range = node.children.first.source_range
|
150
|
-
node_range = node.source_range
|
151
|
-
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
152
|
-
end
|
153
|
-
|
154
|
-
new(match, node.children.first, 0, strip_trailing_chars)
|
155
|
-
end
|
156
|
-
|
157
|
-
def self.from_to_h(node, match)
|
158
|
-
new(match, node, 0, 0)
|
159
|
-
end
|
160
|
-
|
161
|
-
def strip_prefix_and_suffix(node, corrector)
|
162
|
-
expression = node.source_range
|
163
|
-
corrector.remove_leading(expression, leading)
|
164
|
-
corrector.remove_trailing(expression, trailing)
|
165
|
-
end
|
166
|
-
|
167
|
-
def set_new_method_name(new_method_name, corrector)
|
168
|
-
range = block_node.send_node.loc.selector
|
169
|
-
if (send_end = block_node.send_node.loc.end)
|
170
|
-
# If there are arguments (only true in the `each_with_object`
|
171
|
-
# case)
|
172
|
-
range = range.begin.join(send_end)
|
173
|
-
end
|
174
|
-
corrector.replace(range, new_method_name)
|
175
|
-
end
|
176
|
-
|
177
|
-
def set_new_arg_name(transformed_argname, corrector)
|
178
|
-
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
179
|
-
end
|
180
|
-
|
181
|
-
def set_new_body_expression(transforming_body_expr, corrector)
|
182
|
-
body_source = transforming_body_expr.source
|
183
|
-
if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
184
|
-
body_source = "{ #{body_source} }"
|
185
|
-
end
|
186
|
-
|
187
|
-
corrector.replace(block_node.body, body_source)
|
188
|
-
end
|
189
|
-
end
|
190
190
|
end
|
191
191
|
end
|
192
192
|
end
|
@@ -4,7 +4,12 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for checking whether an AST node/token is aligned
|
6
6
|
# with something on a preceding or following line
|
7
|
+
# rubocop:disable Metrics/ModuleLength
|
7
8
|
module PrecedingFollowingAlignment
|
9
|
+
# Tokens that end with an `=`, as well as `<<`, that can be aligned together:
|
10
|
+
# `=`, `==`, `===`, `!=`, `<=`, `>=`, `<<` and operator assignment (`+=`, etc).
|
11
|
+
ASSIGNMENT_OR_COMPARISON_TOKENS = %i[tEQL tEQ tEQQ tNEQ tLEQ tGEQ tOP_ASGN tLSHFT].freeze
|
12
|
+
|
8
13
|
private
|
9
14
|
|
10
15
|
def allow_for_alignment?
|
@@ -19,16 +24,20 @@ module RuboCop
|
|
19
24
|
aligned_with_adjacent_line?(range, method(:aligned_operator?))
|
20
25
|
end
|
21
26
|
|
22
|
-
|
27
|
+
# Allows alignment with a preceding operator that ends with an `=`,
|
28
|
+
# including assignment and comparison operators.
|
29
|
+
def aligned_with_preceding_equals_operator(token)
|
23
30
|
preceding_line_range = token.line.downto(1)
|
24
31
|
|
25
|
-
|
32
|
+
aligned_with_equals_sign(token, preceding_line_range)
|
26
33
|
end
|
27
34
|
|
28
|
-
|
35
|
+
# Allows alignment with a subsequent operator that ends with an `=`,
|
36
|
+
# including assignment and comparison operators.
|
37
|
+
def aligned_with_subsequent_equals_operator(token)
|
29
38
|
subsequent_line_range = token.line.upto(processed_source.lines.length)
|
30
39
|
|
31
|
-
|
40
|
+
aligned_with_equals_sign(token, subsequent_line_range)
|
32
41
|
end
|
33
42
|
|
34
43
|
def aligned_with_adjacent_line?(range, predicate)
|
@@ -75,11 +84,11 @@ module RuboCop
|
|
75
84
|
end
|
76
85
|
|
77
86
|
def aligned_token?(range, line, lineno)
|
78
|
-
aligned_words?(range, line) ||
|
87
|
+
aligned_words?(range, line) || aligned_equals_operator?(range, lineno)
|
79
88
|
end
|
80
89
|
|
81
90
|
def aligned_operator?(range, line, lineno)
|
82
|
-
aligned_identical?(range, line) ||
|
91
|
+
aligned_identical?(range, line) || aligned_equals_operator?(range, lineno)
|
83
92
|
end
|
84
93
|
|
85
94
|
def aligned_words?(range, line)
|
@@ -90,22 +99,24 @@ module RuboCop
|
|
90
99
|
token == line[left_edge, token.length]
|
91
100
|
end
|
92
101
|
|
93
|
-
def
|
94
|
-
# Check that
|
95
|
-
# ie. an equals sign, an operator assignment,
|
102
|
+
def aligned_equals_operator?(range, lineno)
|
103
|
+
# Check that the operator is aligned with a previous assignment or comparison operator
|
104
|
+
# ie. an equals sign, an operator assignment (eg. `+=`), a comparison (`==`, `<=`, etc.).
|
105
|
+
# Since append operators (`<<`) are a type of assignment, they are allowed as well,
|
106
|
+
# despite not ending with a literal equals character.
|
96
107
|
line_range = processed_source.buffer.line_range(lineno)
|
97
108
|
return false unless line_range
|
98
109
|
|
99
110
|
# Find the specific token to avoid matching up to operators inside strings
|
100
|
-
|
101
|
-
|
111
|
+
operator_token = processed_source.tokens_within(line_range).detect do |token|
|
112
|
+
ASSIGNMENT_OR_COMPARISON_TOKENS.include?(token.type)
|
102
113
|
end
|
103
114
|
|
104
|
-
|
105
|
-
aligned_with_append_operator?(range,
|
115
|
+
aligned_with_preceding_equals?(range, operator_token) ||
|
116
|
+
aligned_with_append_operator?(range, operator_token)
|
106
117
|
end
|
107
118
|
|
108
|
-
def
|
119
|
+
def aligned_with_preceding_equals?(range, token)
|
109
120
|
return false unless token
|
110
121
|
|
111
122
|
range.source[-1] == '=' && range.last_column == token.pos.last_column
|
@@ -123,7 +134,7 @@ module RuboCop
|
|
123
134
|
range.source == line[range.column, range.size]
|
124
135
|
end
|
125
136
|
|
126
|
-
def
|
137
|
+
def aligned_with_equals_sign(token, line_range)
|
127
138
|
token_line_indent = processed_source.line_indentation(token.line)
|
128
139
|
assignment_lines = relevant_assignment_lines(line_range)
|
129
140
|
relevant_line_number = assignment_lines[1]
|
@@ -135,7 +146,7 @@ module RuboCop
|
|
135
146
|
return :none if relevant_indent < token_line_indent
|
136
147
|
return :none unless processed_source.lines[relevant_line_number - 1]
|
137
148
|
|
138
|
-
|
149
|
+
aligned_equals_operator?(token.pos, relevant_line_number) ? :yes : :no
|
139
150
|
end
|
140
151
|
|
141
152
|
def assignment_lines
|
@@ -146,10 +157,14 @@ module RuboCop
|
|
146
157
|
@assignment_tokens ||= begin
|
147
158
|
tokens = processed_source.tokens.select(&:equal_sign?)
|
148
159
|
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
|
160
|
+
# We don't want to operate on equals signs which are part of an `optarg` in a
|
161
|
+
# method definition, or the separator of an endless method definition.
|
162
|
+
# For example (the equals sign to ignore is highlighted with ^):
|
163
|
+
# def method(optarg = default_val); end
|
164
|
+
# ^
|
165
|
+
# def method = foo
|
166
|
+
# ^
|
167
|
+
tokens = remove_equals_in_def(tokens, processed_source)
|
153
168
|
|
154
169
|
# Only attempt to align the first = on each line
|
155
170
|
Set.new(tokens.uniq(&:line))
|
@@ -185,11 +200,20 @@ module RuboCop
|
|
185
200
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
186
201
|
# rubocop:enable Metrics/PerceivedComplexity, Metrics/MethodLength
|
187
202
|
|
188
|
-
def
|
189
|
-
|
190
|
-
|
191
|
-
|
203
|
+
def remove_equals_in_def(asgn_tokens, processed_source)
|
204
|
+
nodes = processed_source.ast.each_node(:optarg, :def)
|
205
|
+
eqls_to_ignore = nodes.with_object([]) do |node, arr|
|
206
|
+
loc = if node.def_type?
|
207
|
+
node.loc.assignment if node.endless?
|
208
|
+
else
|
209
|
+
node.loc.operator
|
210
|
+
end
|
211
|
+
arr << loc.begin_pos if loc
|
212
|
+
end
|
213
|
+
|
214
|
+
asgn_tokens.reject { |t| eqls_to_ignore.include?(t.begin_pos) }
|
192
215
|
end
|
193
216
|
end
|
217
|
+
# rubocop:enable Metrics/ModuleLength
|
194
218
|
end
|
195
219
|
end
|
@@ -4,9 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Methods that calculate and return Parser::Source::Ranges
|
6
6
|
module RangeHelp
|
7
|
-
private
|
8
|
-
|
9
7
|
BYTE_ORDER_MARK = 0xfeff # The Unicode codepoint
|
8
|
+
NOT_GIVEN = Module.new
|
9
|
+
|
10
|
+
private
|
10
11
|
|
11
12
|
def source_range(source_buffer, line_number, column, length = 1)
|
12
13
|
if column.is_a?(Range)
|
@@ -51,7 +52,6 @@ module RuboCop
|
|
51
52
|
Parser::Source::Range.new(buffer, begin_pos, end_pos)
|
52
53
|
end
|
53
54
|
|
54
|
-
NOT_GIVEN = Module.new
|
55
55
|
def range_with_surrounding_space(range_positional = NOT_GIVEN, # rubocop:disable Metrics/ParameterLists
|
56
56
|
range: NOT_GIVEN, side: :both, newlines: true,
|
57
57
|
whitespace: false, continuations: false,
|
@@ -55,14 +55,19 @@ module RuboCop
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def if_body_source(if_body)
|
58
|
-
if if_body.call_type? &&
|
59
|
-
if_body.last_argument&.hash_type? && if_body.last_argument.pairs.last&.value_omission?
|
58
|
+
if if_body.call_type? && !if_body.method?(:[]=) && omitted_value_in_last_hash_arg?(if_body)
|
60
59
|
"#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
|
61
60
|
else
|
62
61
|
if_body.source
|
63
62
|
end
|
64
63
|
end
|
65
64
|
|
65
|
+
def omitted_value_in_last_hash_arg?(if_body)
|
66
|
+
return false unless (last_argument = if_body.last_argument)
|
67
|
+
|
68
|
+
last_argument.hash_type? && last_argument.pairs.last&.value_omission?
|
69
|
+
end
|
70
|
+
|
66
71
|
def method_source(if_body)
|
67
72
|
end_range = if_body.implicit_call? ? if_body.loc.dot.end : if_body.loc.selector
|
68
73
|
|
@@ -96,7 +101,7 @@ module RuboCop
|
|
96
101
|
end
|
97
102
|
|
98
103
|
def max_line_length
|
99
|
-
return unless config.
|
104
|
+
return unless config.cop_enabled?('Layout/LineLength')
|
100
105
|
|
101
106
|
config.for_cop('Layout/LineLength')['Max']
|
102
107
|
end
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
def on_str(node)
|
11
11
|
# Constants like __FILE__ are handled as strings,
|
12
12
|
# but don't respond to begin.
|
13
|
-
return unless node.loc
|
13
|
+
return unless node.loc?(:begin)
|
14
14
|
return if part_of_ignored_node?(node)
|
15
15
|
|
16
16
|
if offense?(node)
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
# A :begin node inside a :dstr, :dsym, or :regexp node is an interpolation.
|
34
34
|
node.ancestors
|
35
35
|
.drop_while { |a| !a.begin_type? }
|
36
|
-
.any? { |a| a.
|
36
|
+
.any? { |a| a.type?(:dstr, :dsym, :regexp) }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
|
-
# Common methods shared by Style/TrailingCommaInArguments
|
6
|
-
# Style/
|
5
|
+
# Common methods shared by Style/TrailingCommaInArguments,
|
6
|
+
# Style/TrailingCommaInArrayLiteral and Style/TrailingCommaInHashLiteral
|
7
7
|
module TrailingComma
|
8
8
|
include ConfigurableEnforcedStyle
|
9
9
|
include RangeHelp
|
@@ -181,7 +181,7 @@ module RuboCop
|
|
181
181
|
# ...
|
182
182
|
# SOURCE
|
183
183
|
# })
|
184
|
-
return heredoc?(node.children.last) if node.
|
184
|
+
return heredoc?(node.children.last) if node.type?(:pair, :hash)
|
185
185
|
|
186
186
|
false
|
187
187
|
end
|
@@ -13,6 +13,20 @@ module RuboCop
|
|
13
13
|
# The default variable name is `block`. If the name is already in use, it will not be
|
14
14
|
# autocorrected.
|
15
15
|
#
|
16
|
+
# [NOTE]
|
17
|
+
# ====
|
18
|
+
# Because of a bug in Ruby 3.3.0, when a block is referenced inside of another block,
|
19
|
+
# no offense will be registered until Ruby 3.4:
|
20
|
+
#
|
21
|
+
# [source,ruby]
|
22
|
+
# ----
|
23
|
+
# def foo(&block)
|
24
|
+
# # Using an anonymous block would be a syntax error on Ruby 3.3.0
|
25
|
+
# block_method { bar(&block) }
|
26
|
+
# end
|
27
|
+
# ----
|
28
|
+
# ====
|
29
|
+
#
|
16
30
|
# @example EnforcedStyle: anonymous (default)
|
17
31
|
#
|
18
32
|
# # bad
|
@@ -90,21 +104,11 @@ module RuboCop
|
|
90
104
|
last_argument.source == block_pass_node.source
|
91
105
|
end
|
92
106
|
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
# def foo(&)
|
97
|
-
# block_method do
|
98
|
-
# bar(&)
|
99
|
-
# end
|
100
|
-
# end
|
101
|
-
#
|
102
|
-
# $ ruby -vc foo.rb
|
103
|
-
# ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin22]
|
104
|
-
# foo.rb: foo.rb:4: anonymous block parameter is also used within block (SyntaxError)
|
105
|
-
#
|
107
|
+
# Ruby 3.3.0 had a bug where accessing an anonymous block argument inside of a block
|
108
|
+
# was a syntax error in unambiguous cases: https://bugs.ruby-lang.org/issues/20090
|
109
|
+
# We disallow this also for earlier Ruby versions so that code is forwards compatible.
|
106
110
|
def invalidates_syntax?(block_pass_node)
|
107
|
-
block_pass_node.each_ancestor(:
|
111
|
+
target_ruby_version <= 3.3 && block_pass_node.each_ancestor(:any_block).any?
|
108
112
|
end
|
109
113
|
|
110
114
|
def use_kwarg_in_method_definition?(node)
|
@@ -138,7 +142,7 @@ module RuboCop
|
|
138
142
|
def use_block_argument_as_local_variable?(node, last_argument)
|
139
143
|
return false if node.body.nil?
|
140
144
|
|
141
|
-
node.body.
|
145
|
+
node.body.each_node(:lvar, :lvasgn).any? do |lvar|
|
142
146
|
!lvar.parent.block_pass_type? && lvar.node_parts[0].to_s == last_argument
|
143
147
|
end
|
144
148
|
end
|