rubocop 1.39.0 → 1.44.1

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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +149 -11
  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 +26 -20
  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 +30 -10
  17. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  18. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
  19. data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
  20. data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
  21. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  22. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  23. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
  24. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  25. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
  26. data/lib/rubocop/cop/layout/class_structure.rb +32 -11
  27. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
  28. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  29. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  30. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  31. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  32. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  33. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  34. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  35. data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
  36. data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
  37. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  38. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
  39. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  40. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  41. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  42. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  43. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  44. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  45. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  46. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  47. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +0 -2
  48. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  49. data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
  50. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  51. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
  52. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  53. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  54. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  55. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
  56. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  57. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  58. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  59. data/lib/rubocop/cop/lint/else_layout.rb +2 -6
  60. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  61. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  62. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -7
  63. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
  64. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  65. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  66. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  67. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
  68. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  69. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +15 -3
  70. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  71. data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
  72. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  73. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  74. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -12
  75. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  76. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  77. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  78. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
  79. data/lib/rubocop/cop/lint/useless_rescue.rb +85 -0
  80. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +14 -4
  81. data/lib/rubocop/cop/lint/void.rb +25 -16
  82. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  83. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  84. data/lib/rubocop/cop/metrics/class_length.rb +10 -5
  85. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  86. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  87. data/lib/rubocop/cop/metrics/module_length.rb +10 -5
  88. data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
  89. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  90. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +3 -6
  91. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
  92. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  93. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  94. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  95. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  96. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  97. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +59 -6
  98. data/lib/rubocop/cop/mixin/line_length_help.rb +11 -2
  99. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  100. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  101. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  102. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  103. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  104. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  105. data/lib/rubocop/cop/mixin/statement_modifier.rb +16 -1
  106. data/lib/rubocop/cop/naming/block_forwarding.rb +5 -1
  107. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  108. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  109. data/lib/rubocop/cop/registry.rb +63 -43
  110. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  111. data/lib/rubocop/cop/style/access_modifier_declarations.rb +18 -10
  112. data/lib/rubocop/cop/style/alias.rb +9 -1
  113. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  114. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  115. data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
  116. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -9
  117. data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
  118. data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
  119. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
  120. data/lib/rubocop/cop/style/documentation.rb +11 -5
  121. data/lib/rubocop/cop/style/guard_clause.rb +44 -9
  122. data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
  123. data/lib/rubocop/cop/style/hash_syntax.rb +11 -7
  124. data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
  125. data/lib/rubocop/cop/style/if_with_semicolon.rb +4 -4
  126. data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
  127. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  128. data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
  129. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  130. data/lib/rubocop/cop/style/map_to_set.rb +61 -0
  131. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -14
  132. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
  133. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  134. data/lib/rubocop/cop/style/min_max_comparison.rb +83 -0
  135. data/lib/rubocop/cop/style/missing_else.rb +13 -1
  136. data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
  137. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  138. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
  139. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  140. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
  141. data/lib/rubocop/cop/style/operator_method_call.rb +15 -1
  142. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
  143. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  144. data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
  145. data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
  146. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +45 -0
  147. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  148. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  149. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  150. data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
  151. data/lib/rubocop/cop/style/require_order.rb +135 -0
  152. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  153. data/lib/rubocop/cop/style/select_by_regexp.rb +13 -5
  154. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  155. data/lib/rubocop/cop/style/semicolon.rb +26 -3
  156. data/lib/rubocop/cop/style/signal_exception.rb +8 -6
  157. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
  158. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  159. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  160. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  161. data/lib/rubocop/cop/style/word_array.rb +41 -0
  162. data/lib/rubocop/cop/style/yoda_expression.rb +81 -0
  163. data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
  164. data/lib/rubocop/cop/team.rb +30 -30
  165. data/lib/rubocop/cop/util.rb +32 -5
  166. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  167. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
  168. data/lib/rubocop/cop/variable_force.rb +18 -30
  169. data/lib/rubocop/cops_documentation_generator.rb +33 -11
  170. data/lib/rubocop/directive_comment.rb +1 -1
  171. data/lib/rubocop/file_patterns.rb +43 -0
  172. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  173. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  174. data/lib/rubocop/formatter.rb +4 -1
  175. data/lib/rubocop/options.rb +8 -0
  176. data/lib/rubocop/path_util.rb +50 -22
  177. data/lib/rubocop/result_cache.rb +2 -2
  178. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  179. data/lib/rubocop/rspec/expect_offense.rb +6 -4
  180. data/lib/rubocop/rspec/support.rb +2 -2
  181. data/lib/rubocop/runner.rb +10 -3
  182. data/lib/rubocop/server/cache.rb +3 -1
  183. data/lib/rubocop/server/core.rb +1 -1
  184. data/lib/rubocop/target_finder.rb +1 -1
  185. data/lib/rubocop/target_ruby.rb +1 -2
  186. data/lib/rubocop/version.rb +1 -1
  187. data/lib/rubocop.rb +23 -6
  188. metadata +23 -9
