rubocop 1.84.2 → 1.85.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 +83 -4
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli.rb +6 -3
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- 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/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 +1 -1
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +7 -6
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +32 -12
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- 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 +1 -1
- 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/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
- data/lib/rubocop/cop/style/alias.rb +4 -1
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +5 -2
- 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 +2 -2
- data/lib/rubocop/cop/style/case_equality.rb +4 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +10 -2
- data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
- data/lib/rubocop/cop/style/copyright.rb +1 -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 +21 -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 +63 -0
- data/lib/rubocop/cop/style/for.rb +3 -0
- data/lib/rubocop/cop/style/format_string_token.rb +29 -2
- data/lib/rubocop/cop/style/global_vars.rb +4 -1
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +21 -5
- 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_unless_modifier.rb +3 -3
- data/lib/rubocop/cop/style/inline_comment.rb +4 -1
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +3 -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/not.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +2 -1
- data/lib/rubocop/cop/style/one_class_per_file.rb +95 -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/reduce_to_hash.rb +169 -0
- data/lib/rubocop/cop/style/redundant_begin.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_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +6 -3
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +104 -0
- 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/semicolon.rb +2 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- 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/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +2 -2
- data/lib/rubocop/directive_comment.rb +2 -1
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/lsp/diagnostic.rb +1 -0
- data/lib/rubocop/mcp/server.rb +174 -0
- data/lib/rubocop/options.rb +10 -1
- data/lib/rubocop/server/cache.rb +5 -7
- data/lib/rubocop/target_ruby.rb +18 -12
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +14 -0
- metadata +34 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks unexpected overrides of the `Data` built-in methods
|
|
7
|
+
# via `Data.define`.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# # bad
|
|
11
|
+
# Bad = Data.define(:members, :clone, :to_s)
|
|
12
|
+
# b = Bad.new(members: [], clone: true, to_s: 'bad')
|
|
13
|
+
# b.members #=> [] (overriding `Data#members`)
|
|
14
|
+
# b.clone #=> true (overriding `Object#clone`)
|
|
15
|
+
# b.to_s #=> "bad" (overriding `Data#to_s`)
|
|
16
|
+
#
|
|
17
|
+
# # good
|
|
18
|
+
# Good = Data.define(:id, :name)
|
|
19
|
+
# g = Good.new(id: 1, name: "foo")
|
|
20
|
+
# g.members #=> [:id, :name]
|
|
21
|
+
# g.clone #=> #<data Good id=1, name="foo">
|
|
22
|
+
#
|
|
23
|
+
class DataDefineOverride < Base
|
|
24
|
+
MSG = '`%<member_name>s` member overrides `Data#%<method_name>s` and it may be unexpected.'
|
|
25
|
+
RESTRICT_ON_SEND = %i[define].freeze
|
|
26
|
+
|
|
27
|
+
# This is based on `Data.define.instance_methods.sort` in Ruby 4.0.0.
|
|
28
|
+
DATA_METHOD_NAMES = %i[
|
|
29
|
+
! != !~ <=> == === __id__ __send__ class clone deconstruct deconstruct_keys
|
|
30
|
+
define_singleton_method display dup enum_for eql? equal? extend freeze frozen? hash
|
|
31
|
+
inspect instance_eval instance_exec instance_of? instance_variable_defined?
|
|
32
|
+
instance_variable_get instance_variable_set instance_variables is_a? itself kind_of?
|
|
33
|
+
members method methods nil? object_id private_methods protected_methods
|
|
34
|
+
public_method public_methods public_send remove_instance_variable respond_to? send
|
|
35
|
+
singleton_class singleton_method singleton_methods tap then to_enum to_h to_s with
|
|
36
|
+
yield_self
|
|
37
|
+
].freeze
|
|
38
|
+
MEMBER_NAME_TYPES = %i[sym str].freeze
|
|
39
|
+
|
|
40
|
+
# @!method data_define(node)
|
|
41
|
+
def_node_matcher :data_define, <<~PATTERN
|
|
42
|
+
(send
|
|
43
|
+
(const {nil? cbase} :Data) :define ...)
|
|
44
|
+
PATTERN
|
|
45
|
+
|
|
46
|
+
def on_send(node)
|
|
47
|
+
return unless data_define(node)
|
|
48
|
+
|
|
49
|
+
node.arguments.each do |arg|
|
|
50
|
+
next unless MEMBER_NAME_TYPES.include?(arg.type)
|
|
51
|
+
|
|
52
|
+
member_name = arg.value
|
|
53
|
+
|
|
54
|
+
next unless DATA_METHOD_NAMES.include?(member_name.to_sym)
|
|
55
|
+
|
|
56
|
+
message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s)
|
|
57
|
+
add_offense(arg, message: message)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
|
63
63
|
class EmptyBlock < Base
|
|
64
64
|
MSG = 'Empty block detected.'
|
|
65
65
|
|
|
66
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
66
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
67
67
|
return if node.body
|
|
68
68
|
return if allow_empty_lambdas? && node.lambda_or_proc?
|
|
69
69
|
return if cop_config['AllowComments'] && allow_comment?(node)
|
|
@@ -54,9 +54,14 @@ module RuboCop
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def valid_syntax?(node)
|
|
57
|
-
double_quoted_string = node.source.
|
|
57
|
+
double_quoted_string = if node.source.include?('"')
|
|
58
|
+
node.source.sub(/\A'/, '%{').sub(/'\z/, '}')
|
|
59
|
+
else
|
|
60
|
+
node.source.gsub(/\A'|'\z/, '"')
|
|
61
|
+
end
|
|
58
62
|
|
|
59
|
-
parse(double_quoted_string)
|
|
63
|
+
processed_source = parse(double_quoted_string)
|
|
64
|
+
processed_source.valid_syntax? && processed_source.ast.dstr_type?
|
|
60
65
|
end
|
|
61
66
|
end
|
|
62
67
|
end
|
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
alias on_numblock on_block
|
|
34
|
+
alias on_itblock on_block
|
|
34
35
|
|
|
35
36
|
private
|
|
36
37
|
|
|
@@ -39,6 +40,7 @@ module RuboCop
|
|
|
39
40
|
{
|
|
40
41
|
(block (call _recv {:reduce :inject} !sym) _blockargs $(begin ...))
|
|
41
42
|
(numblock (call _recv {:reduce :inject} !sym) _argscount $(begin ...))
|
|
43
|
+
(itblock (call _recv {:reduce :inject} !sym) _argscount $(begin ...))
|
|
42
44
|
}
|
|
43
45
|
PATTERN
|
|
44
46
|
|
|
@@ -65,7 +65,9 @@ module RuboCop
|
|
|
65
65
|
|
|
66
66
|
maximum_target_ruby_version 2.7
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
# NOTE: itblock is not handled because this cop is limited to Ruby <= 2.7
|
|
69
|
+
# via `maximum_target_ruby_version`, so itblock nodes (Ruby 3.4+) are never encountered.
|
|
70
|
+
def on_block(node) # rubocop:disable InternalAffairs/ItblockHandler
|
|
69
71
|
return unless node.body
|
|
70
72
|
return unless unsorted_dir_loop?(node.send_node)
|
|
71
73
|
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# The Lint/RedundantCopEnableDirective and Lint/RedundantCopDisableDirective
|
|
4
|
-
# cops need to be disabled so as to be able to provide a (bad) example of an
|
|
5
|
-
# unneeded enable.
|
|
6
|
-
|
|
7
|
-
# rubocop:disable Lint/RedundantCopEnableDirective
|
|
8
|
-
# rubocop:disable Lint/RedundantCopDisableDirective
|
|
9
3
|
module RuboCop
|
|
10
4
|
module Cop
|
|
11
5
|
module Lint
|
|
@@ -130,6 +124,3 @@ module RuboCop
|
|
|
130
124
|
end
|
|
131
125
|
end
|
|
132
126
|
end
|
|
133
|
-
|
|
134
|
-
# rubocop:enable Lint/RedundantCopDisableDirective
|
|
135
|
-
# rubocop:enable Lint/RedundantCopEnableDirective
|
|
@@ -71,8 +71,9 @@ module RuboCop
|
|
|
71
71
|
# node = node.parent
|
|
72
72
|
# end
|
|
73
73
|
#
|
|
74
|
-
# # good - without `&.` this
|
|
74
|
+
# # good - without `&.` this changes the return value for `nil`
|
|
75
75
|
# foo&.respond_to?(:to_a)
|
|
76
|
+
# foo&.respond_to?(:class)
|
|
76
77
|
#
|
|
77
78
|
# # bad - for `nil`s conversion methods return default values for the type
|
|
78
79
|
# foo&.to_h || {}
|
|
@@ -151,15 +152,15 @@ module RuboCop
|
|
|
151
152
|
MSG_NON_NIL = 'Redundant safe navigation on non-nil receiver (detected by analyzing ' \
|
|
152
153
|
'previous code/method invocations).'
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
NIL_METHODS = nil.methods.to_set.freeze
|
|
155
156
|
|
|
156
157
|
SNAKE_CASE = /\A[[:digit:][:upper:]_]+\z/.freeze
|
|
157
158
|
|
|
158
159
|
GUARANTEED_INSTANCE_METHODS = %i[to_s to_i to_f to_a to_h].freeze
|
|
159
160
|
|
|
160
|
-
# @!method
|
|
161
|
-
def_node_matcher :
|
|
162
|
-
(csend _ :respond_to? (sym %
|
|
161
|
+
# @!method respond_to_nil_method?(node)
|
|
162
|
+
def_node_matcher :respond_to_nil_method?, <<~PATTERN
|
|
163
|
+
(csend _ :respond_to? (sym %NIL_METHODS))
|
|
163
164
|
PATTERN
|
|
164
165
|
|
|
165
166
|
# @!method conversion_with_default?(node)
|
|
@@ -189,7 +190,7 @@ module RuboCop
|
|
|
189
190
|
|
|
190
191
|
unless assume_receiver_instance_exists?(node.receiver)
|
|
191
192
|
return if !guaranteed_instance?(node.receiver) && !check?(node)
|
|
192
|
-
return if
|
|
193
|
+
return if respond_to_nil_method?(node)
|
|
193
194
|
end
|
|
194
195
|
|
|
195
196
|
add_offense(range) { |corrector| corrector.replace(range, '.') }
|
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Lint
|
|
6
|
-
#
|
|
6
|
+
# Checks that if safe navigation is used in an `&&` or `||` condition,
|
|
7
7
|
# consistent and appropriate safe navigation, without excess or deficiency,
|
|
8
8
|
# is used for all method calls on the same object.
|
|
9
9
|
#
|
|
10
|
+
# @safety
|
|
11
|
+
# Autocorrection is unsafe because if the receiver is not a local variable
|
|
12
|
+
# but a method call, it may not be idempotent. For example, replacing
|
|
13
|
+
# `foo&.bar` with `foo.bar` could raise `NoMethodError` if `foo` returns
|
|
14
|
+
# `nil` on a subsequent call.
|
|
15
|
+
#
|
|
10
16
|
# @example
|
|
11
17
|
# # bad
|
|
12
18
|
# foo&.bar && foo&.baz
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks for unreachable `in` pattern branches in `case...in` statements.
|
|
7
|
+
#
|
|
8
|
+
# An `in` branch is unreachable when a previous branch uses an unguarded
|
|
9
|
+
# catch-all pattern that matches any value unconditionally. Any `in` branches
|
|
10
|
+
# (and `else`) that follow such a catch-all are dead code.
|
|
11
|
+
#
|
|
12
|
+
# A catch-all pattern is one of:
|
|
13
|
+
#
|
|
14
|
+
# * A bare variable capture (`in x`)
|
|
15
|
+
# * An underscore (`in _`)
|
|
16
|
+
# * A pattern alias where the left side is a catch-all (`in _ => y`)
|
|
17
|
+
# * An alternation pattern where at least one alternative is a catch-all
|
|
18
|
+
# (`in _ | Integer`)
|
|
19
|
+
#
|
|
20
|
+
# NOTE: A catch-all pattern with a guard clause (e.g., `in _ if condition`)
|
|
21
|
+
# does NOT make subsequent branches unreachable because the guard might
|
|
22
|
+
# not be satisfied.
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
#
|
|
26
|
+
# # bad
|
|
27
|
+
# case value
|
|
28
|
+
# in Integer
|
|
29
|
+
# handle_integer
|
|
30
|
+
# in x
|
|
31
|
+
# handle_other
|
|
32
|
+
# in String
|
|
33
|
+
# handle_string
|
|
34
|
+
# else
|
|
35
|
+
# handle_else
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# # good
|
|
39
|
+
# case value
|
|
40
|
+
# in Integer
|
|
41
|
+
# handle_integer
|
|
42
|
+
# in String
|
|
43
|
+
# handle_string
|
|
44
|
+
# in x
|
|
45
|
+
# handle_other
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# # bad - else is unreachable after catch-all
|
|
49
|
+
# case value
|
|
50
|
+
# in Integer
|
|
51
|
+
# handle_integer
|
|
52
|
+
# in _
|
|
53
|
+
# handle_other
|
|
54
|
+
# else
|
|
55
|
+
# handle_else
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# # good - guard clause means catch-all might not match
|
|
59
|
+
# case value
|
|
60
|
+
# in x if x.positive?
|
|
61
|
+
# handle_positive
|
|
62
|
+
# in Integer
|
|
63
|
+
# handle_integer
|
|
64
|
+
# else
|
|
65
|
+
# handle_other
|
|
66
|
+
# end
|
|
67
|
+
#
|
|
68
|
+
class UnreachablePatternBranch < Base
|
|
69
|
+
extend TargetRubyVersion
|
|
70
|
+
|
|
71
|
+
MSG = 'Unreachable `in` pattern branch detected.'
|
|
72
|
+
MSG_ELSE = 'Unreachable `else` branch detected.'
|
|
73
|
+
|
|
74
|
+
minimum_target_ruby_version 2.7
|
|
75
|
+
|
|
76
|
+
def on_case_match(case_node)
|
|
77
|
+
catch_all_found = false
|
|
78
|
+
|
|
79
|
+
case_node.in_pattern_branches.each do |in_pattern_node|
|
|
80
|
+
if catch_all_found
|
|
81
|
+
add_offense(in_pattern_node)
|
|
82
|
+
next
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
pattern = in_pattern_node.pattern
|
|
86
|
+
guard = in_pattern_node.children[1]
|
|
87
|
+
|
|
88
|
+
catch_all_found = true if catch_all_pattern?(pattern) && guard.nil?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
return unless catch_all_found && case_node.else?
|
|
92
|
+
|
|
93
|
+
add_offense(case_node.loc.else, message: MSG_ELSE)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def catch_all_pattern?(pattern)
|
|
99
|
+
case pattern.type
|
|
100
|
+
when :match_var
|
|
101
|
+
true
|
|
102
|
+
when :match_as, :begin
|
|
103
|
+
catch_all_pattern?(pattern.children[0])
|
|
104
|
+
when :match_alt
|
|
105
|
+
pattern.children.any? { |child| catch_all_pattern?(child) }
|
|
106
|
+
else
|
|
107
|
+
false
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -213,7 +213,7 @@ module RuboCop
|
|
|
213
213
|
end
|
|
214
214
|
|
|
215
215
|
def remove_local_variable_assignment_part(corrector, node)
|
|
216
|
-
corrector.
|
|
216
|
+
corrector.remove(node.loc.name.begin.join(node.expression.source_range.begin))
|
|
217
217
|
end
|
|
218
218
|
|
|
219
219
|
def variable_in_loop_condition?(assignment_node, variable)
|
|
@@ -87,8 +87,9 @@ module RuboCop
|
|
|
87
87
|
def on_block(node)
|
|
88
88
|
return unless node.body && !node.body.begin_type?
|
|
89
89
|
return unless in_void_context?(node.body)
|
|
90
|
+
return if node.method?(:each)
|
|
90
91
|
|
|
91
|
-
check_void_op(node.body)
|
|
92
|
+
check_void_op(node.body)
|
|
92
93
|
check_expression(node.body)
|
|
93
94
|
end
|
|
94
95
|
alias on_numblock on_block
|
|
@@ -107,22 +108,23 @@ module RuboCop
|
|
|
107
108
|
|
|
108
109
|
def check_begin(node)
|
|
109
110
|
expressions = *node
|
|
110
|
-
|
|
111
|
+
inside_each_block = node.each_ancestor(:any_block).first&.method?(:each)
|
|
112
|
+
expressions.pop if !in_void_context?(node) || inside_each_block
|
|
111
113
|
expressions.each do |expr|
|
|
112
|
-
check_void_op(expr)
|
|
113
|
-
block_node = node.each_ancestor(:any_block).first
|
|
114
|
-
|
|
115
|
-
block_node&.method?(:each)
|
|
116
|
-
end
|
|
117
|
-
|
|
114
|
+
check_void_op(expr) { inside_each_block }
|
|
118
115
|
check_expression(expr)
|
|
119
116
|
end
|
|
120
117
|
end
|
|
121
118
|
|
|
122
119
|
def check_expression(expr)
|
|
123
|
-
|
|
124
|
-
return
|
|
120
|
+
return check_if_expression(expr) if expr.if_type?
|
|
121
|
+
return check_case_expression(expr) if expr.case_type?
|
|
122
|
+
return check_case_match_expression(expr) if expr.case_match_type?
|
|
123
|
+
|
|
124
|
+
check_void_expression_nodes(expr)
|
|
125
|
+
end
|
|
125
126
|
|
|
127
|
+
def check_void_expression_nodes(expr)
|
|
126
128
|
check_literal(expr)
|
|
127
129
|
check_var(expr)
|
|
128
130
|
check_self(expr)
|
|
@@ -132,6 +134,22 @@ module RuboCop
|
|
|
132
134
|
check_nonmutating(expr)
|
|
133
135
|
end
|
|
134
136
|
|
|
137
|
+
def check_if_expression(if_node)
|
|
138
|
+
check_void_expression_nodes(if_node.body) if if_node.body
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def check_case_expression(case_node)
|
|
142
|
+
case_node.each_when { |when_node| check_expression(when_node.body) if when_node.body }
|
|
143
|
+
check_expression(case_node.else_branch) if case_node.else_branch
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def check_case_match_expression(case_node)
|
|
147
|
+
case_node.each_in_pattern do |in_pattern_node|
|
|
148
|
+
check_expression(in_pattern_node.body) if in_pattern_node.body
|
|
149
|
+
end
|
|
150
|
+
check_expression(case_node.else_branch) if case_node.else_branch
|
|
151
|
+
end
|
|
152
|
+
|
|
135
153
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
136
154
|
def check_void_op(node, &block)
|
|
137
155
|
node = node.children.first while node&.begin_type?
|
|
@@ -168,7 +186,9 @@ module RuboCop
|
|
|
168
186
|
end
|
|
169
187
|
|
|
170
188
|
def check_literal(node)
|
|
171
|
-
|
|
189
|
+
if !entirely_literal?(node) || node.xstr_type? || node.range_type? || node.nil_type?
|
|
190
|
+
return
|
|
191
|
+
end
|
|
172
192
|
|
|
173
193
|
add_offense(node, message: format(LIT_MSG, lit: node.source)) do |corrector|
|
|
174
194
|
autocorrect_void_expression(corrector, node)
|
|
@@ -238,7 +258,7 @@ module RuboCop
|
|
|
238
258
|
end
|
|
239
259
|
|
|
240
260
|
def autocorrect_void_expression(corrector, node)
|
|
241
|
-
return if node.parent.
|
|
261
|
+
return if node.parent.type?(:if, :case, :when, :case_match, :in_pattern)
|
|
242
262
|
return if (def_node = node.each_ancestor(:any_def).first) && def_node.assignment_method?
|
|
243
263
|
|
|
244
264
|
corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
|
|
@@ -4,6 +4,8 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Metrics
|
|
6
6
|
# Checks for excessive nesting of conditional and looping constructs.
|
|
7
|
+
# Deeply nested code is harder to read, understand, and maintain.
|
|
8
|
+
# Extracting nested logic into methods improves clarity.
|
|
7
9
|
#
|
|
8
10
|
# You can configure if blocks are considered using the `CountBlocks` and `CountModifierForms`
|
|
9
11
|
# options. When both are set to `false` (the default) blocks and modifier forms are not
|
|
@@ -11,6 +13,27 @@ module RuboCop
|
|
|
11
13
|
# calculation as well.
|
|
12
14
|
#
|
|
13
15
|
# The maximum level of nesting allowed is configurable.
|
|
16
|
+
#
|
|
17
|
+
# @example Max: 3 (default)
|
|
18
|
+
# # bad
|
|
19
|
+
# if condition1
|
|
20
|
+
# if condition2
|
|
21
|
+
# if condition3
|
|
22
|
+
# if condition4
|
|
23
|
+
# do_something
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# # good
|
|
30
|
+
# if condition1
|
|
31
|
+
# if condition2
|
|
32
|
+
# if condition3
|
|
33
|
+
# do_something
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
# end
|
|
14
37
|
class BlockNesting < Base
|
|
15
38
|
NESTING_BLOCKS = %i[case case_match if while while_post until until_post for resbody].freeze
|
|
16
39
|
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Lint/RedundantCopDisableDirective needs to be disabled so as
|
|
4
|
+
# to be able to provide examples of rubocop:disable comments.
|
|
5
|
+
# rubocop:disable Lint/RedundantCopDisableDirective
|
|
3
6
|
module RuboCop
|
|
4
7
|
module Cop
|
|
5
8
|
module Migration
|
|
6
|
-
#
|
|
9
|
+
# Checks that cop names in rubocop:disable comments are given with
|
|
7
10
|
# department name.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# # bad
|
|
14
|
+
# # rubocop:disable AbcSize
|
|
15
|
+
#
|
|
16
|
+
# # good
|
|
17
|
+
# # rubocop:disable Metrics/AbcSize
|
|
8
18
|
class DepartmentName < Base
|
|
9
19
|
include RangeHelp
|
|
10
20
|
extend AutoCorrector
|
|
@@ -79,3 +89,4 @@ module RuboCop
|
|
|
79
89
|
end
|
|
80
90
|
end
|
|
81
91
|
end
|
|
92
|
+
# rubocop:enable Lint/RedundantCopDisableDirective
|
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
|
40
40
|
def safe_to_split?(node)
|
|
41
41
|
node.each_descendant(:if, :case, :kwbegin, :any_def).none? &&
|
|
42
42
|
node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
|
|
43
|
-
node.each_descendant(:begin, :sym).none?
|
|
43
|
+
node.each_descendant(:begin, :sym).none?(&:multiline?)
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module HashTransformMethod
|
|
6
|
+
# Internal helper class to hold autocorrect data
|
|
7
|
+
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
|
8
|
+
def self.from_each_with_object(node, match)
|
|
9
|
+
new(match, node, 0, 0)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.from_hash_brackets_map(node, match)
|
|
13
|
+
new(match, node.children.last, 'Hash['.length, ']'.length)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.from_map_to_h(node, match)
|
|
17
|
+
if node.parent&.block_type? && node.parent.send_node == node
|
|
18
|
+
strip_trailing_chars = 0
|
|
19
|
+
else
|
|
20
|
+
map_range = node.children.first.source_range
|
|
21
|
+
node_range = node.source_range
|
|
22
|
+
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
new(match, node.children.first, 0, strip_trailing_chars)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.from_to_h(node, match)
|
|
29
|
+
new(match, node, 0, 0)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def strip_prefix_and_suffix(node, corrector)
|
|
33
|
+
expression = node.source_range
|
|
34
|
+
corrector.remove_leading(expression, leading)
|
|
35
|
+
corrector.remove_trailing(expression, trailing)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def set_new_method_name(new_method_name, corrector)
|
|
39
|
+
range = block_node.send_node.loc.selector
|
|
40
|
+
if (send_end = block_node.send_node.loc.end)
|
|
41
|
+
# If there are arguments (only true in the `each_with_object`
|
|
42
|
+
# case)
|
|
43
|
+
range = range.begin.join(send_end)
|
|
44
|
+
end
|
|
45
|
+
corrector.replace(range, new_method_name)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def set_new_arg_name(transformed_argname, corrector)
|
|
49
|
+
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def set_new_body_expression(transforming_body_expr, corrector)
|
|
53
|
+
body_source = transforming_body_expr.source
|
|
54
|
+
if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
|
55
|
+
body_source = "{ #{body_source} }"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
corrector.replace(block_node.body, body_source)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'hash_transform_method/autocorrection'
|
|
4
|
+
|
|
3
5
|
module RuboCop
|
|
4
6
|
module Cop
|
|
5
7
|
# Common functionality for Style/HashTransformKeys and
|
|
@@ -27,68 +29,16 @@ module RuboCop
|
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
new(match, node.children.last, 'Hash['.length, ']'.length)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def self.from_map_to_h(node, match)
|
|
41
|
-
if node.parent&.block_type? && node.parent.send_node == node
|
|
42
|
-
strip_trailing_chars = 0
|
|
43
|
-
else
|
|
44
|
-
map_range = node.children.first.source_range
|
|
45
|
-
node_range = node.source_range
|
|
46
|
-
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
new(match, node.children.first, 0, strip_trailing_chars)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def self.from_to_h(node, match)
|
|
53
|
-
new(match, node, 0, 0)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def strip_prefix_and_suffix(node, corrector)
|
|
57
|
-
expression = node.source_range
|
|
58
|
-
corrector.remove_leading(expression, leading)
|
|
59
|
-
corrector.remove_trailing(expression, trailing)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def set_new_method_name(new_method_name, corrector)
|
|
63
|
-
range = block_node.send_node.loc.selector
|
|
64
|
-
if (send_end = block_node.send_node.loc.end)
|
|
65
|
-
# If there are arguments (only true in the `each_with_object`
|
|
66
|
-
# case)
|
|
67
|
-
range = range.begin.join(send_end)
|
|
68
|
-
end
|
|
69
|
-
corrector.replace(range, new_method_name)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def set_new_arg_name(transformed_argname, corrector)
|
|
73
|
-
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def set_new_body_expression(transforming_body_expr, corrector)
|
|
77
|
-
body_source = transforming_body_expr.source
|
|
78
|
-
if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
|
79
|
-
body_source = "{ #{body_source} }"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
corrector.replace(block_node.body, body_source)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# @!method array_receiver?(node)
|
|
87
|
-
def_node_matcher :array_receiver?, <<~PATTERN
|
|
88
|
-
{(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)}
|
|
32
|
+
# @!method hash_receiver?(node)
|
|
33
|
+
def_node_matcher :hash_receiver?, <<~PATTERN
|
|
34
|
+
{(hash ...)
|
|
35
|
+
(send _ {:to_h :to_hash :merge :merge! :update :invert :except :tally} ...)
|
|
36
|
+
(block (send _ {:group_by :to_h :tally :transform_keys :transform_keys!
|
|
37
|
+
:transform_values :transform_values!}) ...)
|
|
38
|
+
(block (send _ :each_with_object (hash)) ...)}
|
|
89
39
|
PATTERN
|
|
90
40
|
|
|
91
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
41
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
92
42
|
on_bad_each_with_object(node) do |*match|
|
|
93
43
|
handle_possible_offense(node, match, 'each_with_object')
|
|
94
44
|
end
|
|
@@ -38,7 +38,7 @@ module RuboCop
|
|
|
38
38
|
class BlockParameterName < Base
|
|
39
39
|
include UncommunicativeName
|
|
40
40
|
|
|
41
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
41
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
|
|
42
42
|
return unless node.arguments?
|
|
43
43
|
|
|
44
44
|
check(node, node.arguments)
|