rubocop 1.82.1 → 1.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/config/default.yml +44 -0
- data/lib/rubocop/cli/command/lsp.rb +1 -1
- data/lib/rubocop/cli.rb +2 -1
- data/lib/rubocop/comment_config.rb +1 -0
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +20 -2
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
- data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +12 -5
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +32 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +34 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +102 -9
- data/lib/rubocop/cop/layout/line_length.rb +5 -2
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +8 -8
- data/lib/rubocop/cop/lint/duplicate_methods.rb +57 -5
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
- data/lib/rubocop/cop/lint/to_json.rb +12 -16
- data/lib/rubocop/cop/lint/useless_or.rb +1 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
- data/lib/rubocop/cop/naming/predicate_prefix.rb +11 -11
- data/lib/rubocop/cop/offense.rb +2 -1
- data/lib/rubocop/cop/security/json_load.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -2
- data/lib/rubocop/cop/style/documentation.rb +6 -6
- data/lib/rubocop/cop/style/documentation_method.rb +8 -8
- data/lib/rubocop/cop/style/empty_class_definition.rb +144 -0
- data/lib/rubocop/cop/style/guard_clause.rb +7 -4
- data/lib/rubocop/cop/style/hash_lookup_method.rb +94 -0
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
- data/lib/rubocop/cop/style/lambda_call.rb +8 -8
- data/lib/rubocop/cop/style/module_member_existence_check.rb +56 -13
- data/lib/rubocop/cop/style/negative_array_index.rb +218 -0
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/team.rb +3 -3
- data/lib/rubocop/cop/variable_force/branch.rb +28 -4
- data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/tap_formatter.rb +5 -2
- data/lib/rubocop/remote_config.rb +5 -2
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/target_ruby.rb +3 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +4 -0
- metadata +9 -5
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
|
5
5
|
module Layout
|
|
6
6
|
# Checks for indentation that doesn't use the specified number of spaces.
|
|
7
7
|
# The indentation width can be configured using the `Width` setting. The default width is 2.
|
|
8
|
+
# The block body indentation for method chain blocks can be configured using the
|
|
9
|
+
# `EnforcedStyleAlignWith` setting.
|
|
8
10
|
#
|
|
9
11
|
# See also the `Layout/IndentationConsistency` cop which is the companion to this one.
|
|
10
12
|
#
|
|
@@ -41,7 +43,22 @@ module RuboCop
|
|
|
41
43
|
# end
|
|
42
44
|
# end
|
|
43
45
|
# end
|
|
46
|
+
#
|
|
47
|
+
# @example EnforcedStyleAlignWith: start_of_line (default)
|
|
48
|
+
# # good
|
|
49
|
+
# records.uniq { |el| el[:profile_id] }
|
|
50
|
+
# .map do |message|
|
|
51
|
+
# SomeJob.perform_later(message[:id])
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# @example EnforcedStyleAlignWith: relative_to_receiver
|
|
55
|
+
# # good
|
|
56
|
+
# records.uniq { |el| el[:profile_id] }
|
|
57
|
+
# .map do |message|
|
|
58
|
+
# SomeJob.perform_later(message[:id])
|
|
59
|
+
# end
|
|
44
60
|
class IndentationWidth < Base # rubocop:disable Metrics/ClassLength
|
|
61
|
+
include ConfigurableEnforcedStyle
|
|
45
62
|
include EndKeywordAlignment
|
|
46
63
|
include Alignment
|
|
47
64
|
include CheckAssignment
|
|
@@ -50,7 +67,7 @@ module RuboCop
|
|
|
50
67
|
extend AutoCorrector
|
|
51
68
|
|
|
52
69
|
MSG = 'Use %<configured_indentation_width>d (not %<indentation>d) ' \
|
|
53
|
-
'
|
|
70
|
+
'%<indentation_type>s for%<name>s indentation.'
|
|
54
71
|
|
|
55
72
|
# @!method access_modifier?(node)
|
|
56
73
|
def_node_matcher :access_modifier?, <<~PATTERN
|
|
@@ -83,12 +100,11 @@ module RuboCop
|
|
|
83
100
|
|
|
84
101
|
return unless begins_its_line?(end_loc)
|
|
85
102
|
|
|
86
|
-
|
|
87
|
-
# Otherwise, use the end keyword position as the base.
|
|
88
|
-
base_loc = dot_on_new_line?(node) ? node.send_node.loc.dot : end_loc
|
|
103
|
+
base_loc = block_body_indentation_base(node, end_loc)
|
|
89
104
|
check_indentation(base_loc, node.body)
|
|
90
105
|
|
|
91
106
|
return unless indented_internal_methods_style?
|
|
107
|
+
return unless contains_access_modifier?(node.body)
|
|
92
108
|
|
|
93
109
|
check_members(end_loc, [node.body])
|
|
94
110
|
end
|
|
@@ -148,7 +164,7 @@ module RuboCop
|
|
|
148
164
|
end
|
|
149
165
|
|
|
150
166
|
def on_case_match(case_match)
|
|
151
|
-
case_match.
|
|
167
|
+
case_match.in_pattern_branches.each do |in_pattern_node|
|
|
152
168
|
check_indentation(in_pattern_node.loc.keyword, in_pattern_node.body)
|
|
153
169
|
end
|
|
154
170
|
|
|
@@ -167,6 +183,8 @@ module RuboCop
|
|
|
167
183
|
private
|
|
168
184
|
|
|
169
185
|
def autocorrect(corrector, node)
|
|
186
|
+
return unless node
|
|
187
|
+
|
|
170
188
|
AlignmentCorrector.correct(corrector, processed_source, node, @column_delta)
|
|
171
189
|
end
|
|
172
190
|
|
|
@@ -175,7 +193,7 @@ module RuboCop
|
|
|
175
193
|
|
|
176
194
|
return unless members.any? && members.first.begin_type?
|
|
177
195
|
|
|
178
|
-
if
|
|
196
|
+
if indented_internal_methods_style?
|
|
179
197
|
check_members_for_indented_internal_methods_style(members)
|
|
180
198
|
else
|
|
181
199
|
check_members_for_normal_style(base, members)
|
|
@@ -304,10 +322,32 @@ module RuboCop
|
|
|
304
322
|
end
|
|
305
323
|
|
|
306
324
|
def message(configured_indentation_width, indentation, name)
|
|
325
|
+
if using_tabs?
|
|
326
|
+
message_for_tabs(configured_indentation_width, indentation, name)
|
|
327
|
+
else
|
|
328
|
+
message_for_spaces(configured_indentation_width, indentation, name)
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def message_for_tabs(configured_indentation_width, indentation, name)
|
|
333
|
+
configured_tabs = 1
|
|
334
|
+
actual_tabs = indentation / configured_indentation_width
|
|
335
|
+
|
|
336
|
+
format(
|
|
337
|
+
MSG,
|
|
338
|
+
configured_indentation_width: configured_tabs,
|
|
339
|
+
indentation: actual_tabs,
|
|
340
|
+
indentation_type: 'tabs',
|
|
341
|
+
name: name
|
|
342
|
+
)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def message_for_spaces(configured_indentation_width, indentation, name)
|
|
307
346
|
format(
|
|
308
347
|
MSG,
|
|
309
348
|
configured_indentation_width: configured_indentation_width,
|
|
310
349
|
indentation: indentation,
|
|
350
|
+
indentation_type: 'spaces',
|
|
311
351
|
name: name
|
|
312
352
|
)
|
|
313
353
|
end
|
|
@@ -363,7 +403,13 @@ module RuboCop
|
|
|
363
403
|
def offending_range(body_node, indentation)
|
|
364
404
|
expr = body_node.source_range
|
|
365
405
|
begin_pos = expr.begin_pos
|
|
366
|
-
|
|
406
|
+
|
|
407
|
+
ind = if using_tabs?
|
|
408
|
+
begin_pos - line_indentation(expr).length
|
|
409
|
+
else
|
|
410
|
+
begin_pos - indentation
|
|
411
|
+
end
|
|
412
|
+
|
|
367
413
|
pos = indentation >= 0 ? ind..begin_pos : begin_pos..ind
|
|
368
414
|
range_between(pos.begin, pos.end)
|
|
369
415
|
end
|
|
@@ -377,8 +423,47 @@ module RuboCop
|
|
|
377
423
|
starting_node.send_type? && starting_node.bare_access_modifier?
|
|
378
424
|
end
|
|
379
425
|
|
|
380
|
-
def
|
|
381
|
-
|
|
426
|
+
def contains_access_modifier?(body_node)
|
|
427
|
+
return false unless body_node.begin_type?
|
|
428
|
+
|
|
429
|
+
body_node.children.any? { |child| child.send_type? && child.bare_access_modifier? }
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
def indentation_style
|
|
433
|
+
config.for_cop('Layout/IndentationStyle')['EnforcedStyle'] || 'spaces'
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def using_tabs?
|
|
437
|
+
indentation_style == 'tabs'
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def column_offset_between(base_range, range)
|
|
441
|
+
return super unless using_tabs?
|
|
442
|
+
|
|
443
|
+
base_uses_tabs = line_uses_tabs?(base_range)
|
|
444
|
+
range_uses_tabs = line_uses_tabs?(range)
|
|
445
|
+
|
|
446
|
+
return super unless base_uses_tabs || range_uses_tabs
|
|
447
|
+
|
|
448
|
+
visual_column(base_range) - visual_column(range)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def line_indentation(range)
|
|
452
|
+
line = processed_source.lines[range.line - 1]
|
|
453
|
+
line[0...range.column]
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def line_uses_tabs?(range)
|
|
457
|
+
line_indentation(range).include?("\t")
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def visual_column(range)
|
|
461
|
+
indentation = line_indentation(range)
|
|
462
|
+
|
|
463
|
+
tab_count = indentation.count("\t")
|
|
464
|
+
space_count = indentation.count(' ')
|
|
465
|
+
|
|
466
|
+
(tab_count * configured_indentation_width) + space_count
|
|
382
467
|
end
|
|
383
468
|
|
|
384
469
|
def leftmost_modifier_of(node)
|
|
@@ -387,6 +472,14 @@ module RuboCop
|
|
|
387
472
|
leftmost_modifier_of(node.parent)
|
|
388
473
|
end
|
|
389
474
|
|
|
475
|
+
def block_body_indentation_base(node, end_loc)
|
|
476
|
+
if style != :relative_to_receiver || !dot_on_new_line?(node)
|
|
477
|
+
end_loc
|
|
478
|
+
else
|
|
479
|
+
node.send_node.loc.dot
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
390
483
|
def dot_on_new_line?(node)
|
|
391
484
|
send_node = node.send_node
|
|
392
485
|
return false unless send_node.loc?(:dot)
|
|
@@ -418,8 +418,11 @@ module RuboCop
|
|
|
418
418
|
# The maximum allowed length of a string value is:
|
|
419
419
|
# `Max` - end delimiter (quote) - continuation characters (space and slash)
|
|
420
420
|
max_length = max - 3
|
|
421
|
-
# If the string
|
|
422
|
-
|
|
421
|
+
# If the string is on the same line as its parent, offset by the column difference
|
|
422
|
+
# (Only apply when on same line to avoid negative offsets for multi-line dstr)
|
|
423
|
+
if same_line?(node, node.parent)
|
|
424
|
+
max_length -= column_offset_between(node.loc, node.parent.loc)
|
|
425
|
+
end
|
|
423
426
|
node.source[0...(max_length)]
|
|
424
427
|
end
|
|
425
428
|
end
|
|
@@ -27,67 +27,67 @@ module RuboCop
|
|
|
27
27
|
# line as the last element of the array.
|
|
28
28
|
#
|
|
29
29
|
# @example EnforcedStyle: symmetrical (default)
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
30
|
+
# # bad
|
|
31
|
+
# [ :a,
|
|
32
|
+
# :b
|
|
33
|
+
# ]
|
|
34
|
+
#
|
|
35
|
+
# # bad
|
|
36
|
+
# [
|
|
37
|
+
# :a,
|
|
38
|
+
# :b ]
|
|
39
|
+
#
|
|
40
|
+
# # good
|
|
41
|
+
# [ :a,
|
|
42
|
+
# :b ]
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# [
|
|
46
|
+
# :a,
|
|
47
|
+
# :b
|
|
48
|
+
# ]
|
|
49
49
|
#
|
|
50
50
|
# @example EnforcedStyle: new_line
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
51
|
+
# # bad
|
|
52
|
+
# [
|
|
53
|
+
# :a,
|
|
54
|
+
# :b ]
|
|
55
|
+
#
|
|
56
|
+
# # bad
|
|
57
|
+
# [ :a,
|
|
58
|
+
# :b ]
|
|
59
|
+
#
|
|
60
|
+
# # good
|
|
61
|
+
# [ :a,
|
|
62
|
+
# :b
|
|
63
|
+
# ]
|
|
64
|
+
#
|
|
65
|
+
# # good
|
|
66
|
+
# [
|
|
67
|
+
# :a,
|
|
68
|
+
# :b
|
|
69
|
+
# ]
|
|
70
70
|
#
|
|
71
71
|
# @example EnforcedStyle: same_line
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
72
|
+
# # bad
|
|
73
|
+
# [ :a,
|
|
74
|
+
# :b
|
|
75
|
+
# ]
|
|
76
|
+
#
|
|
77
|
+
# # bad
|
|
78
|
+
# [
|
|
79
|
+
# :a,
|
|
80
|
+
# :b
|
|
81
|
+
# ]
|
|
82
|
+
#
|
|
83
|
+
# # good
|
|
84
|
+
# [
|
|
85
|
+
# :a,
|
|
86
|
+
# :b ]
|
|
87
|
+
#
|
|
88
|
+
# # good
|
|
89
|
+
# [ :a,
|
|
90
|
+
# :b ]
|
|
91
91
|
class MultilineArrayBraceLayout < Base
|
|
92
92
|
include MultilineLiteralBraceLayout
|
|
93
93
|
extend AutoCorrector
|
|
@@ -28,66 +28,66 @@ module RuboCop
|
|
|
28
28
|
#
|
|
29
29
|
# @example EnforcedStyle: symmetrical (default)
|
|
30
30
|
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
31
|
+
# # bad
|
|
32
|
+
# { a: 1,
|
|
33
|
+
# b: 2
|
|
34
|
+
# }
|
|
35
|
+
# # bad
|
|
36
|
+
# {
|
|
37
|
+
# a: 1,
|
|
38
|
+
# b: 2 }
|
|
39
|
+
#
|
|
40
|
+
# # good
|
|
41
|
+
# { a: 1,
|
|
42
|
+
# b: 2 }
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# {
|
|
46
|
+
# a: 1,
|
|
47
|
+
# b: 2
|
|
48
|
+
# }
|
|
49
49
|
#
|
|
50
50
|
# @example EnforcedStyle: new_line
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
51
|
+
# # bad
|
|
52
|
+
# {
|
|
53
|
+
# a: 1,
|
|
54
|
+
# b: 2 }
|
|
55
|
+
#
|
|
56
|
+
# # bad
|
|
57
|
+
# { a: 1,
|
|
58
|
+
# b: 2 }
|
|
59
|
+
#
|
|
60
|
+
# # good
|
|
61
|
+
# { a: 1,
|
|
62
|
+
# b: 2
|
|
63
|
+
# }
|
|
64
|
+
#
|
|
65
|
+
# # good
|
|
66
|
+
# {
|
|
67
|
+
# a: 1,
|
|
68
|
+
# b: 2
|
|
69
|
+
# }
|
|
70
70
|
#
|
|
71
71
|
# @example EnforcedStyle: same_line
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
72
|
+
# # bad
|
|
73
|
+
# { a: 1,
|
|
74
|
+
# b: 2
|
|
75
|
+
# }
|
|
76
|
+
#
|
|
77
|
+
# # bad
|
|
78
|
+
# {
|
|
79
|
+
# a: 1,
|
|
80
|
+
# b: 2
|
|
81
|
+
# }
|
|
82
|
+
#
|
|
83
|
+
# # good
|
|
84
|
+
# {
|
|
85
|
+
# a: 1,
|
|
86
|
+
# b: 2 }
|
|
87
|
+
#
|
|
88
|
+
# # good
|
|
89
|
+
# { a: 1,
|
|
90
|
+
# b: 2 }
|
|
91
91
|
class MultilineHashBraceLayout < Base
|
|
92
92
|
include MultilineLiteralBraceLayout
|
|
93
93
|
extend AutoCorrector
|
|
@@ -7,18 +7,18 @@ module RuboCop
|
|
|
7
7
|
# parenthesis (`(`) in lambda literals.
|
|
8
8
|
#
|
|
9
9
|
# @example EnforcedStyle: require_no_space (default)
|
|
10
|
-
#
|
|
11
|
-
#
|
|
10
|
+
# # bad
|
|
11
|
+
# a = -> (x, y) { x + y }
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
13
|
+
# # good
|
|
14
|
+
# a = ->(x, y) { x + y }
|
|
15
15
|
#
|
|
16
16
|
# @example EnforcedStyle: require_space
|
|
17
|
-
#
|
|
18
|
-
#
|
|
17
|
+
# # bad
|
|
18
|
+
# a = ->(x, y) { x + y }
|
|
19
19
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
20
|
+
# # good
|
|
21
|
+
# a = -> (x, y) { x + y }
|
|
22
22
|
class SpaceInLambdaLiteral < Base
|
|
23
23
|
include ConfigurableEnforcedStyle
|
|
24
24
|
include RangeHelp
|
|
@@ -56,6 +56,27 @@ module RuboCop
|
|
|
56
56
|
# 1
|
|
57
57
|
# end
|
|
58
58
|
#
|
|
59
|
+
# # bad
|
|
60
|
+
# class MyClass
|
|
61
|
+
# extend Forwardable
|
|
62
|
+
#
|
|
63
|
+
# # or with: `def_instance_delegator`, `def_delegators`, `def_instance_delegators`
|
|
64
|
+
# def_delegator :delegation_target, :delegated_method_name
|
|
65
|
+
#
|
|
66
|
+
# def delegated_method_name
|
|
67
|
+
# end
|
|
68
|
+
# end
|
|
69
|
+
#
|
|
70
|
+
# # good
|
|
71
|
+
# class MyClass
|
|
72
|
+
# extend Forwardable
|
|
73
|
+
#
|
|
74
|
+
# def_delegator :delegation_target, :delegated_method_name
|
|
75
|
+
#
|
|
76
|
+
# def non_duplicated_delegated_method_name
|
|
77
|
+
# end
|
|
78
|
+
# end
|
|
79
|
+
#
|
|
59
80
|
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
|
60
81
|
#
|
|
61
82
|
# # good
|
|
@@ -97,10 +118,11 @@ module RuboCop
|
|
|
97
118
|
# delegate :foo, to: :bar
|
|
98
119
|
# end
|
|
99
120
|
#
|
|
100
|
-
class DuplicateMethods < Base
|
|
121
|
+
class DuplicateMethods < Base # rubocop:disable Metrics/ClassLength
|
|
101
122
|
MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
|
|
102
123
|
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
|
|
103
|
-
delegate
|
|
124
|
+
delegate def_delegator def_instance_delegator def_delegators
|
|
125
|
+
def_instance_delegators].freeze
|
|
104
126
|
|
|
105
127
|
def initialize(config = nil, options = nil)
|
|
106
128
|
super
|
|
@@ -154,23 +176,49 @@ module RuboCop
|
|
|
154
176
|
)
|
|
155
177
|
PATTERN
|
|
156
178
|
|
|
179
|
+
# @!method delegator?(node)
|
|
180
|
+
def_node_matcher :delegator?, <<~PATTERN
|
|
181
|
+
(send nil? {:def_delegator :def_instance_delegator}
|
|
182
|
+
{
|
|
183
|
+
{sym str} ({sym str} $_) |
|
|
184
|
+
{sym str} {sym str} ({sym str} $_)
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
PATTERN
|
|
188
|
+
|
|
189
|
+
# @!method delegators?(node)
|
|
190
|
+
def_node_matcher :delegators?, <<~PATTERN
|
|
191
|
+
(send nil? {:def_delegators :def_instance_delegators}
|
|
192
|
+
{sym str}
|
|
193
|
+
({sym str} $_)+
|
|
194
|
+
)
|
|
195
|
+
PATTERN
|
|
196
|
+
|
|
157
197
|
# @!method sym_name(node)
|
|
158
198
|
def_node_matcher :sym_name, '(sym $_name)'
|
|
159
199
|
|
|
160
|
-
def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
200
|
+
def on_send(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
161
201
|
name, original_name = alias_method?(node)
|
|
162
202
|
|
|
163
203
|
if name && original_name
|
|
164
204
|
return if name == original_name
|
|
165
|
-
return if
|
|
205
|
+
return if inside_condition?(node)
|
|
166
206
|
|
|
167
207
|
found_instance_method(node, name)
|
|
168
208
|
elsif (attr = node.attribute_accessor?)
|
|
169
209
|
on_attr(node, *attr)
|
|
170
210
|
elsif active_support_extensions_enabled? && (names = delegate_method?(node))
|
|
171
|
-
return if
|
|
211
|
+
return if inside_condition?(node)
|
|
172
212
|
|
|
173
213
|
on_delegate(node, names)
|
|
214
|
+
elsif (name = delegator?(node))
|
|
215
|
+
return if inside_condition?(node)
|
|
216
|
+
|
|
217
|
+
found_instance_method(node, name)
|
|
218
|
+
elsif (names = delegators?(node))
|
|
219
|
+
return if inside_condition?(node)
|
|
220
|
+
|
|
221
|
+
names.each { |name| found_instance_method(node, name) }
|
|
174
222
|
end
|
|
175
223
|
end
|
|
176
224
|
|
|
@@ -190,6 +238,10 @@ module RuboCop
|
|
|
190
238
|
found_method(node, "#{enclosing}.#{name}")
|
|
191
239
|
end
|
|
192
240
|
|
|
241
|
+
def inside_condition?(node)
|
|
242
|
+
node.ancestors.any?(&:if_type?)
|
|
243
|
+
end
|
|
244
|
+
|
|
193
245
|
def message_for_dup(node, method_name, key)
|
|
194
246
|
format(MSG, method: method_name, defined: source_location(@definitions[key]),
|
|
195
247
|
current: source_location(node))
|
|
@@ -77,7 +77,7 @@ module RuboCop
|
|
|
77
77
|
|
|
78
78
|
def on_case(node)
|
|
79
79
|
node.when_branches.each do |when_branch|
|
|
80
|
-
when_branch.
|
|
80
|
+
when_branch.conditions.each do |condition|
|
|
81
81
|
next if !float?(condition) || literal_safe?(condition)
|
|
82
82
|
|
|
83
83
|
add_offense(condition, message: MSG_CASE)
|
|
@@ -157,7 +157,7 @@ module RuboCop
|
|
|
157
157
|
|
|
158
158
|
check_case(case_match_node)
|
|
159
159
|
else
|
|
160
|
-
case_match_node.
|
|
160
|
+
case_match_node.in_pattern_branches.each do |in_pattern_node|
|
|
161
161
|
next unless in_pattern_node.condition.literal?
|
|
162
162
|
|
|
163
163
|
add_offense(in_pattern_node)
|
|
@@ -77,7 +77,7 @@ module RuboCop
|
|
|
77
77
|
PERCENT_CAPITAL_W = '%W'
|
|
78
78
|
PERCENT_I = '%i'
|
|
79
79
|
PERCENT_CAPITAL_I = '%I'
|
|
80
|
-
ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn].freeze
|
|
80
|
+
ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn casgn].freeze
|
|
81
81
|
|
|
82
82
|
# @!method array_new?(node)
|
|
83
83
|
def_node_matcher :array_new?, <<~PATTERN
|
|
@@ -26,7 +26,23 @@ module RuboCop
|
|
|
26
26
|
'and it may be unexpected.'
|
|
27
27
|
RESTRICT_ON_SEND = %i[new].freeze
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
# This is based on `Struct.instance_methods.sort` in Ruby 4.0.0.
|
|
30
|
+
STRUCT_METHOD_NAMES = %i[
|
|
31
|
+
! != !~ <=> == === [] []= __id__ __send__ all? any? chain chunk chunk_while class clone
|
|
32
|
+
collect collect_concat compact count cycle deconstruct deconstruct_keys
|
|
33
|
+
define_singleton_method detect dig display drop drop_while dup each each_cons each_entry
|
|
34
|
+
each_pair each_slice each_with_index each_with_object entries enum_for eql? equal? extend
|
|
35
|
+
filter filter_map find find_all find_index first flat_map freeze frozen? grep grep_v
|
|
36
|
+
group_by hash include? inject inspect instance_eval instance_exec instance_of?
|
|
37
|
+
instance_variable_defined? instance_variable_get instance_variable_set instance_variables
|
|
38
|
+
is_a? itself kind_of? lazy length map max max_by member? members method methods
|
|
39
|
+
min min_by minmax minmax_by nil? none? object_id one? partition private_methods
|
|
40
|
+
protected_methods public_method public_methods public_send reduce reject
|
|
41
|
+
remove_instance_variable respond_to? reverse_each select send singleton_class
|
|
42
|
+
singleton_method singleton_methods size slice_after slice_before slice_when sort sort_by
|
|
43
|
+
sum take take_while tally tap then to_a to_enum to_h to_s to_set uniq values values_at
|
|
44
|
+
yield_self zip
|
|
45
|
+
].freeze
|
|
30
46
|
STRUCT_MEMBER_NAME_TYPES = %i[sym str].freeze
|
|
31
47
|
|
|
32
48
|
# @!method struct_new(node)
|
|
@@ -5,27 +5,23 @@ module RuboCop
|
|
|
5
5
|
module Lint
|
|
6
6
|
# Checks to make sure `#to_json` includes an optional argument.
|
|
7
7
|
# When overriding `#to_json`, callers may invoke JSON
|
|
8
|
-
# generation via `JSON.generate(your_obj)`.
|
|
8
|
+
# generation via `JSON.generate(your_obj)`. Since `JSON#generate` allows
|
|
9
9
|
# for an optional argument, your method should too.
|
|
10
10
|
#
|
|
11
11
|
# @example
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# def to_json
|
|
17
|
-
# JSON.generate([x, y])
|
|
18
|
-
# end
|
|
12
|
+
# # bad - incorrect arity
|
|
13
|
+
# def to_json
|
|
14
|
+
# JSON.generate([x, y])
|
|
15
|
+
# end
|
|
19
16
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
17
|
+
# # good - preserving args
|
|
18
|
+
# def to_json(*args)
|
|
19
|
+
# JSON.generate([x, y], *args)
|
|
20
|
+
# end
|
|
24
21
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# end
|
|
22
|
+
# # good - discarding args
|
|
23
|
+
# def to_json(*_args)
|
|
24
|
+
# JSON.generate([x, y])
|
|
29
25
|
# end
|
|
30
26
|
#
|
|
31
27
|
class ToJSON < Base
|