rubocop 1.70.0 → 1.71.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/README.md +1 -1
- data/config/default.yml +17 -0
- data/lib/rubocop/cli/command/show_cops.rb +24 -2
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
- 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/on_send_without_on_csend.rb +90 -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.rb +3 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -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 +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
- 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/line_end_string_concatenation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -5
- 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_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
- 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/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 +2 -6
- 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 +1 -1
- 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 +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +13 -3
- 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 +3 -3
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +13 -18
- 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/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 +3 -3
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- 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_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 +2 -7
- 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/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -5
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
- data/lib/rubocop/cop/mixin/hash_subset.rb +188 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +22 -8
- data/lib/rubocop/cop/mixin/statement_modifier.rb +7 -2
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
- data/lib/rubocop/cop/naming/block_forwarding.rb +18 -14
- 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 +2 -4
- data/lib/rubocop/cop/style/arguments_forwarding.rb +38 -19
- 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 +1 -1
- 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 +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -3
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- 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 +20 -131
- data/lib/rubocop/cop/style/hash_slice.rb +80 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- 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 +1 -1
- 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 +10 -13
- 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/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +2 -2
- 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/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/raise_args.rb +1 -1
- 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_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_freeze.rb +2 -2
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -10
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -6
- 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 +12 -27
- 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 +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- 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 +4 -4
- 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_expression.rb +1 -1
- data/lib/rubocop/cop/util.rb +2 -2
- 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 +9 -8
- data/lib/rubocop/options.rb +2 -1
- data/lib/rubocop/result_cache.rb +13 -13
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/rspec/support.rb +1 -2
- data/lib/rubocop/target_finder.rb +1 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +15 -11
- data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -32,6 +32,21 @@ module RuboCop
|
|
32
32
|
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].include?(k) }
|
33
33
|
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| !%i[bar].include?(k) }
|
34
34
|
#
|
35
|
+
# # good
|
36
|
+
# {foo: 1, bar: 2, baz: 3}.except(:bar)
|
37
|
+
#
|
38
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].exclude?(k) }
|
42
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].exclude?(k) }
|
43
|
+
#
|
44
|
+
# # good
|
45
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| k.in?(%i[bar]) }
|
46
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !k.in?(%i[bar]) }
|
47
|
+
#
|
48
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
49
|
+
#
|
35
50
|
# # bad
|
36
51
|
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].exclude?(k) }
|
37
52
|
# {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].exclude?(k) }
|
@@ -44,146 +59,20 @@ module RuboCop
|
|
44
59
|
# {foo: 1, bar: 2, baz: 3}.except(:bar)
|
45
60
|
#
|
46
61
|
class HashExcept < Base
|
47
|
-
include
|
62
|
+
include HashSubset
|
48
63
|
extend TargetRubyVersion
|
49
64
|
extend AutoCorrector
|
50
65
|
|
51
66
|
minimum_target_ruby_version 3.0
|
52
67
|
|
53
|
-
MSG = 'Use `%<prefer>s` instead.'
|
54
|
-
RESTRICT_ON_SEND = %i[reject select filter].freeze
|
55
|
-
|
56
|
-
SUBSET_METHODS = %i[== != eql? include?].freeze
|
57
|
-
ACTIVE_SUPPORT_SUBSET_METHODS = (SUBSET_METHODS + %i[in? exclude?]).freeze
|
58
|
-
|
59
|
-
# @!method block_with_first_arg_check?(node)
|
60
|
-
def_node_matcher :block_with_first_arg_check?, <<~PATTERN
|
61
|
-
(block
|
62
|
-
(call _ _)
|
63
|
-
(args
|
64
|
-
$(arg _key)
|
65
|
-
(arg _))
|
66
|
-
{
|
67
|
-
$(send
|
68
|
-
{(lvar _key) $_ _ | _ $_ (lvar _key)})
|
69
|
-
(send
|
70
|
-
$(send
|
71
|
-
{(lvar _key) $_ _ | _ $_ (lvar _key)}) :!)
|
72
|
-
})
|
73
|
-
PATTERN
|
74
|
-
|
75
|
-
def on_send(node)
|
76
|
-
block = node.parent
|
77
|
-
return unless extracts_hash_subset?(block) && semantically_except_method?(node, block)
|
78
|
-
|
79
|
-
except_key = except_key(block)
|
80
|
-
return unless safe_to_register_offense?(block, except_key)
|
81
|
-
|
82
|
-
range = offense_range(node)
|
83
|
-
preferred_method = "except(#{except_key_source(except_key)})"
|
84
|
-
|
85
|
-
add_offense(range, message: format(MSG, prefer: preferred_method)) do |corrector|
|
86
|
-
corrector.replace(range, preferred_method)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
alias on_csend on_send
|
90
|
-
|
91
68
|
private
|
92
69
|
|
93
|
-
def
|
94
|
-
|
95
|
-
return false unless supported_subset_method?(method)
|
96
|
-
|
97
|
-
case method
|
98
|
-
when :include?, :exclude?
|
99
|
-
send_node.first_argument.source == key_arg.source
|
100
|
-
when :in?
|
101
|
-
send_node.receiver.source == key_arg.source
|
102
|
-
else
|
103
|
-
true
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def supported_subset_method?(method)
|
109
|
-
if active_support_extensions_enabled?
|
110
|
-
ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
|
111
|
-
else
|
112
|
-
SUBSET_METHODS.include?(method)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def semantically_except_method?(node, block)
|
117
|
-
body, negated = extract_body_if_negated(block.body)
|
118
|
-
|
119
|
-
if node.method?('reject')
|
120
|
-
body.method?('==') || body.method?('eql?') || included?(body, negated)
|
121
|
-
else
|
122
|
-
body.method?('!=') || not_included?(body, negated)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def included?(body, negated)
|
127
|
-
if negated
|
128
|
-
body.method?('exclude?')
|
129
|
-
else
|
130
|
-
body.method?('include?') || body.method?('in?')
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def not_included?(body, negated)
|
135
|
-
included?(body, !negated)
|
136
|
-
end
|
137
|
-
|
138
|
-
def safe_to_register_offense?(block, except_key)
|
139
|
-
body = block.body
|
140
|
-
|
141
|
-
if body.method?('==') || body.method?('!=')
|
142
|
-
except_key.sym_type? || except_key.str_type?
|
143
|
-
else
|
144
|
-
true
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def extract_body_if_negated(body)
|
149
|
-
if body.method?('!')
|
150
|
-
[body.receiver, true]
|
151
|
-
else
|
152
|
-
[body, false]
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def except_key_source(key)
|
157
|
-
if key.array_type?
|
158
|
-
key = if key.percent_literal?
|
159
|
-
key.each_value.map { |v| decorate_source(v) }
|
160
|
-
else
|
161
|
-
key.each_value.map(&:source)
|
162
|
-
end
|
163
|
-
return key.join(', ')
|
164
|
-
end
|
165
|
-
|
166
|
-
key.literal? ? key.source : "*#{key.source}"
|
167
|
-
end
|
168
|
-
|
169
|
-
def decorate_source(value)
|
170
|
-
return ":\"#{value.source}\"" if value.dsym_type?
|
171
|
-
return "\"#{value.source}\"" if value.dstr_type?
|
172
|
-
return ":#{value.source}" if value.sym_type?
|
173
|
-
|
174
|
-
"'#{value.source}'"
|
175
|
-
end
|
176
|
-
|
177
|
-
def except_key(node)
|
178
|
-
key_arg = node.argument_list.first.source
|
179
|
-
body, = extract_body_if_negated(node.body)
|
180
|
-
lhs, _method_name, rhs = *body
|
181
|
-
|
182
|
-
lhs.source == key_arg ? rhs : lhs
|
70
|
+
def semantically_subset_method?(node)
|
71
|
+
semantically_except_method?(node)
|
183
72
|
end
|
184
73
|
|
185
|
-
def
|
186
|
-
|
74
|
+
def preferred_method_name
|
75
|
+
'except'
|
187
76
|
end
|
188
77
|
end
|
189
78
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
|
7
|
+
# that can be replaced with `Hash#slice` method.
|
8
|
+
#
|
9
|
+
# This cop should only be enabled on Ruby version 2.5 or higher.
|
10
|
+
# (`Hash#slice` was added in Ruby 2.5.)
|
11
|
+
#
|
12
|
+
# For safe detection, it is limited to commonly used string and symbol comparisons
|
13
|
+
# when using `==` or `!=`.
|
14
|
+
#
|
15
|
+
# This cop doesn't check for `Hash#delete_if` and `Hash#keep_if` because they
|
16
|
+
# modify the receiver.
|
17
|
+
#
|
18
|
+
# @safety
|
19
|
+
# This cop is unsafe because it cannot be guaranteed that the receiver
|
20
|
+
# is a `Hash` or responds to the replacement method.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
#
|
24
|
+
# # bad
|
25
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| k == :bar }
|
26
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| k != :bar }
|
27
|
+
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| k == :bar }
|
28
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| k.eql?(:bar) }
|
29
|
+
#
|
30
|
+
# # bad
|
31
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].include?(k) }
|
32
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].include?(k) }
|
33
|
+
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| %i[bar].include?(k) }
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# {foo: 1, bar: 2, baz: 3}.slice(:bar)
|
37
|
+
#
|
38
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].exclude?(k) }
|
42
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].exclude?(k) }
|
43
|
+
#
|
44
|
+
# # good
|
45
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| k.in?(%i[bar]) }
|
46
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !k.in?(%i[bar]) }
|
47
|
+
#
|
48
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
49
|
+
#
|
50
|
+
# # bad
|
51
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].exclude?(k) }
|
52
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].exclude?(k) }
|
53
|
+
#
|
54
|
+
# # bad
|
55
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| k.in?(%i[bar]) }
|
56
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !k.in?(%i[bar]) }
|
57
|
+
#
|
58
|
+
# # good
|
59
|
+
# {foo: 1, bar: 2, baz: 3}.slice(:bar)
|
60
|
+
#
|
61
|
+
class HashSlice < Base
|
62
|
+
include HashSubset
|
63
|
+
extend TargetRubyVersion
|
64
|
+
extend AutoCorrector
|
65
|
+
|
66
|
+
minimum_target_ruby_version 2.5
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def semantically_subset_method?(node)
|
71
|
+
semantically_slice_method?(node)
|
72
|
+
end
|
73
|
+
|
74
|
+
def preferred_method_name
|
75
|
+
'slice'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -203,17 +203,36 @@ module RuboCop
|
|
203
203
|
corrector.remove(range)
|
204
204
|
next if inserted_expression
|
205
205
|
|
206
|
-
if
|
207
|
-
corrector
|
206
|
+
if node.parent&.assignment?
|
207
|
+
correct_assignment(corrector, node, expression, insert_position)
|
208
208
|
else
|
209
|
-
corrector
|
209
|
+
correct_no_assignment(corrector, node, expression, insert_position)
|
210
210
|
end
|
211
|
+
|
211
212
|
inserted_expression = true
|
212
213
|
end
|
213
214
|
end
|
214
215
|
end
|
215
216
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
216
217
|
|
218
|
+
def correct_assignment(corrector, node, expression, insert_position)
|
219
|
+
if insert_position == :after_condition
|
220
|
+
assignment = node.parent.source_range.with(end_pos: node.source_range.begin_pos)
|
221
|
+
corrector.remove(assignment)
|
222
|
+
corrector.insert_after(node, "\n#{assignment.source}#{expression.source}")
|
223
|
+
else
|
224
|
+
corrector.insert_before(node.parent, "#{expression.source}\n")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def correct_no_assignment(corrector, node, expression, insert_position)
|
229
|
+
if insert_position == :after_condition
|
230
|
+
corrector.insert_after(node, "\n#{expression.source}")
|
231
|
+
else
|
232
|
+
corrector.insert_before(node, "#{expression.source}\n")
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
217
236
|
def last_child_of_parent?(node)
|
218
237
|
return true unless (parent = node.parent)
|
219
238
|
|
@@ -103,7 +103,7 @@ module RuboCop
|
|
103
103
|
|
104
104
|
def defined_argument_is_undefined?(if_node, defined_node)
|
105
105
|
defined_argument = defined_node.first_argument
|
106
|
-
return false unless defined_argument.
|
106
|
+
return false unless defined_argument.type?(:lvar, :send)
|
107
107
|
|
108
108
|
if_node.left_siblings.none? do |sibling|
|
109
109
|
sibling.respond_to?(:lvasgn_type?) && sibling.lvasgn_type? &&
|
@@ -112,11 +112,11 @@ module RuboCop
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def pattern_matching_nodes(condition)
|
115
|
-
if condition.
|
115
|
+
if condition.type?(:match_pattern, :match_pattern_p)
|
116
116
|
[condition]
|
117
117
|
else
|
118
118
|
condition.each_descendant.select do |node|
|
119
|
-
node.
|
119
|
+
node.type?(:match_pattern, :match_pattern_p)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
end
|
@@ -67,7 +67,7 @@ module RuboCop
|
|
67
67
|
|
68
68
|
# @!method if_with_boolean_literal_branches?(node)
|
69
69
|
def_node_matcher :if_with_boolean_literal_branches?, <<~PATTERN
|
70
|
-
(if #return_boolean_value?
|
70
|
+
(if #return_boolean_value? <true false>)
|
71
71
|
PATTERN
|
72
72
|
# @!method double_negative?(node)
|
73
73
|
def_node_matcher :double_negative?, '(send (send _ :!) :!)'
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
def message(node)
|
43
43
|
template = if require_newline?(node)
|
44
44
|
MSG_NEWLINE
|
45
|
-
elsif node.else_branch&.
|
45
|
+
elsif node.else_branch&.type?(:if, :begin) ||
|
46
46
|
use_masgn_or_block_in_branches?(node)
|
47
47
|
MSG_IF_ELSE
|
48
48
|
else
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
|
67
67
|
def use_masgn_or_block_in_branches?(node)
|
68
68
|
node.branches.compact.any? do |branch|
|
69
|
-
branch.
|
69
|
+
branch.type?(:masgn, :any_block)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def autocorrect(corrector, node)
|
71
|
-
if node.
|
71
|
+
if node.type?(:while_post, :until_post)
|
72
72
|
replace_begin_end_with_modifier(corrector, node)
|
73
73
|
elsif node.modifier_form?
|
74
74
|
replace_source(corrector, node.source_range, modifier_replacement(node))
|
@@ -60,18 +60,18 @@ module RuboCop
|
|
60
60
|
def_node_matcher :inverse_candidate?, <<~PATTERN
|
61
61
|
{
|
62
62
|
(send $(call $(...) $_ $...) :!)
|
63
|
-
(send (
|
63
|
+
(send (any_block $(call $(...) $_) $...) :!)
|
64
64
|
(send (begin $(call $(...) $_ $...)) :!)
|
65
65
|
}
|
66
66
|
PATTERN
|
67
67
|
|
68
68
|
# @!method inverse_block?(node)
|
69
69
|
def_node_matcher :inverse_block?, <<~PATTERN
|
70
|
-
(
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
(any_block $(call (...) $_) ... { $(call ... :!)
|
71
|
+
$(send (...) {:!= :!~} ...)
|
72
|
+
(begin ... $(call ... :!))
|
73
|
+
(begin ... $(send (...) {:!= :!~} ...))
|
74
|
+
})
|
75
75
|
PATTERN
|
76
76
|
|
77
77
|
def on_send(node)
|
@@ -57,7 +57,7 @@ module RuboCop
|
|
57
57
|
|
58
58
|
def append_newline_to_last_kwoptarg(arguments, corrector)
|
59
59
|
last_argument = arguments.last
|
60
|
-
return if last_argument.
|
60
|
+
return if last_argument.type?(:kwrestarg, :blockarg)
|
61
61
|
|
62
62
|
last_kwoptarg = arguments.reverse.find(&:kwoptarg_type?)
|
63
63
|
corrector.insert_after(last_kwoptarg, "\n") unless arguments.parent.block_type?
|
@@ -72,7 +72,7 @@ module RuboCop
|
|
72
72
|
def_node_matcher :each_block_with_push?, <<-PATTERN
|
73
73
|
[
|
74
74
|
^({begin kwbegin block} ...)
|
75
|
-
(
|
75
|
+
(any_block (send !{nil? self} :each) _
|
76
76
|
(send (lvar _) {:<< :push :append} #suitable_argument_node?))
|
77
77
|
]
|
78
78
|
PATTERN
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
40
40
|
# @!method map_to_h(node)
|
41
41
|
def_node_matcher :map_to_h, <<~PATTERN
|
42
42
|
{
|
43
|
-
$(call (
|
43
|
+
$(call (any_block $(call _ {:map :collect}) ...) :to_h)
|
44
44
|
$(call $(call _ {:map :collect} (block_pass sym)) :to_h)
|
45
45
|
}
|
46
46
|
PATTERN
|
@@ -33,8 +33,8 @@ module RuboCop
|
|
33
33
|
# @!method map_to_set?(node)
|
34
34
|
def_node_matcher :map_to_set?, <<~PATTERN
|
35
35
|
{
|
36
|
-
$(
|
37
|
-
$(
|
36
|
+
$(call (any_block $(call _ {:map :collect}) ...) :to_set)
|
37
|
+
$(call $(call _ {:map :collect} (block_pass sym)) :to_set)
|
38
38
|
}
|
39
39
|
PATTERN
|
40
40
|
|
@@ -49,6 +49,7 @@ module RuboCop
|
|
49
49
|
autocorrect(corrector, to_set_node, map_node)
|
50
50
|
end
|
51
51
|
end
|
52
|
+
alias on_csend on_send
|
52
53
|
|
53
54
|
private
|
54
55
|
|
@@ -111,9 +111,7 @@ module RuboCop
|
|
111
111
|
parent = node.parent&.block_type? ? node.parent.parent : node.parent
|
112
112
|
return false unless parent
|
113
113
|
|
114
|
-
parent.
|
115
|
-
parent.array_type? ||
|
116
|
-
parent.range_type? ||
|
114
|
+
parent.type?(:pair, :array, :range) ||
|
117
115
|
splat?(parent) ||
|
118
116
|
ternary_if?(parent)
|
119
117
|
end
|
@@ -128,14 +126,14 @@ module RuboCop
|
|
128
126
|
end
|
129
127
|
|
130
128
|
def call_in_optional_arguments?(node)
|
131
|
-
node.parent
|
129
|
+
node.parent&.type?(:optarg, :kwoptarg)
|
132
130
|
end
|
133
131
|
|
134
132
|
def call_in_single_line_inheritance?(node)
|
135
133
|
node.parent&.class_type? && node.parent.single_line?
|
136
134
|
end
|
137
135
|
|
138
|
-
# rubocop:disable Metrics/
|
136
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
139
137
|
def call_with_ambiguous_arguments?(node)
|
140
138
|
call_with_braced_block?(node) ||
|
141
139
|
call_in_argument_with_block?(node) ||
|
@@ -144,33 +142,32 @@ module RuboCop
|
|
144
142
|
hash_literal_in_arguments?(node) ||
|
145
143
|
ambiguous_range_argument?(node) ||
|
146
144
|
node.descendants.any? do |n|
|
147
|
-
n.
|
145
|
+
n.type?(:forwarded_args, :any_block) ||
|
148
146
|
ambiguous_literal?(n) || logical_operator?(n)
|
149
147
|
end
|
150
148
|
end
|
151
|
-
# rubocop:enable Metrics/
|
149
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
152
150
|
|
153
151
|
def call_with_braced_block?(node)
|
154
|
-
|
152
|
+
node.type?(:call, :super) && node.block_node&.braces?
|
155
153
|
end
|
156
154
|
|
157
155
|
def call_in_argument_with_block?(node)
|
158
156
|
parent = node.parent&.block_type? && node.parent.parent
|
159
157
|
return false unless parent
|
160
158
|
|
161
|
-
parent.
|
159
|
+
parent.type?(:call, :super, :yield)
|
162
160
|
end
|
163
161
|
|
164
162
|
def call_as_argument_or_chain?(node)
|
165
|
-
node.parent &&
|
166
|
-
(node.parent.call_type? || node.parent.super_type? || node.parent.yield_type?) &&
|
163
|
+
node.parent&.type?(:call, :super, :yield) &&
|
167
164
|
!assigned_before?(node.parent, node)
|
168
165
|
end
|
169
166
|
|
170
167
|
def call_in_match_pattern?(node)
|
171
168
|
return false unless (parent = node.parent)
|
172
169
|
|
173
|
-
parent.
|
170
|
+
parent.type?(:match_pattern, :match_pattern_p)
|
174
171
|
end
|
175
172
|
|
176
173
|
def hash_literal_in_arguments?(node)
|
@@ -205,7 +202,7 @@ module RuboCop
|
|
205
202
|
end
|
206
203
|
|
207
204
|
def splat?(node)
|
208
|
-
node.
|
205
|
+
node.type?(:splat, :kwsplat, :block_pass)
|
209
206
|
end
|
210
207
|
|
211
208
|
def ternary_if?(node)
|
@@ -45,6 +45,7 @@ module RuboCop
|
|
45
45
|
register_offense(node)
|
46
46
|
end
|
47
47
|
# rubocop:enable Metrics/CyclomaticComplexity
|
48
|
+
alias on_csend on_send
|
48
49
|
|
49
50
|
private
|
50
51
|
|
@@ -100,7 +101,7 @@ module RuboCop
|
|
100
101
|
# `obj.method ||= value` parses as (or-asgn (send ...) ...)
|
101
102
|
# which IS an `asgn_node`. Similarly, `obj.method += value` parses
|
102
103
|
# as (op-asgn (send ...) ...), which is also an `asgn_node`.
|
103
|
-
next if asgn_node.shorthand_asgn? && asgn_node.lhs.
|
104
|
+
next if asgn_node.shorthand_asgn? && asgn_node.lhs.call_type?
|
104
105
|
|
105
106
|
yield asgn_node
|
106
107
|
end
|
@@ -40,10 +40,8 @@ module RuboCop
|
|
40
40
|
def on_send(node)
|
41
41
|
return if ignored_node?(node)
|
42
42
|
|
43
|
-
receiver = node.receiver
|
44
|
-
|
45
|
-
return unless (receiver&.block_type? || receiver&.numblock_type?) &&
|
46
|
-
receiver.loc.end.is?('end')
|
43
|
+
return unless (receiver = node.receiver)
|
44
|
+
return unless receiver.any_block_type? && receiver.loc.end.is?('end')
|
47
45
|
|
48
46
|
range = range_between(receiver.loc.end.begin_pos, node.source_range.end_pos)
|
49
47
|
|
@@ -168,7 +168,7 @@ module RuboCop
|
|
168
168
|
|
169
169
|
def anonymous_arguments?(node)
|
170
170
|
return true if node.arguments.any? do |arg|
|
171
|
-
arg.
|
171
|
+
arg.type?(:forward_arg, :restarg, :kwrestarg)
|
172
172
|
end
|
173
173
|
return false unless (last_argument = node.last_argument)
|
174
174
|
|
@@ -31,7 +31,7 @@ module RuboCop
|
|
31
31
|
node.send_node.each_node(:send, :csend) do |send_node|
|
32
32
|
receiver = send_node.receiver
|
33
33
|
|
34
|
-
next unless
|
34
|
+
next unless receiver&.any_block_type? && receiver.multiline?
|
35
35
|
|
36
36
|
range = range_between(receiver.loc.end.begin_pos, node.send_node.source_range.end_pos)
|
37
37
|
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
# acceptable value other than none, it will suppress the offenses
|
20
20
|
# raised by this cop. It enforces frozen state.
|
21
21
|
#
|
22
|
-
# NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
|
22
|
+
# NOTE: `Regexp` and `Range` literals are frozen objects since Ruby 3.0.
|
23
23
|
#
|
24
24
|
# NOTE: From Ruby 3.0, interpolated strings are not frozen when
|
25
25
|
# `# frozen-string-literal: true` is used, so this cop enforces explicit
|
@@ -197,7 +197,7 @@ module RuboCop
|
|
197
197
|
end
|
198
198
|
|
199
199
|
def frozen_regexp_or_range_literals?(node)
|
200
|
-
target_ruby_version >= 3.0 &&
|
200
|
+
target_ruby_version >= 3.0 && node.type?(:regexp, :range)
|
201
201
|
end
|
202
202
|
|
203
203
|
def requires_parentheses?(node)
|
@@ -3,15 +3,15 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Flags uses of OpenStruct
|
6
|
+
# Flags uses of `OpenStruct`, as it is now officially discouraged
|
7
7
|
# to be used for performance, version compatibility, and potential security issues.
|
8
8
|
#
|
9
9
|
# @safety
|
10
|
-
#
|
11
10
|
# Note that this cop may flag false positives; for instance, the following legal
|
12
11
|
# use of a hand-rolled `OpenStruct` type would be considered an offense:
|
13
12
|
#
|
14
|
-
#
|
13
|
+
# [source,ruby]
|
14
|
+
# -----
|
15
15
|
# module MyNamespace
|
16
16
|
# class OpenStruct # not the OpenStruct we're looking for
|
17
17
|
# end
|
@@ -20,7 +20,7 @@ module RuboCop
|
|
20
20
|
# OpenStruct.new # resolves to MyNamespace::OpenStruct
|
21
21
|
# end
|
22
22
|
# end
|
23
|
-
#
|
23
|
+
# -----
|
24
24
|
#
|
25
25
|
# @example
|
26
26
|
#
|
@@ -61,7 +61,7 @@ module RuboCop
|
|
61
61
|
def custom_class_or_module_definition?(node)
|
62
62
|
parent = node.parent
|
63
63
|
|
64
|
-
|
64
|
+
parent.type?(:class, :module) && node.left_siblings.empty?
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|