rubocop 1.57.1 → 1.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +4 -5
- data/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +136 -19
- data/lib/rubocop/cached_data.rb +11 -3
- data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
- data/lib/rubocop/cli.rb +10 -1
- data/lib/rubocop/config.rb +36 -12
- data/lib/rubocop/config_finder.rb +12 -2
- data/lib/rubocop/config_loader.rb +1 -2
- data/lib/rubocop/config_loader_resolver.rb +9 -3
- data/lib/rubocop/config_obsoletion.rb +11 -8
- data/lib/rubocop/config_validator.rb +14 -7
- data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
- data/lib/rubocop/cop/base.rb +63 -16
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
- data/lib/rubocop/cop/cop.rb +20 -2
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/documentation.rb +16 -6
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/force.rb +12 -0
- data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
- data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
- data/lib/rubocop/cop/internal_affairs/example_description.rb +6 -5
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- 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 +123 -29
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +24 -7
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +20 -20
- data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -3
- 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_around_operators.rb +53 -20
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
- data/lib/rubocop/cop/legacy/corrector.rb +12 -2
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +6 -6
- 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 +29 -3
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +2 -2
- data/lib/rubocop/cop/lint/empty_when.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +24 -17
- 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/implicit_string_concatenation.rb +14 -7
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
- data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +54 -6
- data/lib/rubocop/cop/lint/redundant_with_index.rb +6 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -3
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +3 -2
- data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
- data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_times.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +53 -12
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
- data/lib/rubocop/cop/metrics/class_length.rb +6 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
- data/lib/rubocop/cop/mixin/alignment.rb +5 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/code_length.rb +12 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +23 -13
- data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
- data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +34 -7
- data/lib/rubocop/cop/naming/constant_name.rb +1 -2
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/compound_hash.rb +2 -2
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +52 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
- data/lib/rubocop/cop/style/alias.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +155 -21
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/case_like_if.rb +5 -5
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/class_vars.rb +3 -3
- data/lib/rubocop/cop/style/collection_compact.rb +21 -11
- data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +7 -8
- data/lib/rubocop/cop/style/copyright.rb +31 -21
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/documentation.rb +24 -24
- data/lib/rubocop/cop/style/documentation_method.rb +20 -0
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +6 -15
- data/lib/rubocop/cop/style/exact_regexp_match.rb +4 -2
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/format_string.rb +9 -9
- data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
- data/lib/rubocop/cop/style/hash_except.rb +10 -6
- data/lib/rubocop/cop/style/hash_syntax.rb +24 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +12 -1
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +44 -2
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +82 -50
- data/lib/rubocop/cop/style/map_into_array.rb +175 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +18 -8
- data/lib/rubocop/cop/style/map_to_set.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +19 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
- 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/multiline_method_signature.rb +10 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +4 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +27 -3
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -10
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +5 -4
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +19 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +50 -19
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
- data/lib/rubocop/cop/style/redundant_return.rb +7 -1
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/sample.rb +3 -4
- data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +8 -0
- data/lib/rubocop/cop/style/send.rb +4 -4
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +104 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_arguments.rb +174 -0
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +75 -5
- data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cop/style/zero_length_predicate.rb +28 -24
- data/lib/rubocop/cop/team.rb +13 -0
- data/lib/rubocop/cop/util.rb +7 -1
- data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +16 -4
- data/lib/rubocop/directive_comment.rb +10 -8
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/ext/regexp_parser.rb +4 -21
- data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
- data/lib/rubocop/formatter/disabled_config_formatter.rb +23 -8
- data/lib/rubocop/formatter/formatter_set.rb +7 -1
- data/lib/rubocop/formatter/html_formatter.rb +37 -14
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/formatter/tap_formatter.rb +3 -7
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lockfile.rb +56 -7
- data/lib/rubocop/lsp/logger.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +12 -15
- data/lib/rubocop/lsp/runtime.rb +1 -1
- data/lib/rubocop/lsp/server.rb +7 -2
- data/lib/rubocop/lsp/severity.rb +1 -1
- data/lib/rubocop/lsp.rb +36 -0
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/options.rb +14 -11
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/result_cache.rb +0 -1
- data/lib/rubocop/rspec/cop_helper.rb +8 -2
- data/lib/rubocop/rspec/expect_offense.rb +16 -8
- data/lib/rubocop/rspec/shared_contexts.rb +73 -16
- data/lib/rubocop/rspec/support.rb +3 -0
- data/lib/rubocop/runner.rb +14 -3
- data/lib/rubocop/server/cache.rb +11 -2
- data/lib/rubocop/server/client_command/exec.rb +2 -3
- data/lib/rubocop/server/client_command/start.rb +1 -1
- data/lib/rubocop/server/core.rb +4 -0
- data/lib/rubocop/server/server_command/exec.rb +0 -1
- data/lib/rubocop/target_finder.rb +84 -78
- data/lib/rubocop/target_ruby.rb +82 -80
- data/lib/rubocop/version.rb +19 -4
- data/lib/rubocop.rb +8 -0
- metadata +27 -29
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
|
@@ -17,10 +17,16 @@ module RuboCop
|
|
|
17
17
|
# @example
|
|
18
18
|
# # bad
|
|
19
19
|
# hash.keys.each { |k| p k }
|
|
20
|
-
# hash.
|
|
20
|
+
# hash.each { |k, unused_value| p k }
|
|
21
21
|
#
|
|
22
22
|
# # good
|
|
23
23
|
# hash.each_key { |k| p k }
|
|
24
|
+
#
|
|
25
|
+
# # bad
|
|
26
|
+
# hash.values.each { |v| p v }
|
|
27
|
+
# hash.each { |unused_key, v| p v }
|
|
28
|
+
#
|
|
29
|
+
# # good
|
|
24
30
|
# hash.each_value { |v| p v }
|
|
25
31
|
#
|
|
26
32
|
# @example AllowedReceivers: ['execute']
|
|
@@ -33,25 +39,59 @@ module RuboCop
|
|
|
33
39
|
extend AutoCorrector
|
|
34
40
|
|
|
35
41
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
|
42
|
+
UNUSED_BLOCK_ARG_MSG = "#{MSG.chop} and remove the unused `%<unused_code>s` block argument."
|
|
43
|
+
ARRAY_CONVERTER_METHODS = %i[assoc chunk flatten rassoc sort sort_by to_a].freeze
|
|
36
44
|
|
|
37
45
|
# @!method kv_each(node)
|
|
38
46
|
def_node_matcher :kv_each, <<~PATTERN
|
|
39
|
-
({block numblock} $(
|
|
47
|
+
({block numblock} $(call (call _ ${:keys :values}) :each) ...)
|
|
48
|
+
PATTERN
|
|
49
|
+
|
|
50
|
+
# @!method each_arguments(node)
|
|
51
|
+
def_node_matcher :each_arguments, <<~PATTERN
|
|
52
|
+
(block (call _ :each)(args $_key $_value) ...)
|
|
40
53
|
PATTERN
|
|
41
54
|
|
|
42
55
|
# @!method kv_each_with_block_pass(node)
|
|
43
56
|
def_node_matcher :kv_each_with_block_pass, <<~PATTERN
|
|
44
|
-
(
|
|
57
|
+
(call $(call _ ${:keys :values}) :each (block_pass (sym _)))
|
|
45
58
|
PATTERN
|
|
46
59
|
|
|
47
60
|
def on_block(node)
|
|
61
|
+
return unless handleable?(node)
|
|
62
|
+
|
|
48
63
|
kv_each(node) do |target, method|
|
|
49
|
-
register_kv_offense(target, method)
|
|
64
|
+
register_kv_offense(target, method) and return
|
|
50
65
|
end
|
|
51
|
-
end
|
|
52
66
|
|
|
67
|
+
return unless (key, value = each_arguments(node))
|
|
68
|
+
|
|
69
|
+
check_unused_block_args(node, key, value)
|
|
70
|
+
end
|
|
53
71
|
alias on_numblock on_block
|
|
54
72
|
|
|
73
|
+
# rubocop:disable Metrics/AbcSize
|
|
74
|
+
def check_unused_block_args(node, key, value)
|
|
75
|
+
return if node.body.nil?
|
|
76
|
+
|
|
77
|
+
value_unused = unused_block_arg_exist?(node, value)
|
|
78
|
+
key_unused = unused_block_arg_exist?(node, key)
|
|
79
|
+
return if value_unused && key_unused
|
|
80
|
+
|
|
81
|
+
if value_unused
|
|
82
|
+
message = message('each_key', node.method_name, value.source)
|
|
83
|
+
unused_range = key.source_range.end.join(value.source_range.end)
|
|
84
|
+
|
|
85
|
+
register_each_args_offense(node, message, 'each_key', unused_range)
|
|
86
|
+
elsif key_unused
|
|
87
|
+
message = message('each_value', node.method_name, key.source)
|
|
88
|
+
unused_range = key.source_range.begin.join(value.source_range.begin)
|
|
89
|
+
|
|
90
|
+
register_each_args_offense(node, message, 'each_value', unused_range)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
# rubocop:enable Metrics/AbcSize
|
|
94
|
+
|
|
55
95
|
def on_block_pass(node)
|
|
56
96
|
kv_each_with_block_pass(node.parent) do |target, method|
|
|
57
97
|
register_kv_with_block_pass_offense(node, target, method)
|
|
@@ -60,27 +100,81 @@ module RuboCop
|
|
|
60
100
|
|
|
61
101
|
private
|
|
62
102
|
|
|
103
|
+
def handleable?(node)
|
|
104
|
+
return false if use_array_converter_method_as_preceding?(node)
|
|
105
|
+
return false unless (root_receiver = root_receiver(node))
|
|
106
|
+
|
|
107
|
+
!root_receiver.literal? || root_receiver.hash_type?
|
|
108
|
+
end
|
|
109
|
+
|
|
63
110
|
def register_kv_offense(target, method)
|
|
64
111
|
return unless (parent_receiver = target.receiver.receiver)
|
|
65
112
|
return if allowed_receiver?(parent_receiver)
|
|
66
113
|
|
|
67
|
-
|
|
114
|
+
current = target.receiver.loc.selector.join(target.source_range.end).source
|
|
115
|
+
|
|
116
|
+
add_offense(kv_range(target), message: format_message(method, current)) do |corrector|
|
|
68
117
|
correct_key_value_each(target, corrector)
|
|
69
118
|
end
|
|
70
119
|
end
|
|
71
120
|
|
|
121
|
+
def unused_block_arg_exist?(node, block_arg)
|
|
122
|
+
lvar_sources = node.body.each_descendant(:lvar).map(&:source)
|
|
123
|
+
|
|
124
|
+
if block_arg.mlhs_type?
|
|
125
|
+
block_arg.each_descendant(:arg, :restarg).all? do |block_arg|
|
|
126
|
+
lvar_sources.none?(block_arg.source.delete_prefix('*'))
|
|
127
|
+
end
|
|
128
|
+
else
|
|
129
|
+
lvar_sources.none?(block_arg.source.delete_prefix('*'))
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def message(prefer, method_name, unused_code)
|
|
134
|
+
format(
|
|
135
|
+
UNUSED_BLOCK_ARG_MSG, prefer: prefer, current: method_name, unused_code: unused_code
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def register_each_args_offense(node, message, prefer, unused_range)
|
|
140
|
+
add_offense(node, message: message) do |corrector|
|
|
141
|
+
corrector.replace(node.send_node.loc.selector, prefer)
|
|
142
|
+
corrector.remove(unused_range)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
72
146
|
def register_kv_with_block_pass_offense(node, target, method)
|
|
73
147
|
return unless (parent_receiver = node.parent.receiver.receiver)
|
|
74
148
|
return if allowed_receiver?(parent_receiver)
|
|
75
149
|
|
|
76
|
-
range = target.loc.selector.
|
|
77
|
-
|
|
150
|
+
range = target.loc.selector.join(node.parent.loc.selector.end)
|
|
151
|
+
|
|
152
|
+
add_offense(range, message: format_message(method, range.source)) do |corrector|
|
|
78
153
|
corrector.replace(range, "each_#{method[0..-2]}")
|
|
79
154
|
end
|
|
80
155
|
end
|
|
81
156
|
|
|
82
|
-
def
|
|
83
|
-
|
|
157
|
+
def use_array_converter_method_as_preceding?(node)
|
|
158
|
+
return false unless (preceding_method = node.children.first.children.first)
|
|
159
|
+
unless preceding_method.call_type? ||
|
|
160
|
+
preceding_method.block_type? || preceding_method.numblock_type?
|
|
161
|
+
return false
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
ARRAY_CONVERTER_METHODS.include?(preceding_method.method_name)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def root_receiver(node)
|
|
168
|
+
receiver = node.receiver
|
|
169
|
+
if receiver&.receiver
|
|
170
|
+
root_receiver(receiver)
|
|
171
|
+
else
|
|
172
|
+
receiver
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def format_message(method_name, current)
|
|
177
|
+
format(MSG, prefer: "each_#{method_name[0..-2]}", current: current)
|
|
84
178
|
end
|
|
85
179
|
|
|
86
180
|
def check_argument(variable)
|
|
@@ -103,7 +197,7 @@ module RuboCop
|
|
|
103
197
|
name = "each_#{node.receiver.method_name.to_s.chop}"
|
|
104
198
|
return correct_implicit(node, corrector, name) unless receiver
|
|
105
199
|
|
|
106
|
-
new_source = receiver.source + "
|
|
200
|
+
new_source = receiver.source + "#{node.loc.dot.source}#{name}"
|
|
107
201
|
corrector.replace(node, new_source)
|
|
108
202
|
end
|
|
109
203
|
|
|
@@ -23,9 +23,9 @@ module RuboCop
|
|
|
23
23
|
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| k == :bar }
|
|
24
24
|
# {foo: 1, bar: 2, baz: 3}.select {|k, v| k != :bar }
|
|
25
25
|
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| k != :bar }
|
|
26
|
-
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[
|
|
27
|
-
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[
|
|
28
|
-
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| !%i[
|
|
26
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].include?(k) }
|
|
27
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].include?(k) }
|
|
28
|
+
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| !%i[bar].include?(k) }
|
|
29
29
|
#
|
|
30
30
|
# # good
|
|
31
31
|
# {foo: 1, bar: 2, baz: 3}.except(:bar)
|
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
|
43
43
|
# @!method bad_method_with_poro?(node)
|
|
44
44
|
def_node_matcher :bad_method_with_poro?, <<~PATTERN
|
|
45
45
|
(block
|
|
46
|
-
(
|
|
46
|
+
(call _ _)
|
|
47
47
|
(args
|
|
48
48
|
$(arg _)
|
|
49
49
|
(arg _))
|
|
@@ -73,8 +73,9 @@ module RuboCop
|
|
|
73
73
|
PATTERN
|
|
74
74
|
|
|
75
75
|
def on_send(node)
|
|
76
|
+
method_name = node.method_name
|
|
76
77
|
block = node.parent
|
|
77
|
-
return unless bad_method?(block) && semantically_except_method?(node, block)
|
|
78
|
+
return unless bad_method?(method_name, block) && semantically_except_method?(node, block)
|
|
78
79
|
|
|
79
80
|
except_key = except_key(block)
|
|
80
81
|
return if except_key.nil? || !safe_to_register_offense?(block, except_key)
|
|
@@ -86,11 +87,12 @@ module RuboCop
|
|
|
86
87
|
corrector.replace(range, preferred_method)
|
|
87
88
|
end
|
|
88
89
|
end
|
|
90
|
+
alias on_csend on_send
|
|
89
91
|
|
|
90
92
|
private
|
|
91
93
|
|
|
92
94
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
93
|
-
def bad_method?(block)
|
|
95
|
+
def bad_method?(method_name, block)
|
|
94
96
|
if active_support_extensions_enabled?
|
|
95
97
|
bad_method_with_active_support?(block) do |key_arg, send_node|
|
|
96
98
|
if send_node.method?(:in?) && send_node.receiver&.source != key_arg.source
|
|
@@ -102,6 +104,8 @@ module RuboCop
|
|
|
102
104
|
end
|
|
103
105
|
else
|
|
104
106
|
bad_method_with_poro?(block) do |key_arg, send_node|
|
|
107
|
+
return false if method_name == :reject && block.body.method?(:!)
|
|
108
|
+
|
|
105
109
|
!send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
|
|
106
110
|
end
|
|
107
111
|
end
|
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
|
29
29
|
# * never - forces use of explicit hash literal value
|
|
30
30
|
# * either - accepts both shorthand and explicit use of hash literal value
|
|
31
31
|
# * consistent - forces use of the 3.1 syntax only if all values can be omitted in the hash
|
|
32
|
+
# * either_consistent - accepts both shorthand and explicit use of hash literal value,
|
|
33
|
+
# but they must be consistent
|
|
32
34
|
#
|
|
33
35
|
# @example EnforcedStyle: ruby19 (default)
|
|
34
36
|
# # bad
|
|
@@ -110,6 +112,22 @@ module RuboCop
|
|
|
110
112
|
# # good - can't omit `baz`
|
|
111
113
|
# {foo: foo, bar: baz}
|
|
112
114
|
#
|
|
115
|
+
# @example EnforcedShorthandSyntax: either_consistent
|
|
116
|
+
#
|
|
117
|
+
# # good - `foo` and `bar` values can be omitted, but they are consistent, so it's accepted
|
|
118
|
+
# {foo: foo, bar: bar}
|
|
119
|
+
#
|
|
120
|
+
# # bad - `bar` value can be omitted
|
|
121
|
+
# {foo:, bar: bar}
|
|
122
|
+
#
|
|
123
|
+
# # bad - mixed syntaxes
|
|
124
|
+
# {foo:, bar: baz}
|
|
125
|
+
#
|
|
126
|
+
# # good
|
|
127
|
+
# {foo:, bar:}
|
|
128
|
+
#
|
|
129
|
+
# # good - can't omit `baz`
|
|
130
|
+
# {foo: foo, bar: baz}
|
|
113
131
|
class HashSyntax < Base
|
|
114
132
|
include ConfigurableEnforcedStyle
|
|
115
133
|
include HashShorthandSyntax
|
|
@@ -195,6 +213,7 @@ module RuboCop
|
|
|
195
213
|
acceptable_19_syntax_symbol?(pair.key.source)
|
|
196
214
|
end
|
|
197
215
|
|
|
216
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
198
217
|
def acceptable_19_syntax_symbol?(sym_name)
|
|
199
218
|
sym_name.delete_prefix!(':')
|
|
200
219
|
|
|
@@ -209,9 +228,12 @@ module RuboCop
|
|
|
209
228
|
# Most hash keys can be matched against a simple regex.
|
|
210
229
|
return true if /\A[_a-z]\w*[?!]?\z/i.match?(sym_name)
|
|
211
230
|
|
|
212
|
-
|
|
213
|
-
|
|
231
|
+
return false if target_ruby_version <= 2.1
|
|
232
|
+
|
|
233
|
+
(sym_name.start_with?("'") && sym_name.end_with?("'")) ||
|
|
234
|
+
(sym_name.start_with?('"') && sym_name.end_with?('"'))
|
|
214
235
|
end
|
|
236
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
215
237
|
|
|
216
238
|
def check(pairs, delim, msg)
|
|
217
239
|
pairs.each do |pair|
|
|
@@ -153,7 +153,18 @@ module RuboCop
|
|
|
153
153
|
return unless duplicated_expressions?(node, heads)
|
|
154
154
|
|
|
155
155
|
condition_variable = assignable_condition_value(node)
|
|
156
|
-
|
|
156
|
+
|
|
157
|
+
head = heads.first
|
|
158
|
+
if head.assignment?
|
|
159
|
+
# The `send` node is used instead of the `indexasgn` node, so `name` cannot be used.
|
|
160
|
+
# https://github.com/rubocop/rubocop-ast/blob/v1.29.0/lib/rubocop/ast/node/indexasgn_node.rb
|
|
161
|
+
#
|
|
162
|
+
# FIXME: It would be better to update `RuboCop::AST::OpAsgnNode` or its subclasses to
|
|
163
|
+
# handle `self.foo ||= value` as a solution, instead of using `head.node_parts[0].to_s`.
|
|
164
|
+
assigned_value = head.send_type? ? head.receiver.source : head.node_parts[0].to_s
|
|
165
|
+
|
|
166
|
+
return if condition_variable == assigned_value
|
|
167
|
+
end
|
|
157
168
|
|
|
158
169
|
check_expressions(node, heads, :before_condition)
|
|
159
170
|
end
|
|
@@ -112,9 +112,11 @@ module RuboCop
|
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
def message(node, keyword)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
if node.elsif?
|
|
116
|
+
MSG_FOR_ELSIF
|
|
117
|
+
else
|
|
118
|
+
format(MSG, keyword: keyword)
|
|
119
|
+
end
|
|
118
120
|
end
|
|
119
121
|
|
|
120
122
|
def return_boolean_value?(condition)
|
|
@@ -60,25 +60,25 @@ module RuboCop
|
|
|
60
60
|
# @!method inverse_candidate?(node)
|
|
61
61
|
def_node_matcher :inverse_candidate?, <<~PATTERN
|
|
62
62
|
{
|
|
63
|
-
(send $(
|
|
64
|
-
(send ({block numblock} $(
|
|
65
|
-
(send (begin $(
|
|
63
|
+
(send $(call $(...) $_ $...) :!)
|
|
64
|
+
(send ({block numblock} $(call $(...) $_) $...) :!)
|
|
65
|
+
(send (begin $(call $(...) $_ $...)) :!)
|
|
66
66
|
}
|
|
67
67
|
PATTERN
|
|
68
68
|
|
|
69
69
|
# @!method inverse_block?(node)
|
|
70
70
|
def_node_matcher :inverse_block?, <<~PATTERN
|
|
71
|
-
({block numblock} $(
|
|
71
|
+
({block numblock} $(call (...) $_) ... { $(call ... :!)
|
|
72
72
|
$(send (...) {:!= :!~} ...)
|
|
73
|
-
(begin ... $(
|
|
73
|
+
(begin ... $(call ... :!))
|
|
74
74
|
(begin ... $(send (...) {:!= :!~} ...))
|
|
75
75
|
})
|
|
76
76
|
PATTERN
|
|
77
77
|
|
|
78
78
|
def on_send(node)
|
|
79
|
-
inverse_candidate?(node) do |
|
|
79
|
+
inverse_candidate?(node) do |method_call, lhs, method, rhs|
|
|
80
80
|
return unless inverse_methods.key?(method)
|
|
81
|
-
return if negated?(node)
|
|
81
|
+
return if negated?(node) || relational_comparison_with_safe_navigation?(method_call)
|
|
82
82
|
return if part_of_ignored_node?(node)
|
|
83
83
|
return if possible_class_hierarchy_check?(lhs, rhs, method)
|
|
84
84
|
|
|
@@ -87,6 +87,7 @@ module RuboCop
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
+
alias on_csend on_send
|
|
90
91
|
|
|
91
92
|
def on_block(node)
|
|
92
93
|
inverse_block?(node) do |_method_call, method, block|
|
|
@@ -154,16 +155,16 @@ module RuboCop
|
|
|
154
155
|
node.parent.respond_to?(:method?) && node.parent.method?(:!)
|
|
155
156
|
end
|
|
156
157
|
|
|
158
|
+
def relational_comparison_with_safe_navigation?(node)
|
|
159
|
+
node.csend_type? && CLASS_COMPARISON_METHODS.include?(node.method_name)
|
|
160
|
+
end
|
|
161
|
+
|
|
157
162
|
def not_to_receiver(node, method_call)
|
|
158
|
-
|
|
159
|
-
node.loc.selector.begin_pos,
|
|
160
|
-
method_call.source_range.begin_pos)
|
|
163
|
+
node.loc.selector.begin.join(method_call.source_range.begin)
|
|
161
164
|
end
|
|
162
165
|
|
|
163
166
|
def end_parentheses(node, method_call)
|
|
164
|
-
|
|
165
|
-
method_call.source_range.end_pos,
|
|
166
|
-
node.source_range.end_pos)
|
|
167
|
+
method_call.source_range.end.join(node.source_range.end)
|
|
167
168
|
end
|
|
168
169
|
|
|
169
170
|
# When comparing classes, `!(Integer < Numeric)` is not the same as
|
|
@@ -32,12 +32,14 @@ module RuboCop
|
|
|
32
32
|
# foo unless x != y
|
|
33
33
|
# foo unless x >= 10
|
|
34
34
|
# foo unless x.even?
|
|
35
|
+
# foo unless odd?
|
|
35
36
|
#
|
|
36
37
|
# # good
|
|
37
38
|
# foo if bar
|
|
38
39
|
# foo if x == y
|
|
39
40
|
# foo if x < 10
|
|
40
41
|
# foo if x.odd?
|
|
42
|
+
# foo if even?
|
|
41
43
|
#
|
|
42
44
|
# # bad (complex condition)
|
|
43
45
|
# foo unless x != y || x.even?
|
|
@@ -51,7 +53,7 @@ module RuboCop
|
|
|
51
53
|
class InvertibleUnlessCondition < Base
|
|
52
54
|
extend AutoCorrector
|
|
53
55
|
|
|
54
|
-
MSG = '
|
|
56
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
|
55
57
|
|
|
56
58
|
def on_if(node)
|
|
57
59
|
return unless node.unless?
|
|
@@ -59,7 +61,10 @@ module RuboCop
|
|
|
59
61
|
condition = node.condition
|
|
60
62
|
return unless invertible?(condition)
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
message = format(MSG, prefer: "#{node.inverse_keyword} #{preferred_condition(condition)}",
|
|
65
|
+
current: "#{node.keyword} #{condition.source}")
|
|
66
|
+
|
|
67
|
+
add_offense(node, message: message) do |corrector|
|
|
63
68
|
corrector.replace(node.loc.keyword, node.inverse_keyword)
|
|
64
69
|
autocorrect(corrector, condition)
|
|
65
70
|
end
|
|
@@ -88,6 +93,43 @@ module RuboCop
|
|
|
88
93
|
(argument.const_type? && argument.short_name.to_s.upcase != argument.short_name.to_s)
|
|
89
94
|
end
|
|
90
95
|
|
|
96
|
+
def preferred_condition(node)
|
|
97
|
+
case node.type
|
|
98
|
+
when :begin then "(#{preferred_condition(node.children.first)})"
|
|
99
|
+
when :send then preferred_send_condition(node)
|
|
100
|
+
when :or, :and then preferred_logical_condition(node)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def preferred_send_condition(node) # rubocop:disable Metrics/CyclomaticComplexity
|
|
105
|
+
receiver_source = node.receiver&.source
|
|
106
|
+
return receiver_source if node.method?(:!)
|
|
107
|
+
|
|
108
|
+
# receiver may be implicit (self)
|
|
109
|
+
dotted_receiver_source = receiver_source ? "#{receiver_source}." : ''
|
|
110
|
+
|
|
111
|
+
inverse_method_name = inverse_methods[node.method_name]
|
|
112
|
+
return "#{dotted_receiver_source}#{inverse_method_name}" unless node.arguments?
|
|
113
|
+
|
|
114
|
+
argument_list = node.arguments.map(&:source).join(', ')
|
|
115
|
+
if node.operator_method?
|
|
116
|
+
return "#{receiver_source} #{inverse_method_name} #{argument_list}"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
if node.parenthesized?
|
|
120
|
+
return "#{dotted_receiver_source}#{inverse_method_name}(#{argument_list})"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
"#{dotted_receiver_source}#{inverse_method_name} #{argument_list}"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def preferred_logical_condition(node)
|
|
127
|
+
preferred_lhs = preferred_condition(node.lhs)
|
|
128
|
+
preferred_rhs = preferred_condition(node.rhs)
|
|
129
|
+
|
|
130
|
+
"#{preferred_lhs} #{node.inverse_operator} #{preferred_rhs}"
|
|
131
|
+
end
|
|
132
|
+
|
|
91
133
|
def autocorrect(corrector, node)
|
|
92
134
|
case node.type
|
|
93
135
|
when :begin
|
|
@@ -4,6 +4,7 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Prefer `select` or `reject` over `map { ... }.compact`.
|
|
7
|
+
# This cop also handles `filter_map { ... }`, similar to `map { ... }.compact`.
|
|
7
8
|
#
|
|
8
9
|
# @example
|
|
9
10
|
#
|
|
@@ -11,6 +12,9 @@ module RuboCop
|
|
|
11
12
|
# array.map { |e| some_condition? ? e : next }.compact
|
|
12
13
|
#
|
|
13
14
|
# # bad
|
|
15
|
+
# array.filter_map { |e| some_condition? ? e : next }
|
|
16
|
+
#
|
|
17
|
+
# # bad
|
|
14
18
|
# array.map do |e|
|
|
15
19
|
# if some_condition?
|
|
16
20
|
# e
|
|
@@ -40,54 +44,73 @@ module RuboCop
|
|
|
40
44
|
class MapCompactWithConditionalBlock < Base
|
|
41
45
|
extend AutoCorrector
|
|
42
46
|
|
|
43
|
-
MSG = 'Replace `
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
47
|
+
MSG = 'Replace `%<current>s` with `%<method>s`.'
|
|
48
|
+
RESTRICT_ON_SEND = %i[compact filter_map].freeze
|
|
49
|
+
|
|
50
|
+
# @!method conditional_block(node)
|
|
51
|
+
def_node_matcher :conditional_block, <<~RUBY
|
|
52
|
+
(block
|
|
53
|
+
(call _ {:map :filter_map})
|
|
54
|
+
(args
|
|
55
|
+
$(arg _))
|
|
56
|
+
{
|
|
57
|
+
(if $_ $(lvar _) {next nil?})
|
|
58
|
+
(if $_ {next nil?} $(lvar _))
|
|
59
|
+
(if $_ (next $(lvar _)) {next nil nil?})
|
|
60
|
+
(if $_ {next nil nil?} (next $(lvar _)))
|
|
61
|
+
(begin
|
|
62
|
+
{
|
|
63
|
+
(if $_ next nil?)
|
|
64
|
+
(if $_ nil? next)
|
|
65
|
+
}
|
|
66
|
+
$(lvar _))
|
|
67
|
+
(begin
|
|
68
|
+
{
|
|
69
|
+
(if $_ (next $(lvar _)) nil?)
|
|
70
|
+
(if $_ nil? (next $(lvar _)))
|
|
71
|
+
}
|
|
72
|
+
(nil))
|
|
73
|
+
})
|
|
70
74
|
RUBY
|
|
71
75
|
|
|
72
76
|
def on_send(node)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)
|
|
85
|
-
end
|
|
77
|
+
map_candidate = node.children.first
|
|
78
|
+
if (block_argument, condition, return_value = conditional_block(map_candidate))
|
|
79
|
+
return unless node.method?(:compact) && node.arguments.empty?
|
|
80
|
+
|
|
81
|
+
range = map_with_compact_range(node)
|
|
82
|
+
elsif (block_argument, condition, return_value = conditional_block(node.parent))
|
|
83
|
+
return unless node.method?(:filter_map)
|
|
84
|
+
|
|
85
|
+
range = filter_map_range(node)
|
|
86
|
+
else
|
|
87
|
+
return
|
|
86
88
|
end
|
|
89
|
+
|
|
90
|
+
inspect(node, block_argument, condition, return_value, range)
|
|
87
91
|
end
|
|
92
|
+
alias on_csend on_send
|
|
88
93
|
|
|
89
94
|
private
|
|
90
95
|
|
|
96
|
+
def inspect(node, block_argument_node, condition_node, return_value_node, range)
|
|
97
|
+
return unless returns_block_argument?(block_argument_node, return_value_node)
|
|
98
|
+
return if condition_node.parent.elsif?
|
|
99
|
+
|
|
100
|
+
method = truthy_branch?(return_value_node) ? 'select' : 'reject'
|
|
101
|
+
current = current(node)
|
|
102
|
+
|
|
103
|
+
add_offense(range, message: format(MSG, current: current, method: method)) do |corrector|
|
|
104
|
+
return if part_of_ignored_node?(node) || ignored_node?(node)
|
|
105
|
+
|
|
106
|
+
corrector.replace(
|
|
107
|
+
range, "#{method} { |#{block_argument_node.source}| #{condition_node.source} }"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
ignore_node(node)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
91
114
|
def returns_block_argument?(block_argument_node, return_value_node)
|
|
92
115
|
block_argument_node.name == return_value_node.children.first
|
|
93
116
|
end
|
|
@@ -115,20 +138,29 @@ module RuboCop
|
|
|
115
138
|
def truthy_branch_for_guard?(node)
|
|
116
139
|
if_node = node.left_sibling
|
|
117
140
|
|
|
118
|
-
if if_node.if?
|
|
119
|
-
if_node.
|
|
120
|
-
|
|
121
|
-
if_node.if_branch.
|
|
141
|
+
if if_node.if?
|
|
142
|
+
if_node.if_branch.arguments.any?
|
|
143
|
+
else
|
|
144
|
+
if_node.if_branch.arguments.none?
|
|
122
145
|
end
|
|
123
146
|
end
|
|
124
147
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
148
|
+
def current(node)
|
|
149
|
+
if node.method?(:compact)
|
|
150
|
+
map_or_filter_map_method = node.children.first
|
|
151
|
+
|
|
152
|
+
"#{map_or_filter_map_method.method_name} { ... }.compact"
|
|
153
|
+
else
|
|
154
|
+
'filter_map { ... }'
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def map_with_compact_range(node)
|
|
159
|
+
node.receiver.send_node.loc.selector.begin.join(node.source_range.end)
|
|
160
|
+
end
|
|
130
161
|
|
|
131
|
-
|
|
162
|
+
def filter_map_range(node)
|
|
163
|
+
node.loc.selector.join(node.parent.source_range.end)
|
|
132
164
|
end
|
|
133
165
|
end
|
|
134
166
|
end
|