@@ -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
@@ -22,6 +22,7 @@ module RuboCop
22
22
  # RUBY
23
23
  #
24
24
  class HeredocIndentation < Base
25
+ include Alignment
25
26
  include Heredoc
26
27
  extend AutoCorrector
27
28
 
@@ -37,7 +38,7 @@ module RuboCop
37
38
  heredoc_indent_type = heredoc_indent_type(node)
38
39
 
39
40
  if heredoc_indent_type == '~'
40
- expected_indent_level = base_indent_level(node) + indentation_width
41
+ expected_indent_level = base_indent_level(node) + configured_indentation_width
41
42
  return if expected_indent_level == body_indent_level
42
43
  else
43
44
  return unless body_indent_level.zero?
@@ -66,9 +67,9 @@ module RuboCop
66
67
  current_indent_type = "<<#{heredoc_indent_type}"
67
68
 
68
69
  if current_indent_type == '<<~'
69
- width_message(indentation_width)
70
+ width_message(configured_indentation_width)
70
71
  else
71
- type_message(indentation_width, current_indent_type)
72
+ type_message(configured_indentation_width, current_indent_type)
72
73
  end
73
74
  end
74
75
 
@@ -89,7 +90,7 @@ module RuboCop
89
90
 
90
91
  body = heredoc_body(node)
91
92
 
92
- expected_indent = base_indent_level(node) + indentation_width
93
+ expected_indent = base_indent_level(node) + configured_indentation_width
93
94
  actual_indent = indent_level(body)
94
95
  increase_indent_level = expected_indent - actual_indent
95
96
 
@@ -122,7 +123,7 @@ module RuboCop
122
123
  def indented_body(node)
123
124
  body = heredoc_body(node)
124
125
  body_indent_level = indent_level(body)
