rubocop 1.39.0 → 1.42.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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +91 -10
  5. data/exe/rubocop +1 -1
  6. data/lib/rubocop/cli.rb +1 -1
  7. data/lib/rubocop/comment_config.rb +5 -0
  8. data/lib/rubocop/config.rb +39 -15
  9. data/lib/rubocop/config_loader.rb +14 -5
  10. data/lib/rubocop/config_loader_resolver.rb +6 -2
  11. data/lib/rubocop/config_validator.rb +1 -1
  12. data/lib/rubocop/cop/badge.rb +9 -4
  13. data/lib/rubocop/cop/base.rb +84 -74
  14. data/lib/rubocop/cop/commissioner.rb +8 -3
  15. data/lib/rubocop/cop/cop.rb +29 -29
  16. data/lib/rubocop/cop/corrector.rb +23 -11
  17. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  18. data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
  19. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  20. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  21. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  22. data/lib/rubocop/cop/layout/class_structure.rb +32 -11
  23. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  24. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  25. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  26. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  27. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  28. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  29. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  30. data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
  31. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  32. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
  33. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  34. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  35. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  36. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  37. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  38. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  39. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  40. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  41. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  42. data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
  43. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  44. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  45. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  46. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  47. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  48. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  49. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  50. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  51. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  52. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  53. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  54. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
  55. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  56. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +15 -3
  57. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  58. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  59. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  60. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -12
  61. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  62. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  63. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  64. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -3
  65. data/lib/rubocop/cop/lint/void.rb +6 -6
  66. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  67. data/lib/rubocop/cop/metrics/class_length.rb +10 -5
  68. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  69. data/lib/rubocop/cop/metrics/module_length.rb +10 -5
  70. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  71. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -4
  72. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
  73. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  74. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  75. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  76. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  77. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  78. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +28 -5
  79. data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
  80. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  81. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  82. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  83. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  84. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  85. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  86. data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
  87. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  88. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  89. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  90. data/lib/rubocop/cop/registry.rb +51 -36
  91. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  92. data/lib/rubocop/cop/style/alias.rb +9 -1
  93. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  94. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  95. data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
  96. data/lib/rubocop/cop/style/documentation.rb +11 -5
  97. data/lib/rubocop/cop/style/guard_clause.rb +44 -9
  98. data/lib/rubocop/cop/style/hash_syntax.rb +10 -7
  99. data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
  100. data/lib/rubocop/cop/style/if_with_semicolon.rb +4 -4
  101. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  102. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  103. data/lib/rubocop/cop/style/map_to_set.rb +61 -0
  104. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  105. data/lib/rubocop/cop/style/min_max_comparison.rb +73 -0
  106. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  107. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  108. data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
  109. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
  110. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  111. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  112. data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
  113. data/lib/rubocop/cop/style/require_order.rb +142 -0
  114. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  115. data/lib/rubocop/cop/style/select_by_regexp.rb +13 -5
  116. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  117. data/lib/rubocop/cop/style/signal_exception.rb +8 -6
  118. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  119. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  120. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  121. data/lib/rubocop/cop/style/word_array.rb +41 -0
  122. data/lib/rubocop/cop/style/yoda_expression.rb +74 -0
  123. data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
  124. data/lib/rubocop/cop/team.rb +30 -30
  125. data/lib/rubocop/cop/util.rb +32 -5
  126. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  127. data/lib/rubocop/cop/variable_force.rb +17 -29
  128. data/lib/rubocop/cops_documentation_generator.rb +33 -11
  129. data/lib/rubocop/directive_comment.rb +1 -1
  130. data/lib/rubocop/file_patterns.rb +43 -0
  131. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  132. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  133. data/lib/rubocop/formatter.rb +5 -1
  134. data/lib/rubocop/options.rb +8 -0
  135. data/lib/rubocop/path_util.rb +39 -16
  136. data/lib/rubocop/result_cache.rb +2 -2
  137. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  138. data/lib/rubocop/rspec/support.rb +2 -2
  139. data/lib/rubocop/runner.rb +10 -3
  140. data/lib/rubocop/server/core.rb +1 -1
  141. data/lib/rubocop/target_finder.rb +1 -1
  142. data/lib/rubocop/target_ruby.rb +1 -2
  143. data/lib/rubocop/version.rb +1 -1
  144. data/lib/rubocop.rb +19 -6
  145. metadata +19 -9
@@ -154,7 +154,9 @@ module RuboCop
154
154
  end
155
155
 
156
156
  def less_indented?(line)
