rubocop 1.84.2 → 1.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/default.yml +106 -16
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cache_config.rb +1 -1
- data/lib/rubocop/cli/command/auto_generate_config.rb +28 -2
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli/command/show_cops.rb +2 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +9 -7
- data/lib/rubocop/comment_config.rb +12 -15
- data/lib/rubocop/config.rb +14 -10
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +17 -2
- data/lib/rubocop/config_loader_resolver.rb +13 -4
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_store.rb +2 -2
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
- data/lib/rubocop/cop/base.rb +8 -2
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/documentation.rb +2 -3
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +5 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +23 -7
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +8 -5
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +12 -0
- data/lib/rubocop/cop/layout/line_length.rb +5 -3
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +53 -3
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +3 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -0
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/constant_reassignment.rb +93 -11
- data/lib/rubocop/cop/lint/constant_resolution.rb +6 -6
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +55 -8
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_when.rb +8 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
- data/lib/rubocop/cop/lint/number_conversion.rb +6 -6
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -11
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +2 -2
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +4 -9
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +35 -9
- data/lib/rubocop/cop/lint/void.rb +32 -12
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +12 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
- data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
- data/lib/rubocop/cop/mixin.rb +86 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +2 -2
- data/lib/rubocop/cop/naming/predicate_prefix.rb +1 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +8 -0
- data/lib/rubocop/cop/registry.rb +62 -38
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +14 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
- data/lib/rubocop/cop/style/alias.rb +14 -2
- data/lib/rubocop/cop/style/and_or.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +5 -2
- data/lib/rubocop/cop/style/bare_percent_literals.rb +3 -1
- data/lib/rubocop/cop/style/begin_block.rb +3 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +25 -33
- data/lib/rubocop/cop/style/case_equality.rb +4 -0
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +18 -2
- data/lib/rubocop/cop/style/collection_compact.rb +36 -16
- data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +0 -4
- data/lib/rubocop/cop/style/copyright.rb +22 -11
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -0
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_class_definition.rb +43 -20
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/encoding.rb +7 -1
- data/lib/rubocop/cop/style/end_block.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +8 -3
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/file_write.rb +18 -16
- data/lib/rubocop/cop/style/for.rb +3 -0
- data/lib/rubocop/cop/style/format_string.rb +4 -3
- data/lib/rubocop/cop/style/format_string_token.rb +29 -2
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +9 -6
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +21 -5
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
- data/lib/rubocop/cop/style/hash_lookup_method.rb +19 -7
- data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
- data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
- data/lib/rubocop/cop/style/if_unless_modifier.rb +14 -3
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
- data/lib/rubocop/cop/style/inline_comment.rb +4 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -3
- data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
- data/lib/rubocop/cop/style/module_member_existence_check.rb +7 -14
- data/lib/rubocop/cop/style/multiline_if_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -3
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
- data/lib/rubocop/cop/style/not.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +4 -0
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
- data/lib/rubocop/cop/style/proc.rb +3 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
- data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
- data/lib/rubocop/cop/style/redundant_each.rb +3 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +25 -22
- data/lib/rubocop/cop/style/redundant_percent_q.rb +4 -1
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
- data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
- data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
- data/lib/rubocop/cop/style/select_by_range.rb +197 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +2 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
- data/lib/rubocop/cop/team.rb +86 -35
- data/lib/rubocop/cop/variable_force/branch.rb +2 -2
- data/lib/rubocop/directive_comment.rb +2 -1
- data/lib/rubocop/file_patterns.rb +9 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -2
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +22 -21
- data/lib/rubocop/lsp/diagnostic.rb +1 -0
- data/lib/rubocop/lsp/routes.rb +10 -3
- data/lib/rubocop/lsp/runtime.rb +1 -2
- data/lib/rubocop/mcp/server.rb +200 -0
- data/lib/rubocop/options.rb +35 -4
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/project_index_loader.rb +66 -0
- data/lib/rubocop/result_cache.rb +22 -10
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/shared_contexts.rb +32 -2
- data/lib/rubocop/runner.rb +124 -53
- data/lib/rubocop/server/cache.rb +5 -7
- data/lib/rubocop/server/core.rb +2 -0
- data/lib/rubocop/target_finder.rb +14 -7
- data/lib/rubocop/target_ruby.rb +18 -12
- data/lib/rubocop/version.rb +21 -3
- data/lib/rubocop.rb +22 -96
- metadata +27 -5
|
@@ -39,6 +39,9 @@ module RuboCop
|
|
|
39
39
|
# array.reject { |x| x =~ /regexp/ }
|
|
40
40
|
# array.reject { |x| /regexp/ =~ x }
|
|
41
41
|
#
|
|
42
|
+
# # bad (negative form)
|
|
43
|
+
# array.reject { |x| !x.match? /regexp/ }
|
|
44
|
+
#
|
|
42
45
|
# # good
|
|
43
46
|
# array.grep(regexp)
|
|
44
47
|
# array.grep_v(regexp)
|
|
@@ -48,18 +51,19 @@ module RuboCop
|
|
|
48
51
|
|
|
49
52
|
MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
|
|
50
53
|
RESTRICT_ON_SEND = %i[select filter find_all reject].freeze
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}.freeze
|
|
55
|
-
REGEXP_METHODS = %i[match? =~ !~].to_set.freeze
|
|
54
|
+
SELECT_METHODS = %i[select filter find_all].freeze
|
|
55
|
+
REGEXP_METHODS = %i[match? =~].to_set.freeze
|
|
56
|
+
REGEXP_METHODS_NEGATED = %i[!~].to_set.freeze
|
|
56
57
|
|
|
57
58
|
# @!method regexp_match?(node)
|
|
58
59
|
def_node_matcher :regexp_match?, <<~PATTERN
|
|
59
60
|
{
|
|
60
|
-
(block call (args (arg $_)) ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
|
|
61
|
-
(
|
|
62
|
-
(
|
|
61
|
+
(block call (args (arg $_)) ${(send _ %REGEXP_METHODS _) (send _ %REGEXP_METHODS_NEGATED _) match-with-lvasgn})
|
|
62
|
+
(block call (args (arg $_)) ${(send (send _ %REGEXP_METHODS _) :!) (send (begin (send _ %REGEXP_METHODS _)) :!) (send match-with-lvasgn :!) (send (begin match-with-lvasgn) :!)})
|
|
63
|
+
(numblock call $1 ${(send _ %REGEXP_METHODS _) (send _ %REGEXP_METHODS_NEGATED _) match-with-lvasgn})
|
|
64
|
+
(numblock call $1 ${(send (send _ %REGEXP_METHODS _) :!) (send (begin (send _ %REGEXP_METHODS _)) :!) (send match-with-lvasgn :!) (send (begin match-with-lvasgn) :!)})
|
|
65
|
+
(itblock call $_ ${(send _ %REGEXP_METHODS _) (send _ %REGEXP_METHODS_NEGATED _) match-with-lvasgn})
|
|
66
|
+
(itblock call $_ ${(send (send _ %REGEXP_METHODS _) :!) (send (begin (send _ %REGEXP_METHODS _)) :!) (send match-with-lvasgn :!) (send (begin match-with-lvasgn) :!)})
|
|
63
67
|
}
|
|
64
68
|
PATTERN
|
|
65
69
|
|
|
@@ -84,6 +88,12 @@ module RuboCop
|
|
|
84
88
|
(send (lvar %1) ...)
|
|
85
89
|
(send ... (lvar %1))
|
|
86
90
|
(match-with-lvasgn regexp (lvar %1))
|
|
91
|
+
(send (send (lvar %1) ...) :!)
|
|
92
|
+
(send (send ... (lvar %1)) :!)
|
|
93
|
+
(send (match-with-lvasgn regexp (lvar %1)) :!)
|
|
94
|
+
(send (begin (send (lvar %1) ...)) :!)
|
|
95
|
+
(send (begin (send ... (lvar %1))) :!)
|
|
96
|
+
(send (begin (match-with-lvasgn regexp (lvar %1))) :!)
|
|
87
97
|
}
|
|
88
98
|
PATTERN
|
|
89
99
|
|
|
@@ -97,7 +107,7 @@ module RuboCop
|
|
|
97
107
|
return if match_predicate_without_receiver?(regexp_method_send_node)
|
|
98
108
|
|
|
99
109
|
replacement = replacement(regexp_method_send_node, node)
|
|
100
|
-
return if target_ruby_version <= 2.2 && replacement
|
|
110
|
+
return if target_ruby_version <= 2.2 && replacement.include?('grep_v')
|
|
101
111
|
|
|
102
112
|
regexp = find_regexp(regexp_method_send_node, block_node)
|
|
103
113
|
|
|
@@ -115,11 +125,14 @@ module RuboCop
|
|
|
115
125
|
end
|
|
116
126
|
|
|
117
127
|
def replacement(regexp_method_send_node, node)
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
negated = negated?(regexp_method_send_node)
|
|
120
129
|
method_name = node.method_name
|
|
121
130
|
|
|
122
|
-
|
|
131
|
+
if SELECT_METHODS.include?(method_name)
|
|
132
|
+
negated ? 'grep_v' : 'grep'
|
|
133
|
+
else # reject
|
|
134
|
+
negated ? 'grep' : 'grep_v'
|
|
135
|
+
end
|
|
123
136
|
end
|
|
124
137
|
|
|
125
138
|
def register_offense(node, block_node, regexp, replacement)
|
|
@@ -138,30 +151,47 @@ module RuboCop
|
|
|
138
151
|
return unless (block_arg_name, regexp_method_send_node = regexp_match?(block_node))
|
|
139
152
|
|
|
140
153
|
block_arg_name = :"_#{block_arg_name}" if block_node.numblock_type?
|
|
154
|
+
block_arg_name = :it if block_node.type?(:itblock)
|
|
141
155
|
|
|
142
156
|
return unless calls_lvar?(regexp_method_send_node, block_arg_name)
|
|
143
157
|
|
|
144
158
|
regexp_method_send_node
|
|
145
159
|
end
|
|
146
160
|
|
|
147
|
-
def
|
|
148
|
-
regexp_method_send_node.send_type? && regexp_method_send_node.method?(
|
|
161
|
+
def negated?(regexp_method_send_node)
|
|
162
|
+
return true if regexp_method_send_node.send_type? && regexp_method_send_node.method?(:!)
|
|
163
|
+
|
|
164
|
+
inner = unwrap_negation(regexp_method_send_node)
|
|
165
|
+
inner.send_type? && inner.method?(:!~)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def unwrap_negation(node)
|
|
169
|
+
if node.send_type? && node.method?(:!)
|
|
170
|
+
receiver = node.receiver
|
|
171
|
+
receiver = receiver.children.first if receiver.begin_type?
|
|
172
|
+
receiver
|
|
173
|
+
else
|
|
174
|
+
node
|
|
175
|
+
end
|
|
149
176
|
end
|
|
150
177
|
|
|
151
178
|
def find_regexp(node, block)
|
|
152
|
-
|
|
179
|
+
inner = unwrap_negation(node)
|
|
180
|
+
|
|
181
|
+
return inner.child_nodes.first if inner.match_with_lvasgn_type?
|
|
153
182
|
|
|
154
|
-
if
|
|
183
|
+
if inner.receiver.lvar_type? &&
|
|
155
184
|
(block.type?(:numblock, :itblock) ||
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
elsif
|
|
159
|
-
|
|
185
|
+
inner.receiver.source == block.first_argument.source)
|
|
186
|
+
inner.first_argument
|
|
187
|
+
elsif inner.first_argument&.lvar_type?
|
|
188
|
+
inner.receiver
|
|
160
189
|
end
|
|
161
190
|
end
|
|
162
191
|
|
|
163
192
|
def match_predicate_without_receiver?(node)
|
|
164
|
-
|
|
193
|
+
inner = unwrap_negation(node)
|
|
194
|
+
inner.send_type? && inner.method?(:match?) && inner.receiver.nil?
|
|
165
195
|
end
|
|
166
196
|
end
|
|
167
197
|
end
|
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for multiple expressions placed on the same line.
|
|
7
7
|
# It also checks for lines terminated with a semicolon.
|
|
8
|
+
# In idiomatic Ruby, each expression should be on its own line
|
|
9
|
+
# for readability.
|
|
8
10
|
#
|
|
9
11
|
# This cop has `AllowAsExpressionSeparator` configuration option.
|
|
10
12
|
# It allows `;` to separate several expressions on the same line.
|
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
|
33
33
|
|
|
34
34
|
MSG = 'Name `%<method>s` block params `|%<params>s|`.'
|
|
35
35
|
|
|
36
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
36
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
37
37
|
return unless node.single_line?
|
|
38
38
|
|
|
39
39
|
return unless eligible_method?(node)
|
|
@@ -89,7 +89,7 @@ module RuboCop
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
def method_names
|
|
92
|
-
methods.map { |method| method_name(method).to_sym }
|
|
92
|
+
@method_names ||= methods.map { |method| method_name(method).to_sym }.freeze
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def method_name(method)
|
|
@@ -38,7 +38,7 @@ module RuboCop
|
|
|
38
38
|
|
|
39
39
|
# rubocop:disable Metrics/AbcSize
|
|
40
40
|
def on_block(node)
|
|
41
|
-
return if
|
|
41
|
+
return if node.multiline? || node.braces?
|
|
42
42
|
return if single_line_blocks_preferred? && suitable_as_single_line?(node)
|
|
43
43
|
|
|
44
44
|
add_offense(node) do |corrector|
|
|
@@ -4,7 +4,9 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for single-line method definitions that contain a body.
|
|
7
|
-
#
|
|
7
|
+
# Single-line methods with a body are harder to read and debug
|
|
8
|
+
# than their multi-line equivalents. It will accept single-line
|
|
9
|
+
# methods with no body.
|
|
8
10
|
#
|
|
9
11
|
# Endless methods added in Ruby 3.0 are also accepted by this cop.
|
|
10
12
|
#
|
|
@@ -65,7 +65,10 @@ module RuboCop
|
|
|
65
65
|
|
|
66
66
|
message = format(MSG, conditional_type: node.keyword)
|
|
67
67
|
add_offense(if_branch.loc.keyword, message: message) do |corrector|
|
|
68
|
+
next if ignored_node?(node)
|
|
69
|
+
|
|
68
70
|
autocorrect(corrector, node, if_branch)
|
|
71
|
+
ignore_node(if_branch)
|
|
69
72
|
end
|
|
70
73
|
end
|
|
71
74
|
|
|
@@ -115,9 +118,8 @@ module RuboCop
|
|
|
115
118
|
end
|
|
116
119
|
|
|
117
120
|
def correct_node(corrector, node)
|
|
118
|
-
corrector.replace(node.loc.keyword, 'if') if node.unless?
|
|
121
|
+
corrector.replace(node.loc.keyword, 'if') if node.unless?
|
|
119
122
|
corrector.replace(node.condition, chainable_condition(node))
|
|
120
|
-
ignore_node(node)
|
|
121
123
|
end
|
|
122
124
|
|
|
123
125
|
def correct_for_guard_condition_style(corrector, node, if_branch)
|
|
@@ -4,7 +4,12 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Looks for uses of Perl-style global variables.
|
|
7
|
-
#
|
|
7
|
+
# Perl-style global variables like `$;` or `$/` are cryptic
|
|
8
|
+
# and hard to understand without consulting documentation.
|
|
9
|
+
# The `English` library provides descriptive aliases like
|
|
10
|
+
# `$FIELD_SEPARATOR` and `$INPUT_RECORD_SEPARATOR`.
|
|
11
|
+
#
|
|
12
|
+
# Correcting to global variables in the `English` library
|
|
8
13
|
# will add a require statement to the top of the file if
|
|
9
14
|
# enabled by RequireEnglish config.
|
|
10
15
|
#
|
|
@@ -61,6 +61,8 @@ module RuboCop
|
|
|
61
61
|
corrector.remove(range_with_surrounding_space(parent.loc.end, newlines: false))
|
|
62
62
|
elsif (class_node = parent.parent).body.nil?
|
|
63
63
|
corrector.remove(range_for_empty_class_body(class_node, parent))
|
|
64
|
+
elsif unparenthesized_struct_new?(parent)
|
|
65
|
+
wrap_unparenthesized_call_with_do(corrector, parent)
|
|
64
66
|
else
|
|
65
67
|
corrector.insert_after(parent, ' do')
|
|
66
68
|
end
|
|
@@ -73,6 +75,17 @@ module RuboCop
|
|
|
73
75
|
range_by_whole_lines(class_node.loc.end, include_final_newline: true)
|
|
74
76
|
end
|
|
75
77
|
end
|
|
78
|
+
|
|
79
|
+
def unparenthesized_struct_new?(parent)
|
|
80
|
+
parent.send_type? && parent.arguments.any? && !parent.parenthesized?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def wrap_unparenthesized_call_with_do(corrector, parent)
|
|
84
|
+
args_source = parent.arguments.map(&:source).join(', ')
|
|
85
|
+
range = parent.loc.selector.end.join(parent.source_range.end)
|
|
86
|
+
|
|
87
|
+
corrector.replace(range, "(#{args_source}) do")
|
|
88
|
+
end
|
|
76
89
|
end
|
|
77
90
|
end
|
|
78
91
|
end
|
|
@@ -179,7 +179,7 @@ module RuboCop
|
|
|
179
179
|
return if allowed_method_name?(dispatch_node.method_name)
|
|
180
180
|
return if allow_if_method_has_argument?(node.send_node)
|
|
181
181
|
return if node.block_type? && destructuring_block_argument?(arguments_node)
|
|
182
|
-
return if allow_comments?
|
|
182
|
+
return if allow_comments?(node)
|
|
183
183
|
|
|
184
184
|
register_offense(node, method_name, dispatch_node.method_name)
|
|
185
185
|
end
|
|
@@ -260,10 +260,10 @@ module RuboCop
|
|
|
260
260
|
end
|
|
261
261
|
|
|
262
262
|
def begin_pos_for_replacement(node)
|
|
263
|
-
|
|
263
|
+
send_node = node.send_node
|
|
264
264
|
|
|
265
|
-
if
|
|
266
|
-
|
|
265
|
+
if send_node.parenthesized? && send_node.arguments.empty?
|
|
266
|
+
send_node.loc.begin.begin_pos
|
|
267
267
|
else
|
|
268
268
|
node.loc.begin.begin_pos
|
|
269
269
|
end
|
|
@@ -273,8 +273,9 @@ module RuboCop
|
|
|
273
273
|
!!cop_config.fetch('AllowMethodsWithArguments', false) && send_node.arguments.any?
|
|
274
274
|
end
|
|
275
275
|
|
|
276
|
-
def allow_comments?
|
|
277
|
-
cop_config.fetch('AllowComments', false)
|
|
276
|
+
def allow_comments?(node)
|
|
277
|
+
cop_config.fetch('AllowComments', false) && contains_comments?(node) &&
|
|
278
|
+
!comments_contain_disables?(node, name)
|
|
278
279
|
end
|
|
279
280
|
end
|
|
280
281
|
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for manual counting patterns that can be replaced by `Enumerable#tally`.
|
|
7
|
+
#
|
|
8
|
+
# The cop detects the following patterns:
|
|
9
|
+
#
|
|
10
|
+
# - `each_with_object(Hash.new(0)) { |item, counts| counts[item] += 1 }`
|
|
11
|
+
# - `group_by(&:itself).transform_values(&:count)`
|
|
12
|
+
# - `group_by { |x| x }.transform_values(&:size)`
|
|
13
|
+
# - `group_by { |x| x }.transform_values { |v| v.length }`
|
|
14
|
+
#
|
|
15
|
+
# @safety
|
|
16
|
+
# This cop is unsafe because it cannot guarantee that the receiver
|
|
17
|
+
# is an `Enumerable` by static analysis, so the correction may
|
|
18
|
+
# not be actually equivalent.
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# # bad
|
|
22
|
+
# array.each_with_object(Hash.new(0)) { |item, counts| counts[item] += 1 }
|
|
23
|
+
#
|
|
24
|
+
# # bad
|
|
25
|
+
# array.group_by(&:itself).transform_values(&:count)
|
|
26
|
+
#
|
|
27
|
+
# # bad
|
|
28
|
+
# array.group_by { |item| item }.transform_values(&:size)
|
|
29
|
+
#
|
|
30
|
+
# # bad
|
|
31
|
+
# array.group_by { |item| item }.transform_values { |v| v.length }
|
|
32
|
+
#
|
|
33
|
+
# # good
|
|
34
|
+
# array.tally
|
|
35
|
+
#
|
|
36
|
+
class TallyMethod < Base
|
|
37
|
+
extend AutoCorrector
|
|
38
|
+
extend TargetRubyVersion
|
|
39
|
+
include RangeHelp
|
|
40
|
+
|
|
41
|
+
minimum_target_ruby_version 2.7
|
|
42
|
+
|
|
43
|
+
MSG_EACH_WITH_OBJECT = 'Use `tally` instead of `each_with_object`.'
|
|
44
|
+
MSG_GROUP_BY = 'Use `tally` instead of `group_by` and `transform_values`.'
|
|
45
|
+
RESTRICT_ON_SEND = %i[each_with_object transform_values].freeze
|
|
46
|
+
COUNTING_METHODS = %i[count size length].to_set.freeze
|
|
47
|
+
|
|
48
|
+
# Pattern 1: collection.each_with_object(Hash.new(0)) { |elem, hash| hash[elem] += 1 }
|
|
49
|
+
# @!method tally_each_with_object?(node)
|
|
50
|
+
def_node_matcher :tally_each_with_object?, <<~PATTERN
|
|
51
|
+
{
|
|
52
|
+
(block
|
|
53
|
+
(call _ :each_with_object
|
|
54
|
+
(send (const {nil? cbase} :Hash) :new (int 0)))
|
|
55
|
+
(args (arg _elem) (arg _hash))
|
|
56
|
+
(op_asgn
|
|
57
|
+
(send (lvar _hash) :[] (lvar _elem)) :+ (int 1)))
|
|
58
|
+
(numblock
|
|
59
|
+
(call _ :each_with_object
|
|
60
|
+
(send (const {nil? cbase} :Hash) :new (int 0)))
|
|
61
|
+
2
|
|
62
|
+
(op_asgn
|
|
63
|
+
(send (lvar :_2) :[] (lvar :_1)) :+ (int 1)))
|
|
64
|
+
}
|
|
65
|
+
PATTERN
|
|
66
|
+
|
|
67
|
+
# Pattern 2: collection.group_by(&:itself).transform_values(&:count/size/length)
|
|
68
|
+
# @!method tally_group_by_symbol?(node)
|
|
69
|
+
def_node_matcher :tally_group_by_symbol?, <<~PATTERN
|
|
70
|
+
(call
|
|
71
|
+
(call _ :group_by (block_pass (sym :itself)))
|
|
72
|
+
:transform_values
|
|
73
|
+
(block_pass (sym %COUNTING_METHODS)))
|
|
74
|
+
PATTERN
|
|
75
|
+
|
|
76
|
+
# Pattern 3: collection.group_by { |x| x }.transform_values(&:count/size/length)
|
|
77
|
+
# @!method tally_group_by_identity_block?(node)
|
|
78
|
+
def_node_matcher :tally_group_by_identity_block?, <<~PATTERN
|
|
79
|
+
(call
|
|
80
|
+
{
|
|
81
|
+
(block (call _ :group_by) (args (arg _x)) (lvar _x))
|
|
82
|
+
(numblock (call _ :group_by) 1 (lvar :_1))
|
|
83
|
+
(itblock (call _ :group_by) :it (lvar :it))
|
|
84
|
+
}
|
|
85
|
+
:transform_values
|
|
86
|
+
(block_pass (sym %COUNTING_METHODS)))
|
|
87
|
+
PATTERN
|
|
88
|
+
|
|
89
|
+
# Pattern 4: collection.group_by(&:itself).transform_values { |v| v.count/size/length }
|
|
90
|
+
# collection.group_by { |x| x }.transform_values { |v| v.count/size/length }
|
|
91
|
+
# @!method tally_group_by_transform_block?(node)
|
|
92
|
+
def_node_matcher :tally_group_by_transform_block?, <<~PATTERN
|
|
93
|
+
{
|
|
94
|
+
(block
|
|
95
|
+
(call
|
|
96
|
+
{
|
|
97
|
+
(call _ :group_by (block_pass (sym :itself)))
|
|
98
|
+
(block (call _ :group_by) (args (arg _x)) (lvar _x))
|
|
99
|
+
(numblock (call _ :group_by) 1 (lvar :_1))
|
|
100
|
+
(itblock (call _ :group_by) :it (lvar :it))
|
|
101
|
+
}
|
|
102
|
+
:transform_values)
|
|
103
|
+
(args (arg _v))
|
|
104
|
+
(send (lvar _v) %COUNTING_METHODS))
|
|
105
|
+
(numblock
|
|
106
|
+
(call
|
|
107
|
+
{
|
|
108
|
+
(call _ :group_by (block_pass (sym :itself)))
|
|
109
|
+
(block (call _ :group_by) (args (arg _x)) (lvar _x))
|
|
110
|
+
(numblock (call _ :group_by) 1 (lvar :_1))
|
|
111
|
+
(itblock (call _ :group_by) :it (lvar :it))
|
|
112
|
+
}
|
|
113
|
+
:transform_values)
|
|
114
|
+
1
|
|
115
|
+
(send (lvar :_1) %COUNTING_METHODS))
|
|
116
|
+
(itblock
|
|
117
|
+
(call
|
|
118
|
+
{
|
|
119
|
+
(call _ :group_by (block_pass (sym :itself)))
|
|
120
|
+
(block (call _ :group_by) (args (arg _x)) (lvar _x))
|
|
121
|
+
(numblock (call _ :group_by) 1 (lvar :_1))
|
|
122
|
+
(itblock (call _ :group_by) :it (lvar :it))
|
|
123
|
+
}
|
|
124
|
+
:transform_values)
|
|
125
|
+
:it
|
|
126
|
+
(send (lvar :it) %COUNTING_METHODS))
|
|
127
|
+
}
|
|
128
|
+
PATTERN
|
|
129
|
+
def on_send(node)
|
|
130
|
+
if node.method?(:each_with_object)
|
|
131
|
+
check_each_with_object(node)
|
|
132
|
+
elsif node.method?(:transform_values)
|
|
133
|
+
check_transform_values(node)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
alias on_csend on_send
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
def check_each_with_object(node)
|
|
141
|
+
block_node = node.block_node
|
|
142
|
+
return unless block_node
|
|
143
|
+
return unless tally_each_with_object?(block_node)
|
|
144
|
+
|
|
145
|
+
add_offense(node.loc.selector, message: MSG_EACH_WITH_OBJECT) do |corrector|
|
|
146
|
+
corrector.replace(replacement_range(node, block_node), 'tally')
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def check_transform_values(node)
|
|
151
|
+
if tally_group_by_symbol?(node) || tally_group_by_identity_block?(node)
|
|
152
|
+
register_group_by_offense(node, node)
|
|
153
|
+
elsif (block_node = node.block_node) && tally_group_by_transform_block?(block_node)
|
|
154
|
+
register_group_by_offense(node, block_node)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def register_group_by_offense(transform_node, end_node)
|
|
159
|
+
group_by_node = group_by_send_node(transform_node)
|
|
160
|
+
|
|
161
|
+
add_offense(group_by_node.loc.selector, message: MSG_GROUP_BY) do |corrector|
|
|
162
|
+
corrector.replace(replacement_range(group_by_node, end_node), 'tally')
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def group_by_send_node(transform_node)
|
|
167
|
+
receiver = transform_node.receiver
|
|
168
|
+
if receiver.type?(:any_block)
|
|
169
|
+
receiver.send_node
|
|
170
|
+
else
|
|
171
|
+
receiver
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def replacement_range(start_node, end_node)
|
|
176
|
+
range_between(start_node.loc.selector.begin_pos, end_node.source_range.end_pos)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Newcomers to
|
|
6
|
+
# Newcomers to Ruby applications may write top-level methods,
|
|
7
7
|
# when ideally they should be organized in appropriate classes or modules.
|
|
8
8
|
# This cop looks for definitions of top-level methods and warns about them.
|
|
9
9
|
#
|
|
10
|
-
# However for
|
|
10
|
+
# However, for Ruby scripts it is perfectly fine to use top-level methods.
|
|
11
11
|
# Hence this cop is disabled by default.
|
|
12
12
|
#
|
|
13
13
|
# @example
|
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
|
64
64
|
|
|
65
65
|
MSG = 'Useless trailing comma present in block arguments.'
|
|
66
66
|
|
|
67
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
67
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
68
68
|
# lambda literal (`->`) never has block arguments.
|
|
69
69
|
return if node.send_node.lambda_literal?
|
|
70
70
|
return unless useless_trailing_comma?(node)
|
|
@@ -14,11 +14,11 @@ module RuboCop
|
|
|
14
14
|
#
|
|
15
15
|
# `forbid_mixed_logical_operators` style forbids the use of more than one type
|
|
16
16
|
# of logical operators. This makes the `unless` condition easier to read
|
|
17
|
-
# because either all conditions need to be met or any condition
|
|
17
|
+
# because either all conditions need to be met or any condition needs to be met
|
|
18
18
|
# in order for the expression to be truthy or falsey.
|
|
19
19
|
#
|
|
20
|
-
# `forbid_logical_operators` style forbids any use of logical
|
|
21
|
-
# This makes it even
|
|
20
|
+
# `forbid_logical_operators` style forbids any use of logical operators.
|
|
21
|
+
# This makes it even easier to read the `unless` condition as
|
|
22
22
|
# there is only one condition in the expression.
|
|
23
23
|
#
|
|
24
24
|
# @example EnforcedStyle: forbid_mixed_logical_operators (default)
|
|
@@ -16,6 +16,11 @@ module RuboCop
|
|
|
16
16
|
# # good
|
|
17
17
|
# x += 1 while x < 10
|
|
18
18
|
#
|
|
19
|
+
# # good
|
|
20
|
+
# while x < 10
|
|
21
|
+
# y += 1 if x.odd?
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
19
24
|
# # bad
|
|
20
25
|
# until x > 10
|
|
21
26
|
# x += 1
|
|
@@ -24,6 +29,11 @@ module RuboCop
|
|
|
24
29
|
# # good
|
|
25
30
|
# x += 1 until x > 10
|
|
26
31
|
#
|
|
32
|
+
# # good
|
|
33
|
+
# until x > 10
|
|
34
|
+
# y += 1 unless x.even?
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
27
37
|
# # bad
|
|
28
38
|
# x += 100 while x < 500 # a long comment that makes code too long if it were a single line
|
|
29
39
|
#
|
|
@@ -45,6 +55,12 @@ module RuboCop
|
|
|
45
55
|
end
|
|
46
56
|
end
|
|
47
57
|
alias on_until on_while
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def non_eligible_body?(body)
|
|
62
|
+
body&.conditional? || super
|
|
63
|
+
end
|
|
48
64
|
end
|
|
49
65
|
end
|
|
50
66
|
end
|