125
- correct_indent_level = base_indent_level(node) + indentation_width
126
+ correct_indent_level = base_indent_level(node) + configured_indentation_width
126
127
  body.gsub(/^[^\S\r\n]{#{body_indent_level}}/, ' ' * correct_indent_level)
127
128
  end
128
129
 
@@ -148,10 +149,6 @@ module RuboCop
148
149
  node.source[/^<<([~-])/, 1]
149
150
  end
150
151
 
151
- def indentation_width
152
- @config.for_cop('Layout/IndentationWidth')['Width'] || 2
153
- end
154
-
155
152
  def heredoc_body(node)
156
153
  node.loc.heredoc_body.source
157
154
  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
@@ -9,13 +9,18 @@ module RuboCop
9
9
  # NOTE: This cop does not move the first argument, if you want that to
10
10
  # be on a separate line, see `Layout/FirstMethodArgumentLineBreak`.
11
11
  #
12
- # @example
12
+ # @example AllowMultilineFinalElement: false (default)
13
13
  #
14
14
  # # bad
15
15
  # foo(a, b,
16
16
  # c
17
17
  # )
18
18
  #
19
+ # # bad
20
+ # foo(a, b, {
21
+ # foo: "bar",
22
+ # })
23
+ #
19
24
  # # good
20
25
  # foo(
21
26
  # a,
@@ -25,6 +30,46 @@ module RuboCop
25
30
  #
26
31
  # # good
27
32
  # foo(a, b, c)
33
+ #
34
+ # # good
35
+ # foo(
36
+ # a,
37
+ # b,
38
+ # {
39
+ # foo: "bar",
40
+ # }
41
+ # )
42
+ #
43
+ # @example AllowMultilineFinalElement: true
44
+ #
45
+ # # bad
46
+ # foo(a, b,
47
+ # c
48
+ # )
49
+ #
50
+ # # good
51
+ # foo(a, b, {
52
+ # foo: "bar",
53
+ # })
54
+ #
55
+ # # good
56
+ # foo(
57
+ # a,
58
+ # b,
59
+ # c
60
+ # )
61
+ #
62
+ # # good
63
+ # foo(a, b, c)
64
+ #
65
+ # # good
66
+ # foo(
67
+ # a,
68
+ # b,
69
+ # {
70
+ # foo: "bar",
71
+ # }
72
+ # )
28
73
  class MultilineMethodArgumentLineBreaks < Base
29
74
  include MultilineElementLineBreaks
30
75
  extend AutoCorrector
@@ -45,7 +90,13 @@ module RuboCop
45
90
  last_arg = args.last
46
91
  args = args[0...-1] + last_arg.children if last_arg&.hash_type? && !last_arg&.braces?
47
92
 
48
- check_line_breaks(node, args)
93
+ check_line_breaks(node, args, ignore_last: ignore_last_element?)
94
+ end
95
+
96
+ private
97
+
98
+ def ignore_last_element?
99
+ !!cop_config['AllowMultilineFinalElement']
49
100
  end
50
101
  end
51
102
  end
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # NOTE: This cop does not move the first argument, if you want that to
10
10
  # be on a separate line, see `Layout/FirstMethodParameterLineBreak`.
11
11
  #
12
- # @example
12
+ # @example AllowMultilineFinalElement: false (default)
13
13
  #
14
14
  # # bad
15
15
  # def foo(a, b,
@@ -17,6 +17,47 @@ module RuboCop
17
17
  # )
18
18
  # end
19
19
  #
20
+ # # bad
21
+ # def foo(a, b = {
22
+ # foo: "bar",
23
+ # })
24
+ # end
25
+ #
26
+ # # good
27
+ # def foo(
28
+ # a,
29
+ # b,
30
+ # c
31
+ # )
32
+ # end
33
+ #
34
+ # # good
35
+ # def foo(
36
+ # a,
37
+ # b = {
38
+ # foo: "bar",
39
+ # }
40
+ # )
41
+ # end
42
+ #
43
+ # # good
44
+ # def foo(a, b, c)
45
+ # end
46
+ #
47
+ # @example AllowMultilineFinalElement: true
48
+ #
49
+ # # bad
50
+ # def foo(a, b,
51
+ # c
52
+ # )
53
+ # end
54
+ #
55
+ # # good
56
+ # def foo(a, b = {
57
+ # foo: "bar",
58
+ # })
59
+ # end
60
+ #
20
61
  # # good
21
62
  # def foo(
22
63
  # a,
@@ -26,6 +67,15 @@ module RuboCop
26
67
  # end
27
68
  #
28
69
  # # good
70
+ # def foo(
71
+ # a,
72
+ # b = {
73
+ # foo: "bar",
74
+ # }
75
+ # )
76
+ # end
77
+ #
78
+ # # good
29
79
  # def foo(a, b, c)
30
80
  # end
31
81
  class MultilineMethodParameterLineBreaks < Base
@@ -37,7 +87,13 @@ module RuboCop
37
87
  def on_def(node)
38
88
  return if node.arguments.empty?
39
89
 
40
- check_line_breaks(node, node.arguments)
90
+ check_line_breaks(node, node.arguments, ignore_last: ignore_last_element?)
91
+ end
92
+
93
+ private
94
+
95
+ def ignore_last_element?
96
+ !!cop_config['AllowMultilineFinalElement']
41
97
  end
42
98
  end
43
99
  end
@@ -84,11 +84,11 @@ module RuboCop
84
84
  return true if other_cop_takes_precedence?(node)
85
85
 
86
86
  !cop_config['InspectBlocks'] && (node.block_type? ||
87
- node.each_descendant(:block).any?(&:multiline?))
87
+ any_descendant?(node, :block, &:multiline?))
88
88
  end
89
89
 
90
90
  def other_cop_takes_precedence?(node)
91
- single_line_block_chain_enabled? && node.each_descendant(:block).any? do |block_node|
91
+ single_line_block_chain_enabled? && any_descendant?(node, :block) do |block_node|
92
92
  block_node.parent.send_type? && block_node.parent.loc.dot && !block_node.multiline?
93
93
  end
94
94
  end
@@ -256,7 +256,7 @@ module RuboCop
256
256
  # regular dotted method calls bind more tightly than operators
257
257
  # so we need to climb up the AST past them
258
258
  node.each_ancestor do |ancestor|
259
- return true if ancestor.and_type? || ancestor.or_type?
259
+ return true if ancestor.and_type? || ancestor.or_type? || ancestor.range_type?
260
260
  return false unless ancestor.send_type?
261
261
  return true if ancestor.operator_method?
262
262
  end
@@ -178,8 +178,6 @@ module RuboCop
178
178
  def multi_dimensional_array?(node, token, side: :right)
179
179
  offset = side == :right ? -1 : +1
180
180
  i = index_for(node, token) + offset
181
- # TODO: change this type check once
182
- # https://github.com/rubocop/rubocop-ast/pull/240 is merged
183
181
  i += offset while processed_source.tokens_within(node)[i].new_line?
184
182
  if side == :right
185
183
  processed_source.tokens_within(node)[i].right_bracket?
@@ -79,7 +79,7 @@ module RuboCop
79
79
  def ends_in_end?(processed_source)
80
80
  buffer = processed_source.buffer
81
81
 
82
- return true if buffer.source.strip.start_with?('__END__')
82
+ return true if buffer.source.match?(/\s*__END__/)
83
83
  return false if processed_source.tokens.empty?
84
84
 
85
85
  extra = buffer.source[processed_source.tokens.last.end_pos..]
@@ -47,7 +47,6 @@ module RuboCop
47
47
  MSG = 'Trailing whitespace detected.'
48
48
 
49
49
  def on_new_investigation
50
- @heredocs = extract_heredocs(processed_source.ast)
51
50
  processed_source.lines.each_with_index do |line, index|
52
51
  next unless line.end_with?(' ', "\t")
53
52
 
@@ -102,17 +101,25 @@ module RuboCop
102
101
  end
103
102
 
104
103
  def find_heredoc(line_number)
105
- @heredocs.each { |node, r| return node if r.include?(line_number) }
104
+ heredocs.each { |node, r| return node if r.include?(line_number) }
106
105
  nil
107
106
  end
108
107
 
108
+ def heredocs
109
+ @heredocs ||= extract_heredocs(processed_source.ast)
110
+ end
111
+
109
112
  def extract_heredocs(ast)
110
113
  return [] unless ast
111
114
 
112
- ast.each_node(:str, :dstr, :xstr).select(&:heredoc?).map do |node|
115
+ heredocs = []
116
+ ast.each_node(:str, :dstr, :xstr) do |node|
117
+ next unless node.heredoc?
118
+
113
119
  body = node.location.heredoc_body
114
- [node, body.first_line...body.last_line]
120
+ heredocs << [node, body.first_line...body.last_line]
115
121
  end
122
+ heredocs
116
123
  end
117
124
 
118
125
  def offense_range(lineno, line)
@@ -63,7 +63,7 @@ module RuboCop
63
63
  return unless node.arguments?
64
64
 
65
65
  return unless ambiguous_block_association?(node)
66
- return if node.parenthesized? || node.last_argument.lambda? || node.last_argument.proc? ||
66
+ return if node.parenthesized? || node.last_argument.lambda_or_proc? ||
67
67
  allowed_method_pattern?(node)
68
68
 
69
69
  message = message(node)