rubocop 1.39.0 → 1.41.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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +65 -9
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/comment_config.rb +5 -0
  6. data/lib/rubocop/config.rb +33 -9
  7. data/lib/rubocop/config_loader.rb +14 -5
  8. data/lib/rubocop/config_loader_resolver.rb +1 -1
  9. data/lib/rubocop/config_validator.rb +1 -1
  10. data/lib/rubocop/cop/badge.rb +9 -4
  11. data/lib/rubocop/cop/base.rb +26 -17
  12. data/lib/rubocop/cop/commissioner.rb +8 -3
  13. data/lib/rubocop/cop/cop.rb +1 -1
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  15. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  16. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  17. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  18. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  19. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  20. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  21. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  22. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  23. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  24. data/lib/rubocop/cop/layout/indentation_style.rb +3 -1
  25. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  26. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  27. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  28. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  29. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  30. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  31. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  32. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  33. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  34. data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -2
  35. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  36. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  37. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  38. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  39. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  40. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  41. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  42. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  43. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  44. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  45. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  46. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  47. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +13 -3
  48. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  49. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -12
  50. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  51. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  52. data/lib/rubocop/cop/lint/void.rb +6 -6
  53. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  54. data/lib/rubocop/cop/metrics/class_length.rb +10 -5
  55. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  56. data/lib/rubocop/cop/metrics/module_length.rb +10 -5
  57. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
  58. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  59. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  60. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  61. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  62. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  63. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +28 -5
  64. data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
  65. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  66. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  67. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  68. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  69. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  70. data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
  71. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  72. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  73. data/lib/rubocop/cop/registry.rb +29 -14
  74. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  75. data/lib/rubocop/cop/style/concat_array_literals.rb +66 -0
  76. data/lib/rubocop/cop/style/documentation.rb +1 -1
  77. data/lib/rubocop/cop/style/guard_clause.rb +36 -5
  78. data/lib/rubocop/cop/style/if_with_semicolon.rb +4 -4
  79. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  80. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  81. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  82. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  83. data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
  84. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
  85. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  86. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  87. data/lib/rubocop/cop/style/require_order.rb +140 -0
  88. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  89. data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
  90. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  91. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  92. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  93. data/lib/rubocop/cop/team.rb +1 -1
  94. data/lib/rubocop/cop/util.rb +32 -5
  95. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  96. data/lib/rubocop/cop/variable_force.rb +20 -29
  97. data/lib/rubocop/cops_documentation_generator.rb +22 -3
  98. data/lib/rubocop/directive_comment.rb +1 -1
  99. data/lib/rubocop/file_patterns.rb +43 -0
  100. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  101. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  102. data/lib/rubocop/formatter.rb +3 -1
  103. data/lib/rubocop/options.rb +8 -0
  104. data/lib/rubocop/path_util.rb +34 -16
  105. data/lib/rubocop/result_cache.rb +1 -1
  106. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  107. data/lib/rubocop/rspec/support.rb +2 -2
  108. data/lib/rubocop/server/core.rb +1 -1
  109. data/lib/rubocop/target_finder.rb +1 -1
  110. data/lib/rubocop/target_ruby.rb +1 -1
  111. data/lib/rubocop/version.rb +1 -1
  112. data/lib/rubocop.rb +16 -6
  113. metadata +10 -3
@@ -28,7 +28,10 @@ module RuboCop
28
28
  # put the comment.
29
29
  return if new_line_needed_before_closing_brace?(node)
30
30
 
31
- correct_next_line_brace(corrector)
31
+ end_range = last_element_range_with_trailing_comma(node).end
32
+
33
+ correct_next_line_brace(corrector, end_range)
34
+ correct_heredoc_argument_method_chain(corrector, end_range)
32
35
  end
33
36
  end
34
37
 
@@ -40,13 +43,19 @@ module RuboCop
40
43
  corrector.insert_before(node.loc.end, "\n")
41
44
  end
42
45
 