157
- /^\s*(end\b|[)}\]])/.match?(line)
157
+ rule = config.for_cop('Layout/AccessModifierIndentation')['EnforcedStyle'] == 'outdent'
158
+ access_modifier = 'private|protected|public'
159
+ /\A\s*(end\b|[)}\]])/.match?(line) || (rule && /\A\s*(#{access_modifier})\b/.match?(line))
158
160
  end
159
161
 
160
162
  def two_alternatives?(line)
@@ -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
@@ -40,10 +40,13 @@ module RuboCop
40
40
  MSG = '%<type>s detected in indentation.'
41
41
 
42
42
  def on_new_investigation
43
- str_ranges = string_literal_ranges(processed_source.ast)
43
+ str_ranges = nil
44
44
 
45
45
  processed_source.lines.each.with_index(1) do |line, lineno|
46
46
  next unless (range = find_offense(line, lineno))
47
+
48
+ # Perform costly calculation only when needed.
49
+ str_ranges ||= string_literal_ranges(processed_source.ast)
47
50
  next if in_string_literal?(str_ranges, range)
48
51
 
49
52
  add_offense(range) { |corrector| autocorrect(corrector, range) }
@@ -90,7 +93,8 @@ module RuboCop
90
93
  # which lines start inside a string literal?
91
94
  return [] if ast.nil?
92
95
 
93
- ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
96
+ ranges = Set.new
97
+ ast.each_node(:str, :dstr) do |str|
94
98
  loc = str.location
95
99
 
96
100
  if str.heredoc?
@@ -99,6 +103,7 @@ module RuboCop
99
103
  ranges << loc.expression
100
104
  end
101
105
  end
106
+ ranges
102
107
  end
103
108
 
104
109
  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
 
@@ -32,10 +32,9 @@ module RuboCop
32
32
  extend AutoCorrector
33
33
 
34
34
  def on_new_investigation
35
- last_line = last_line(processed_source)
35
+ return unless processed_source.raw_source.include?('\\')
36
36
 
37
- @ignored_ranges = string_literal_ranges(processed_source.ast) +
38
- comment_ranges(processed_source.comments)
37
+ last_line = last_line(processed_source)
39
38
 
40
39
  processed_source.raw_source.lines.each_with_index do |line, index|
41
40
  break if index >= last_line
@@ -92,7 +91,8 @@ module RuboCop
92
91
  # which lines start inside a string literal?
93
92
  return [] if ast.nil?
94
93
 
95
- ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
94
+ ranges = Set.new
95
+ ast.each_node(:str, :dstr) do |str|
96
96
  loc = str.location
97
97
 
98
98
  if str.heredoc?
@@ -101,6 +101,7 @@ module RuboCop
101
101
  ranges << loc.expression
102
102
  end
103
103
  end
104
+ ranges
104
105
  end
105
106
 
106
107
  def comment_ranges(comments)
@@ -114,7 +115,12 @@ module RuboCop
114
115
  end
115
116
 
116
117
  def ignore_range?(backtick_range)
117
- @ignored_ranges.any? { |range| range.contains?(backtick_range) }
118
+ ignored_ranges.any? { |range| range.contains?(backtick_range) }
119
+ end
120
+
121
+ def ignored_ranges
122
+ @ignored_ranges ||= string_literal_ranges(processed_source.ast) +
123
+ comment_ranges(processed_source.comments)
118
124
  end
119
125
 
120
126
  def no_space_style?
@@ -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
@@ -91,7 +91,7 @@ module RuboCop
91
91
  if node.source.lines.first.end_with?("|\n")
92
92
  PIPE_SIZE
93
93
  else
94
- 1 + (PIPE_SIZE * 2)
94
+ (PIPE_SIZE * 2) + 1
95
95
  end
96
96
  end
97
97
 
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Ensures that each key in a multi-line hash
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,54 @@ module RuboCop
14
14
  # c: 3
15
15
  # }
16
16
  #
17
+ # # bad
18
+ # { a: 1, b: {
19
+ # c: 3,
20
+ # }}
21
+ #
17
22
  # # good
18
23
  # {
19
24
  # a: 1,
20
25
  # b: 2,
21
26
  # c: 3
22
27
  # }
28
+ #
29
+ # # good
30
+ # {
31
+ # a: 1,
32
+ # b: {
33
+ # c: 3,
34
+ # }
35
+ # }
36
+ #
37
+ # @example AllowMultilineFinalElement: true
38
+ #
39
+ # # bad
40
+ # {
41
+ # a: 1, b: 2,
42
+ # c: 3
43
+ # }
44
+ #
45
+ # # good
46
+ # { a: 1, b: {
47
+ # c: 3,
48
+ # }}
49
+ #
50
+ # # good
51
+ # {
52
+ # a: 1,
53
+ # b: 2,
54
+ # c: 3
55
+ # }
56
+ #
57
+ #
58
+ # # good
59
+ # {
60
+ # a: 1,
61
+ # b: {
62
+ # c: 3,
63
+ # }
64
+ # }
23
65
  class MultilineHashKeyLineBreaks < Base
24
66
  include MultilineElementLineBreaks
25
67
  extend AutoCorrector
@@ -31,8 +73,9 @@ module RuboCop
31
73
  # braces like {foo: 1}. That is, not a kwargs hashes.
32
74
  # Style/MultilineMethodArgumentLineBreaks handles those.
33
75
  return unless starts_with_curly_brace?(node)
76
+ return unless node.loc.begin
34
77
 
35
- check_line_breaks(node, node.children) if node.loc.begin
78
+ check_line_breaks(node, node.children, ignore_last: ignore_last_element?)
36
79
  end
37
80
 
38
81
  private
@@ -40,6 +83,10 @@ module RuboCop
40
83
  def starts_with_curly_brace?(node)
41
84
  node.loc.begin
42
85
  end
86
+
87
+ def ignore_last_element?
88
+ !!cop_config['AllowMultilineFinalElement']
89
+ end
43
90
  end
44
91
  end
45
92
  end