43
- def correct_next_line_brace(corrector)
46
+ def correct_next_line_brace(corrector, end_range)
44
47
  corrector.remove(range_with_surrounding_space(node.loc.end, side: :left))
48
+ corrector.insert_before(end_range, content_if_comment_present(corrector, node))
49
+ end
45
50
 
46
- corrector.insert_before(
47
- last_element_range_with_trailing_comma(node).end,
48
- content_if_comment_present(corrector, node)
49
- )
51
+ def correct_heredoc_argument_method_chain(corrector, end_range)
52
+ return unless (parent = node.parent)
53
+ return unless use_heredoc_argument_method_chain?(parent)
54
+
55
+ chained_method = range_between(parent.loc.dot.begin_pos, parent.loc.expression.end_pos)
56
+
57
+ corrector.remove(chained_method)
58
+ corrector.insert_after(end_range, chained_method.source)
50
59
  end
51
60
 
52
61
  def content_if_comment_present(corrector, node)
@@ -61,6 +70,13 @@ module RuboCop
61
70
  end
62
71
  end
63
72
 
73
+ def use_heredoc_argument_method_chain?(parent)
74
+ return false unless node.respond_to?(:first_argument)
75
+ return false unless (first_argument = node.first_argument)
76
+
77
+ parent.call_type? && first_argument.str_type? && first_argument.heredoc?
78
+ end
79
+
64
80
  def select_content_to_be_inserted_after_last_element(corrector, node)
65
81
  range = range_between(
66
82
  node.loc.end.begin_pos,
@@ -28,8 +28,9 @@ module RuboCop
28
28
  /^\s+# This cop (?<special>#{SPECIAL_WORDS.join('|')})?\s*(?<word>.+?) .*/.freeze
29
29
  REPLACEMENT_REGEX = /^\s+# This cop (#{SPECIAL_WORDS.join('|')})?\s*(.+?) /.freeze
30
30
 
31
+ # rubocop:disable Metrics/CyclomaticComplexity
31
32
  def on_class(node)
32
- return unless (module_node = node.parent)
33
+ return unless (module_node = node.parent) && node.parent_class
33
34
 
34
35
  description_beginning = first_comment_line(module_node)
35
36
  return unless description_beginning
@@ -48,6 +49,7 @@ module RuboCop
48
49
  end
49
50
  end
50
51
  end
52
+ # rubocop:enable Metrics/CyclomaticComplexity
51
53
 
52
54
  private
53
55
 
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Enforces the use of `node.lambda_or_proc?` instead of `node.lambda? || node.proc?`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # node.lambda? || node.proc?
11
+ # node.proc? || node.lambda?
12
+ #
13
+ # # good
14
+ # node.lambda_or_proc?
15
+ #
16
+ class LambdaOrProc < Base
17
+ extend AutoCorrector
18
+
19
+ MSG = 'Use `%<prefer>s`.'
20
+
21
+ # @!method lambda_or_proc(node)
22
+ def_node_matcher :lambda_or_proc, <<~PATTERN
23
+ {
24
+ (or $(send _node :lambda?) $(send _node :proc?))
25
+ (or $(send _node :proc?) $(send _node :lambda?))
26
+ (or
27
+ (or _ $(send _node :lambda?)) $(send _node :proc?))
28
+ (or
29
+ (or _ $(send _node :proc?)) $(send _node :lambda?))
30
+ }
31
+ PATTERN
32
+
33
+ def on_or(node)
34
+ return unless (lhs, rhs = lambda_or_proc(node))
35
+
36
+ offense = lhs.receiver.source_range.join(rhs.source_range.end)
37
+ prefer = "#{lhs.receiver.source}.lambda_or_proc?"
38
+
39
+ add_offense(offense, message: format(MSG, prefer: prefer)) do |corrector|
40
+ corrector.replace(offense, prefer)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -6,6 +6,7 @@ require_relative 'internal_affairs/empty_line_between_expect_offense_and_correct
6
6
  require_relative 'internal_affairs/example_description'
7
7
  require_relative 'internal_affairs/example_heredoc_delimiter'
8
8
  require_relative 'internal_affairs/inherit_deprecated_cop_class'
9
+ require_relative 'internal_affairs/lambda_or_proc'
9
10
  require_relative 'internal_affairs/location_line_equality_comparison'
10
11
  require_relative 'internal_affairs/method_name_end_with'
11
12
  require_relative 'internal_affairs/method_name_equal'
@@ -27,6 +27,8 @@ module RuboCop
27
27
 
28
28
  def on_new_investigation
29
29
  return if processed_source.tokens.empty?
30
+ # Quick check if we possibly have consecutive blank lines.
31
+ return unless processed_source.raw_source.include?("\n\n\n")
30
32
 
31
33
  lines = Set.new
32
34
  processed_source.each_token { |token| lines << token.line }
@@ -119,12 +119,16 @@ module RuboCop
119
119
  def ignored_ranges(ast)
120
120
  return [] unless ast
121
121
 
122
- @ignored_ranges ||= on_node(:pair, ast).map do |pair|
123
- next if pair.parent.single_line?
124
-
125
- key, value = *pair
126
- key.source_range.end_pos...value.source_range.begin_pos
127
- end.compact
122
+ @ignored_ranges ||= begin
123
+ ranges = []
124
+ on_node(:pair, ast) do |pair|
125
+ next if pair.parent.single_line?
126
+
127
+ key, value = *pair
128
+ ranges << (key.source_range.end_pos...value.source_range.begin_pos)
129
+ end
130
+ ranges
131
+ end
128
132
  end
129
133
 
130
134
  def force_equal_sign_alignment?
@@ -6,17 +6,49 @@ module RuboCop
6
6
  # Checks for a line break before the first element in a
7
7
  # multi-line array.
8
8
  #
9
- # @example
9
+ # @example AllowMultilineFinalElement: false (default)
10
+ #
11
+ # # bad
12
+ # [ :a,
13
+ # :b]
14
+ #
15
+ # # bad
16
+ # [ :a, {
17
+ # :b => :c
18
+ # }]
19
+ #
20
+ # # good
21
+ # [:a, :b]
22
+ #
23
+ # # good
24
+ # [
25
+ # :a,
26
+ # :b]
27
+ #
28
+ # # good
29
+ # [
30
+ # :a, {
31
+ # :b => :c
32
+ # }]
33
+ #
34
+ # @example AllowMultilineFinalElement: true
10
35
  #
11
36
  # # bad
12
37
  # [ :a,
13
38
  # :b]
14
39
  #
15
40
  # # good
41
+ # [ :a, {
42
+ # :b => :c
43
+ # }]
44
+ #
45
+ # # good
16
46
  # [
17
47
  # :a,
18
48
  # :b]
19
49
  #
50
+ # # good
51
+ # [:a, :b]
20
52
  class FirstArrayElementLineBreak < Base
21
53
  include FirstElementLineBreak
22
54
  extend AutoCorrector
@@ -26,7 +58,7 @@ module RuboCop
26
58
  def on_array(node)
27
59
  return if !node.loc.begin && !assignment_on_same_line?(node)
28
60
 
29
- check_children_line_break(node, node.children)
61
+ check_children_line_break(node, node.children, ignore_last: ignore_last_element?)
30
62
  end
31
63
 
32
64
  private
@@ -35,6 +67,10 @@ module RuboCop
35
67
  source = node.source_range.source_line[0...node.loc.column]
36
68
  /\s*=\s*$/.match?(source)
37
69
  end
70
+
71
+ def ignore_last_element?
72
+ !!cop_config['AllowMultilineFinalElement']
73
+ end
38
74
  end
39
75
  end
40
76
  end
@@ -6,16 +6,55 @@ module RuboCop
6
6
  # Checks for a line break before the first element in a
7
7
  # multi-line hash.
8
8
  #
9
- # @example
9
+ # @example AllowMultilineFinalElement: false (default)
10
10
  #
11
11
  # # bad
12
12
  # { a: 1,
13
13
  # b: 2}
14
14
  #
15
+ # # bad
16
+ # { a: 1, b: {
17
+ # c: 3
18
+ # }}
19
+ #
15
20
  # # good
16
21
  # {
17
22
  # a: 1,
18
23
  # b: 2 }
24
+ #
25
+ # # good
26
+ # {
27
+ # a: 1, b: {
28
+ # c: 3
29
+ # }}
30
+ #
31
+ # @example AllowMultilineFinalElement: true
32
+ #
33
+ # # bad
34
+ # { a: 1,
35
+ # b: 2}
36
+ #
37
+ # # bad
38
+ # { a: 1,
39
+ # b: {
40
+ # c: 3
41
+ # }}
42
+ #
43
+ # # good
44
+ # { a: 1, b: {
45
+ # c: 3
46
+ # }}
47
+ #
48
+ # # good
49
+ # {
50
+ # a: 1,
51
+ # b: 2 }
52
+ #
53
+ # # good
54
+ # {
55
+ # a: 1, b: {
56
+ # c: 3
57
+ # }}
19
58
  class FirstHashElementLineBreak < Base
20
59
  include FirstElementLineBreak
21
60
  extend AutoCorrector
@@ -25,7 +64,15 @@ module RuboCop
25
64
  def on_hash(node)
26
65
  # node.loc.begin tells us whether the hash opens with a {
27
66
  # If it doesn't, Style/FirstMethodArgumentLineBreak will handle it
28
- check_children_line_break(node, node.children) if node.loc.begin
67
+ return unless node.loc.begin
68
+
69
+ check_children_line_break(node, node.children, ignore_last: ignore_last_element?)
70
+ end
71
+
72
+ private
73
+
74
+ def ignore_last_element?
75
+ !!cop_config['AllowMultilineFinalElement']
29
76
  end
30
77
  end
31
78
  end
@@ -6,17 +6,70 @@ module RuboCop
6
6
  # Checks for a line break before the first argument in a
7
7
  # multi-line method call.
8
8
  #
9
- # @example
9
+ # @example AllowMultilineFinalElement: false (default)
10
10
  #
11
11
  # # bad
12
12
  # method(foo, bar,
13
13
  # baz)
14
14
  #
15
+ # # bad
16
+ # method(foo, bar, {
17
+ # baz: "a",
18
+ # qux: "b",
19
+ # })
20
+ #
15
21
  # # good
16
22
  # method(
17
23
  # foo, bar,
18
24
  # baz)
19
25
  #
26
+ # # good
27
+ # method(
28
+ # foo, bar, {
29
+ # baz: "a",
30
+ # qux: "b",
31
+ # })
32
+ #
33
+ # # ignored
34
+ # method foo, bar,
35
+ # baz
36
+ #
37
+ # @example AllowMultilineFinalElement: true
38
+ #
39
+ # # bad
40
+ # method(foo, bar,
41
+ # baz)
42
+ #
43
+ # # bad
44
+ # method(foo,
45
+ # bar,
46
+ # {
47
+ # baz: "a",
48
+ # qux: "b",
49
+ # }
50
+ # )
51
+ #
52
+ # # good
53
+ # method(foo, bar, {
54
+ # baz: "a",
55
+ # qux: "b",
56
+ # })
57
+ #
58
+ # # good
59
+ # method(
60
+ # foo, bar,
61
+ # baz)
62
+ #
63
+ # # good
64
+ # method(
65
+ # foo,
66
+ # bar,
67
+ # {
68
+ # baz: "a",
69
+ # qux: "b",
70
+ # }
71
+ # )
72
+ #
20
73
  # # ignored
21
74
  # method foo, bar,
22
75
  # baz
@@ -38,10 +91,16 @@ module RuboCop
38
91
  last_arg = args.last
39
92
  args.concat(args.pop.children) if last_arg&.hash_type? && !last_arg&.braces?
40
93
 
41
- check_method_line_break(node, args)
94
+ check_method_line_break(node, args, ignore_last: ignore_last_element?)
42
95
  end
43
96
  alias on_csend on_send
44
97
  alias on_super on_send
98
+
99
+ private
100
+
101
+ def ignore_last_element?
102
+ !!cop_config['AllowMultilineFinalElement']
103
+ end
45
104
  end
46
105
  end
47
106
  end
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks for a line break before the first parameter in a
7
7
  # multi-line method parameter definition.
8
8
  #
9
- # @example
9
+ # @example AllowMultilineFinalElement: false (default)
10
10
  #
11
11
  # # bad
12
12
  # def method(foo, bar,
@@ -14,6 +14,13 @@ module RuboCop
14
14
  # do_something
15
15
  # end
16
16
  #
17
+ # # bad
18
+ # def method(foo, bar, baz = {
19
+ # :a => "b",
20
+ # })
21
+ # do_something
22
+ # end
23
+ #
17
24
  # # good
18
25
  # def method(
19
26
  # foo, bar,
@@ -21,11 +28,48 @@ module RuboCop
21
28
  # do_something
22
29
  # end
23
30
  #
31
+ # # good
32
+ # def method(
33
+ # foo, bar, baz = {
34
+ # :a => "b",
35
+ # })
36
+ # do_something
37
+ # end
38
+ #
24
39
  # # ignored
25
40
  # def method foo,
26
41
  # bar
27
42
  # do_something
28
43
  # end
44
+ #
45
+ # @example AllowMultilineFinalElement: true
46
+ #
47
+ # # bad
48
+ # def method(foo, bar,
49
+ # baz)
50
+ # do_something
51
+ # end
52
+ #
53
+ # # good
54
+ # def method(foo, bar, baz = {
55
+ # :a => "b",
56
+ # })
57
+ # do_something
58
+ # end
59
+ #
60
+ # # good
61
+ # def method(
62
+ # foo, bar,
63
+ # baz)
64
+ # do_something
65
+ # end
66
+ #
67
+ # # ignored
68
+ # def method foo,
69
+ # bar
70
+ # do_something
71
+ # end
72
+ #
29
73
  class FirstMethodParameterLineBreak < Base
30
74
  include FirstElementLineBreak
31
75
  extend AutoCorrector
@@ -33,9 +77,15 @@ module RuboCop
33
77
  MSG = 'Add a line break before the first parameter of a multi-line method parameter list.'
34
78
 
35
79
  def on_def(node)
36
- check_method_line_break(node, node.arguments)
80
+ check_method_line_break(node, node.arguments, ignore_last: ignore_last_element?)
37
81
  end
38
82
  alias on_defs on_def
83
+
84
+ private
85
+
86
+ def ignore_last_element?
87
+ !!cop_config['AllowMultilineFinalElement']
88
+ end
39
89
  end
40
90
  end
41
91
  end
@@ -90,7 +90,8 @@ module RuboCop
90
90
  # which lines start inside a string literal?
91
91
  return [] if ast.nil?
92
92
 
93
- ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
93
+ ranges = Set.new
94
+ ast.each_node(:str, :dstr) do |str|
94
95
  loc = str.location
95
96
 
96
97
  if str.heredoc?
@@ -99,6 +100,7 @@ module RuboCop
99
100
  ranges << loc.expression
100
101
  end
101
102
  end
103
+ ranges
102
104
  end
103
105
 
104
106
  def message(_node)
@@ -51,7 +51,11 @@ module RuboCop
51
51
  private_constant :LINE_1_ENDING, :LINE_2_BEGINNING,
52
52
  :LEADING_STYLE_OFFENSE, :TRAILING_STYLE_OFFENSE
53
53
 
54
+ # rubocop:disable Metrics/AbcSize
54
55
  def on_dstr(node)
56
+ # Quick check if we possibly have line continuations.
57
+ return unless node.source.include?('\\')
58
+
55
59
  end_of_first_line = node.loc.expression.begin_pos - node.loc.expression.column
56
60
 
57
61
  raw_lines(node).each_cons(2) do |raw_line_one, raw_line_two|
@@ -66,6 +70,7 @@ module RuboCop
66
70
  end
67
71
  end
68
72
  end
73
+ # rubocop:enable Metrics/AbcSize
69
74
 
70
75
  private
71
76
 
@@ -31,7 +31,10 @@ module RuboCop
31
31
  include RangeHelp
32
32
  extend AutoCorrector
33
33
 
34
+ # rubocop:disable Metrics/AbcSize
34
35
  def on_new_investigation
36
+ return unless processed_source.raw_source.include?('\\')
37
+
35
38
  last_line = last_line(processed_source)
36
39
 
37
40
  @ignored_ranges = string_literal_ranges(processed_source.ast) +
@@ -44,6 +47,7 @@ module RuboCop
44
47
  investigate(line, line_number)
45
48
  end
46
49
  end
50
+ # rubocop:enable Metrics/AbcSize
47
51
 
48
52
  private
49
53
 
@@ -92,7 +96,8 @@ module RuboCop
92
96
  # which lines start inside a string literal?
93
97
  return [] if ast.nil?
94
98
 
95
- ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
99
+ ranges = Set.new
100
+ ast.each_node(:str, :dstr) do |str|
96
101
  loc = str.location
97
102
 
98
103
  if str.heredoc?
@@ -101,6 +106,7 @@ module RuboCop
101
106
  ranges << loc.expression
102
107
  end
103
108
  end
109
+ ranges
104
110
  end
105
111
 
106
112
  def comment_ranges(comments)
@@ -86,6 +86,8 @@ module RuboCop
86
86
  alias on_def on_potential_breakable_node
87
87
 
88
88
  def on_new_investigation
89
+ return unless processed_source.raw_source.include?(';')
90
+
89
91
  check_for_breakable_semicolons(processed_source)
90
92
  end
91
93
 
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Ensures that each item in a multi-line array
7
7
  # starts on a separate line.
8
8
  #
9
- # @example
9
+ # @example AllowMultilineFinalElement: false (default)
10
10
  #
11
11
  # # bad
12
12
  # [
@@ -14,12 +14,55 @@ module RuboCop
14
14
  # c
15
15
  # ]
16
16
  #
17
+ # # bad
18
+ # [ a, b, foo(
19
+ # bar
20
+ # )]
21
+ #
17
22
  # # good
18
23
  # [
19
24
  # a,
20
25
  # b,
21
26
  # c
22
27
  # ]
28
+ #
29
+ # # good
30
+ # [
31
+ # a,
32
+ # b,
33
+ # foo(
34
+ # bar
35
+ # )
36
+ # ]
37
+ #
38
+ # @example AllowMultilineFinalElement: true
39
+ #
40
+ # # bad
41
+ # [
42
+ # a, b,
43
+ # c
44
+ # ]
45
+ #
46
+ # # good
47
+ # [ a, b, foo(
48
+ # bar
49
+ # )]
50
+ #
51
+ # # good
52
+ # [
53
+ # a,
54
+ # b,
55
+ # c
56
+ # ]
57
+ #
58
+ # # good
59
+ # [
60
+ # a,
61
+ # b,
62
+ # foo(
63
+ # bar
64
+ # )
65
+ # ]
23
66
  class MultilineArrayLineBreaks < Base
24
67
  include MultilineElementLineBreaks
25
68
  extend AutoCorrector
@@ -27,7 +70,13 @@ module RuboCop
27
70
  MSG = 'Each item in a multi-line array must start on a separate line.'
28
71
 
29
72
  def on_array(node)
30
- check_line_breaks(node, node.children)
73
+ check_line_breaks(node, node.children, ignore_last: ignore_last_element?)
74
+ end
75
+
76
+ private
77
+
78
+ def ignore_last_element?
79
+ !!cop_config['AllowMultilineFinalElement']
31
80
  end
32
81
  end
33
82
  end