rubocop 1.67.0 → 1.69.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +81 -6
  4. data/lib/rubocop/cached_data.rb +12 -4
  5. data/lib/rubocop/cli/command/execute_runner.rb +1 -1
  6. data/lib/rubocop/cli/command/version.rb +2 -2
  7. data/lib/rubocop/cop/autocorrect_logic.rb +22 -2
  8. data/lib/rubocop/cop/base.rb +1 -1
  9. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  10. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  11. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
  12. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  13. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  14. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  15. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  16. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +2 -4
  17. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  18. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +46 -0
  19. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  20. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  21. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -2
  22. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  23. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  24. data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
  25. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  26. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -3
  27. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +3 -4
  28. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +3 -1
  29. data/lib/rubocop/cop/layout/indentation_width.rb +7 -7
  30. data/lib/rubocop/cop/layout/leading_comment_space.rb +44 -1
  31. data/lib/rubocop/cop/layout/line_length.rb +118 -4
  32. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  33. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  34. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
  35. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  36. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -35
  37. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -2
  38. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  39. data/lib/rubocop/cop/layout/space_around_operators.rb +16 -17
  40. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  41. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
  42. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
  43. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
  44. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  45. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +11 -12
  46. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -0
  47. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  48. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  49. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  50. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  51. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  52. data/lib/rubocop/cop/lint/float_comparison.rb +14 -6
  53. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -3
  54. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  55. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  56. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
  57. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  58. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -5
  59. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  60. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  61. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +8 -1
  62. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  63. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  64. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +106 -0
  65. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
  66. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
  67. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  68. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +12 -7
  69. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  70. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  71. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  72. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +9 -0
  73. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +5 -1
  74. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  75. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  76. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  77. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  78. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  79. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  80. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  81. data/lib/rubocop/cop/lint/void.rb +3 -2
  82. data/lib/rubocop/cop/metrics/class_length.rb +7 -7
  83. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
  84. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  85. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -2
  86. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  87. data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -0
  88. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  89. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  90. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  91. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +3 -1
  92. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
  93. data/lib/rubocop/cop/mixin/range_help.rb +0 -1
  94. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  95. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  96. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  97. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  98. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
  99. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -11
  100. data/lib/rubocop/cop/naming/variable_name.rb +3 -4
  101. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  102. data/lib/rubocop/cop/offense.rb +2 -3
  103. data/lib/rubocop/cop/style/access_modifier_declarations.rb +53 -24
  104. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  105. data/lib/rubocop/cop/style/array_intersect.rb +5 -4
  106. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  107. data/lib/rubocop/cop/style/block_delimiters.rb +18 -3
  108. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  109. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  110. data/lib/rubocop/cop/style/commented_keyword.rb +11 -1
  111. data/lib/rubocop/cop/style/conditional_assignment.rb +19 -21
  112. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  113. data/lib/rubocop/cop/style/dig_chain.rb +90 -0
  114. data/lib/rubocop/cop/style/endless_method.rb +1 -14
  115. data/lib/rubocop/cop/style/file_null.rb +73 -0
  116. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  117. data/lib/rubocop/cop/style/for.rb +0 -1
  118. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  119. data/lib/rubocop/cop/style/guard_clause.rb +15 -2
  120. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  121. data/lib/rubocop/cop/style/if_inside_else.rb +0 -1
  122. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -2
  123. data/lib/rubocop/cop/style/if_with_semicolon.rb +14 -5
  124. data/lib/rubocop/cop/style/inverse_methods.rb +0 -1
  125. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  126. data/lib/rubocop/cop/style/lambda_call.rb +0 -1
  127. data/lib/rubocop/cop/style/map_into_array.rb +6 -1
  128. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
  129. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +7 -11
  130. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  131. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  132. data/lib/rubocop/cop/style/multiple_comparison.rb +28 -39
  133. data/lib/rubocop/cop/style/mutable_constant.rb +4 -5
  134. data/lib/rubocop/cop/style/negated_if_else_condition.rb +6 -4
  135. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  136. data/lib/rubocop/cop/style/not.rb +1 -1
  137. data/lib/rubocop/cop/style/one_line_conditional.rb +25 -4
  138. data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
  139. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  140. data/lib/rubocop/cop/style/parallel_assignment.rb +8 -13
  141. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  142. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  143. data/lib/rubocop/cop/style/redundant_condition.rb +36 -21
  144. data/lib/rubocop/cop/style/redundant_line_continuation.rb +21 -2
  145. data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -11
  146. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -0
  147. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  148. data/lib/rubocop/cop/style/redundant_self.rb +7 -14
  149. data/lib/rubocop/cop/style/redundant_self_assignment.rb +7 -5
  150. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  151. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  152. data/lib/rubocop/cop/style/rescue_modifier.rb +2 -3
  153. data/lib/rubocop/cop/style/safe_navigation.rb +13 -1
  154. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  155. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
  156. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  157. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  158. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  159. data/lib/rubocop/cop/style/single_line_do_end_block.rb +13 -3
  160. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -3
  161. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  162. data/lib/rubocop/cop/style/string_concatenation.rb +0 -1
  163. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  164. data/lib/rubocop/cop/style/ternary_parentheses.rb +25 -4
  165. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  166. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  167. data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
  168. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  169. data/lib/rubocop/cop/variable_force/variable.rb +5 -1
  170. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  171. data/lib/rubocop/cop/variable_force.rb +4 -10
  172. data/lib/rubocop/cops_documentation_generator.rb +20 -10
  173. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  174. data/lib/rubocop/runner.rb +16 -8
  175. data/lib/rubocop/target_ruby.rb +1 -1
  176. data/lib/rubocop/version.rb +27 -8
  177. data/lib/rubocop.rb +16 -0
  178. metadata +28 -12
@@ -58,16 +58,17 @@ module RuboCop
58
58
  PATTERN
59
59
 
60
60
  def on_rescue(node)
61
- _begin_node, *_rescue_nodes, else_node = *node
62
- check_indentation(node.loc.else, else_node)
61
+ check_indentation(node.loc.else, node.else_branch)
63
62
  end
64
63
 
65
- def on_ensure(node)
64
+ def on_resbody(node)
66
65
  check_indentation(node.loc.keyword, node.body)
67
66
  end
67
+ alias on_for on_resbody
68
68
 
69
- alias on_resbody on_ensure
70
- alias on_for on_ensure
69
+ def on_ensure(node)
70
+ check_indentation(node.loc.keyword, node.branch)
71
+ end
71
72
 
72
73
  def on_kwbegin(node)
73
74
  # Check indentation against end keyword but only if it's first on its
@@ -325,8 +326,7 @@ module RuboCop
325
326
  if body_node.rescue_type?
326
327
  check_rescue?(body_node)
327
328
  elsif body_node.ensure_type?
328
- block_body, = *body_node
329
-
329
+ block_body, = *body_node # rubocop:disable InternalAffairs/NodeDestructuring
330
330
  if block_body&.rescue_type?
331
331
  check_rescue?(block_body)
332
332
  else
@@ -67,19 +67,40 @@ module RuboCop
67
67
  # attr_reader :name #: String
68
68
  # attr_reader :age #: Integer?
69
69
  #
70
+ # @example AllowSteepAnnotation: false (default)
71
+ #
72
+ # # bad
73
+ # [1, 2, 3].each_with_object([]) do |n, list| #$ Array[Integer]
74
+ # list << n
75
+ # end
76
+ #
77
+ # name = 'John' #: String
78
+ #
79
+ # @example AllowSteepAnnotation: true
80
+ #
81
+ # # good
82
+ #
83
+ # [1, 2, 3].each_with_object([]) do |n, list| #$ Array[Integer]
84
+ # list << n
85
+ # end
86
+ #
87
+ # name = 'John' #: String
88
+ #
70
89
  class LeadingCommentSpace < Base
71
90
  include RangeHelp
72
91
  extend AutoCorrector
73
92
 
74
93
  MSG = 'Missing space after `#`.'
75
94
 
76
- def on_new_investigation # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
95
+ def on_new_investigation # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
77
96
  processed_source.comments.each do |comment|
78
97
  next unless /\A(?!#\+\+|#--)(#+[^#\s=])/.match?(comment.text)
79
98
  next if comment.loc.line == 1 && allowed_on_first_line?(comment)
99
+ next if shebang_continuation?(comment)
80
100
  next if doxygen_comment_style?(comment)
81
101
  next if gemfile_ruby_comment?(comment)
82
102
  next if rbs_inline_annotation?(comment)
103
+ next if steep_annotation?(comment)
83
104
 
84
105
  add_offense(comment) do |corrector|
85
106
  expr = comment.source_range
@@ -103,6 +124,20 @@ module RuboCop
103
124
  comment.text.start_with?('#!')
104
125
  end
105
126
 
127
+ def shebang_continuation?(comment)
128
+ return false unless shebang?(comment)
129
+ return true if comment.loc.line == 1
130
+
131
+ previous_line_comment = processed_source.comment_at_line(comment.loc.line - 1)
132
+ return false unless previous_line_comment
133
+
134
+ # If the comment is a shebang but not on the first line, check if the previous
135
+ # line has a shebang comment that wasn't marked as an offense; if so, this comment
136
+ # continues the shebang and is acceptable.
137
+ shebang?(previous_line_comment) &&
138
+ !current_offense_locations.include?(previous_line_comment.source_range)
139
+ end
140
+
106
141
  def rackup_options?(comment)
107
142
  comment.text.start_with?('#\\')
108
143
  end
@@ -142,6 +177,14 @@ module RuboCop
142
177
  def rbs_inline_annotation?(comment)
143
178
  allow_rbs_inline_annotation? && comment.text.start_with?(/#:|#\[.+\]/)
144
179
  end
180
+
181
+ def allow_steep_annotation?
182
+ cop_config['AllowSteepAnnotation']
183
+ end
184
+
185
+ def steep_annotation?(comment)
186
+ allow_steep_annotation? && comment.text.start_with?(/#[$:]/)
187
+ end
145
188
  end
146
189
  end
147
190
  end
@@ -38,7 +38,7 @@ module RuboCop
38
38
  # * `Layout/MultilineHashKeyLineBreaks`
39
39
  # * `Layout/MultilineMethodArgumentLineBreaks`
40
40
  # * `Layout/MultilineMethodParameterLineBreaks`
41
- # * `Layout//ParameterAlignment`
41
+ # * `Layout/ParameterAlignment`
42
42
  # * `Style/BlockDelimiters`
43
43
  #
44
44
  # Together, these cops will pretty print hashes, arrays,
@@ -60,7 +60,7 @@ module RuboCop
60
60
  # bar: "0000000000",
61
61
  # baz: "0000000000",
62
62
  # }
63
- class LineLength < Base
63
+ class LineLength < Base # rubocop:disable Metrics/ClassLength
64
64
  include CheckLineBreakable
65
65
  include AllowedPattern
66
66
  include RangeHelp
@@ -74,9 +74,16 @@ module RuboCop
74
74
  def on_block(node)
75
75
  check_for_breakable_block(node)
76
76
  end
77
-
78
77
  alias on_numblock on_block
79
78
 
79
+ def on_str(node)
80
+ check_for_breakable_str(node)
81
+ end
82
+
83
+ def on_dstr(node)
84
+ check_for_breakable_dstr(node)
85
+ end
86
+
80
87
  def on_potential_breakable_node(node)
81
88
  check_for_breakable_node(node)
82
89
  end
@@ -132,6 +139,42 @@ module RuboCop
132
139
  breakable_range_by_line_index[line_index] = range_between(pos, pos + 1)
133
140
  end
134
141
 
142
+ def check_for_breakable_str(node)
143
+ line_index = node.loc.line - 1
144
+ return if breakable_range_by_line_index[line_index]
145
+
146
+ return unless breakable_string?(node)
147
+ return unless (delimiter = string_delimiter(node))
148
+ return unless (pos = breakable_string_position(node))
149
+
150
+ breakable_range_by_line_index[line_index] = range_between(pos, pos + 1)
151
+ breakable_string_delimiters[line_index] = delimiter
152
+ end
153
+
154
+ def check_for_breakable_dstr(node) # rubocop:disable Metrics/AbcSize
155
+ line_index = node.loc.line - 1
156
+ return if breakable_range_by_line_index[line_index]
157
+
158
+ return unless breakable_dstr?(node)
159
+ return unless (delimiter = string_delimiter(node))
160
+
161
+ node.each_child_node(:begin).detect do |begin_node|
162
+ next unless (pos = breakable_dstr_begin_position(begin_node))
163
+
164
+ breakable_range_by_line_index[line_index] = range_between(pos, pos + 1)
165
+ breakable_string_delimiters[line_index] = delimiter
166
+ end
167
+ end
168
+
169
+ def breakable_string?(node)
170
+ allow_string_split? &&
171
+ node.single_line? &&
172
+ !node.heredoc? &&
173
+ # TODO: strings inside hashes, kwargs and arrays are currently ignored,
174
+ # but could be considered in the future
175
+ !node.parent&.type?(:pair, :kwoptarg, :array)
176
+ end
177
+
135
178
  def breakable_block_range(block_node)
136
179
  if block_node.arguments? && !block_node.lambda?
137
180
  block_node.arguments.loc.end
@@ -153,10 +196,47 @@ module RuboCop
153
196
  next_range
154
197
  end
155
198
 
199
+ def breakable_string_position(node)
200
+ source_range = node.source_range
201
+ return if source_range.last_column < max
202
+ return unless (pos = breakable_string_range(node))
203
+
204
+ pos.end_pos unless pos.end_pos == source_range.begin_pos
205
+ end
206
+
207
+ # Locate where to break a string that is too long, ensuring that escape characters
208
+ # are not bisected.
209
+ # If the string contains spaces, use them to determine a place for a clean break;
210
+ # otherwise, the string will be broken at the line length limit.
211
+ def breakable_string_range(node) # rubocop:disable Metrics/AbcSize
212
+ source_range = node.source_range
213
+ relevant_substr = largest_possible_string(node)
214
+
215
+ if (space_pos = relevant_substr.rindex(/\s/))
216
+ source_range.resize(space_pos + 1)
217
+ elsif (escape_pos = relevant_substr.rindex(/\\(u[\da-f]{0,4}|x[\da-f]{0,2})?\z/))
218
+ source_range.resize(escape_pos)
219
+ else
220
+ adjustment = max - source_range.last_column - 3
221
+ return if adjustment.abs > source_range.size
222
+
223
+ source_range.adjust(end_pos: max - source_range.last_column - 3)
224
+ end
225
+ end
226
+
227
+ def breakable_dstr_begin_position(node)
228
+ source_range = node.source_range
229
+ source_range.begin_pos if source_range.begin_pos < max && source_range.end_pos >= max
230
+ end
231
+
156
232
  def breakable_range_by_line_index
157
233
  @breakable_range_by_line_index ||= {}
158
234
  end
159
235
 
236
+ def breakable_string_delimiters
237
+ @breakable_string_delimiters ||= {}
238
+ end
239
+
160
240
  def heredocs
161
241
  @heredocs ||= extract_heredocs(processed_source.ast)
162
242
  end
@@ -197,7 +277,14 @@ module RuboCop
197
277
 
198
278
  add_offense(loc, message: message) do |corrector|
199
279
  self.max = line_length(line)
200
- corrector.insert_before(breakable_range, "\n") unless breakable_range.nil?
280
+
281
+ insertion = if (delimiter = breakable_string_delimiters[line_index])
282
+ [delimiter, " \\\n", delimiter].join
283
+ else
284
+ "\n"
285
+ end
286
+
287
+ corrector.insert_before(breakable_range, insertion) unless breakable_range.nil?
201
288
  end
202
289
  end
203
290
 
@@ -224,6 +311,10 @@ module RuboCop
224
311
  cop_config['AllowHeredoc']
225
312
  end
226
313
 
314
+ def allow_string_split?
315
+ cop_config['SplitStrings']
316
+ end
317
+
227
318
  def extract_heredocs(ast)
228
319
  return [] unless ast
229
320
 
@@ -270,6 +361,29 @@ module RuboCop
270
361
 
271
362
  register_offense(excess_range(uri_range, line, line_index), line, line_index)
272
363
  end
364
+
365
+ def breakable_dstr?(node)
366
+ # If the `dstr` only contains one child, it cannot be broken
367
+ breakable_string?(node) && !node.child_nodes.one?
368
+ end
369
+
370
+ def string_delimiter(node)
371
+ delimiter = node.loc.begin
372
+ delimiter ||= node.parent.loc.begin if node.parent&.dstr_type?
373
+ delimiter = delimiter&.source
374
+
375
+ delimiter if %w[' "].include?(delimiter)
376
+ end
377
+
378
+ # Find the largest possible substring of a string node to retain before a break
379
+ def largest_possible_string(node)
380
+ # The maximum allowed length of a string value is:
381
+ # `Max` - end delimiter (quote) - continuation characters (space and slash)
382
+ max_length = max - 3
383
+ # If the string doesn't start at the beginning of the line, the max length is offset
384
+ max_length -= column_offset_between(node.loc, node.parent.loc) if node.parent
385
+ node.source[0...(max_length)]
386
+ end
273
387
  end
274
388
  end
275
389
  end
@@ -12,7 +12,7 @@ module RuboCop
12
12
  # argument of the call, then the closing brace should be on the same
13
13
  # line as the last argument of the call.
14
14
  #
15
- # If an method call's opening brace is on the line above the first
15
+ # If a method call's opening brace is on the line above the first
16
16
  # argument of the call, then the closing brace should be on the line
17
17
  # below the last argument of the call.
18
18
  #
@@ -12,7 +12,7 @@ module RuboCop
12
12
  # first parameter of the definition, then the closing brace should be
13
13
  # on the same line as the last parameter of the definition.
14
14
  #
15
- # If an method definition's opening brace is on the line above the first
15
+ # If a method definition's opening brace is on the line above the first
16
16
  # parameter of the definition, then the closing brace should be on the
17
17
  # line below the last parameter of the definition.
18
18
  #
@@ -76,9 +76,8 @@ module RuboCop
76
76
  end
77
77
 
78
78
  def check_and_or(node)
79
- lhs, rhs = *node
80
- range = offending_range(node, lhs, rhs.source_range, style)
81
- check(range, node, lhs, rhs.source_range)
79
+ range = offending_range(node, node.lhs, node.rhs.source_range, style)
80
+ check(range, node, node.lhs, node.rhs.source_range)
82
81
  end
83
82
 
84
83
  def offending_range(node, lhs, rhs, given_style)
@@ -3,11 +3,10 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Here we check if the parameters on a multi-line method call or
7
- # definition are aligned.
6
+ # Check that the parameters on a multi-line method call or definition are aligned.
8
7
  #
9
- # To set the alignment of the first argument, use the cop
10
- # FirstParameterIndentation.
8
+ # To set the alignment of the first argument, use the
9
+ # `Layout/FirstParameterIndentation` cop.
11
10
  #
12
11
  # @example EnforcedStyle: with_first_parameter (default)
13
12
  # # good
@@ -44,6 +44,7 @@ module RuboCop
44
44
  #
45
45
  class RedundantLineBreak < Base
46
46
  include CheckAssignment
47
+ include CheckSingleLineSuitability
47
48
  extend AutoCorrector
48
49
 
49
50
  MSG = 'Redundant line break detected.'
@@ -84,8 +85,8 @@ module RuboCop
84
85
  end
85
86
 
86
87
  def offense?(node)
87
- return false if !node.multiline? || too_long?(node) || !suitable_as_single_line?(node)
88
- return require_backslash?(node) if node.and_type? || node.or_type?
88
+ return false unless node.multiline? && suitable_as_single_line?(node)
89
+ return require_backslash?(node) if node.operator_keyword?
89
90
 
90
91
  !index_access_call_chained?(node) && !configured_to_not_be_inspected?(node)
91
92
  end
@@ -117,44 +118,11 @@ module RuboCop
117
118
  @config.for_cop('Layout/SingleLineBlockChain')['Enabled']
118
119
  end
119
120
 
120
- def suitable_as_single_line?(node)
121
- !comment_within?(node) &&
122
- node.each_descendant(:if, :case, :kwbegin, :def, :defs).none? &&
123
- node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
124
- node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
125
- end
126
-
127
121
  def convertible_block?(node)
128
122
  parent = node.parent
129
123
  parent&.block_type? && node == parent.send_node &&
130
124
  (node.parenthesized? || !node.arguments?)
131
125
  end
132
-
133
- def comment_within?(node)
134
- comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
135
-
136
- comment_line_numbers.any? do |comment_line_number|
137
- comment_line_number >= node.first_line && comment_line_number <= node.last_line
138
- end
139
- end
140
-
141
- def too_long?(node)
142
- lines = processed_source.lines[(node.first_line - 1)...node.last_line]
143
- to_single_line(lines.join("\n")).length > max_line_length
144
- end
145
-
146
- def to_single_line(source)
147
- source
148
- .gsub(/" *\\\n\s*'/, %q(" + ')) # Double quote, backslash, and then single quote
149
- .gsub(/' *\\\n\s*"/, %q(' + ")) # Single quote, backslash, and then double quote
150
- .gsub(/(["']) *\\\n\s*\1/, '') # Double or single quote, backslash, then same quote
151
- .gsub(/\n\s*(?=(&)?\.\w)/, '') # Extra space within method chaining which includes `&.`
152
- .gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
153
- end
154
-
155
- def max_line_length
156
- config.for_cop('Layout/LineLength')['Max']
157
- end
158
126
  end
159
127
  end
160
128
  end
@@ -92,6 +92,7 @@ module RuboCop
92
92
  )
93
93
  end
94
94
 
95
+ # rubocop:disable Metrics/AbcSize
95
96
  def alignment_source(node, starting_loc)
96
97
  ending_loc =
97
98
  case node.type
@@ -101,8 +102,7 @@ module RuboCop
101
102
  :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
102
103
  node.loc.name
103
104
  when :masgn
104
- mlhs_node, = *node
105
- mlhs_node.source_range
105
+ node.lhs.source_range
106
106
  else
107
107
  # It is a wrapper with receiver of object attribute or access modifier.
108
108
  node.receiver&.source_range || node.child_nodes.first.loc.name
@@ -110,6 +110,7 @@ module RuboCop
110
110
 
111
111
  range_between(starting_loc.begin_pos, ending_loc.end_pos).source
112
112
  end
113
+ # rubocop:enable Metrics/AbcSize
113
114
 
114
115
  # We will use ancestor or wrapper with access modifier.
115
116
 
@@ -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? || ancestor.range_type?
259
+ return true if ancestor.operator_keyword? || ancestor.range_type?
260
260
  return false unless ancestor.send_type?
261
261
  return true if ancestor.operator_method?
262
262
  end
@@ -99,51 +99,50 @@ module RuboCop
99
99
  def on_resbody(node)
100
100
  return unless node.loc.assoc
101
101
 
102
- _, variable, = *node
103
-
104
- check_operator(:resbody, node.loc.assoc, variable)
102
+ check_operator(:resbody, node.loc.assoc, node.exception_variable)
105
103
  end
106
104
 
107
105
  def on_send(node)
108
106
  return if rational_literal?(node)
109
107
 
110
108
  if node.setter_method?
111
- on_special_asgn(node)
109
+ on_setter_method(node)
112
110
  elsif regular_operator?(node)
113
111
  check_operator(:send, node.loc.selector, node.first_argument)
114
112
  end
115
113
  end
116
114
 
117
115
  def on_assignment(node)
118
- _, rhs, = *node
116
+ rhs = node.rhs
119
117
 
120
118
  return unless rhs
121
119
 
122
- check_operator(:assignment, node.loc.operator, rhs)
120
+ type = node.op_asgn_type? ? :special_asgn : :assignment
121
+ check_operator(type, node.loc.operator, rhs)
123
122
  end
124
123
 
125
- def on_casgn(node)
126
- _, _, right, = *node
124
+ def on_class(node)
125
+ rhs = node.parent_class
127
126
 
128
- return unless right
127
+ return unless rhs
129
128
 
130
- check_operator(:assignment, node.loc.operator, right)
129
+ check_operator(:class, node.loc.operator, rhs)
131
130
  end
132
131
 
133
132
  def on_binary(node)
134
- _, rhs, = *node
133
+ rhs = node.rhs
135
134
 
136
135
  return unless rhs
137
136
 
138
137
  check_operator(:binary, node.loc.operator, rhs)
139
138
  end
140
139
 
141
- def on_special_asgn(node)
142
- _, _, right, = *node
140
+ def on_setter_method(node)
141
+ rhs = node.first_argument
143
142
 
144
- return unless right
143
+ return unless rhs
145
144
 
146
- check_operator(:special_asgn, node.loc.operator, right)
145
+ check_operator(:special_asgn, node.loc.operator, node.first_argument)
147
146
  end
148
147
 
149
148
  def on_match_pattern(node)
@@ -155,14 +154,14 @@ module RuboCop
155
154
  alias on_or on_binary
156
155
  alias on_and on_binary
157
156
  alias on_lvasgn on_assignment
157
+ alias on_casgn on_assignment
158
158
  alias on_masgn on_assignment
159
159
  alias on_ivasgn on_assignment
160
160
  alias on_cvasgn on_assignment
161
161
  alias on_gvasgn on_assignment
162
- alias on_class on_binary
163
162
  alias on_or_asgn on_assignment
164
163
  alias on_and_asgn on_assignment
165
- alias on_op_asgn on_special_asgn
164
+ alias on_op_asgn on_assignment
166
165
 
167
166
  private
168
167
 
@@ -33,12 +33,12 @@ module RuboCop
33
33
  private
34
34
 
35
35
  def offense_range(node, begin_pos)
36
- if reference_variable_with_brackets?(node)
37
- receiver_end_pos = node.receiver.source_range.end_pos
38
- selector_begin_pos = node.loc.selector.begin_pos
39
- return if receiver_end_pos >= selector_begin_pos
40
- return if dot_before_brackets?(node, receiver_end_pos, selector_begin_pos)
36
+ receiver_end_pos = node.receiver.source_range.end_pos
37
+ selector_begin_pos = node.loc.selector.begin_pos
38
+ return if receiver_end_pos >= selector_begin_pos
39
+ return if dot_before_brackets?(node, receiver_end_pos, selector_begin_pos)
41
40
 
41
+ if reference_variable_with_brackets?(node)
42
42
  range_between(receiver_end_pos, selector_begin_pos)
43
43
  elsif node.method?(:[]=)
44
44
  offense_range_for_assignment(node, begin_pos)
@@ -12,9 +12,11 @@ module RuboCop
12
12
  #
13
13
  # # bad
14
14
  # array = [ a, b, c, d ]
15
+ # array = [ a, [ b, c ]]
15
16
  #
16
17
  # # good
17
18
  # array = [a, b, c, d]
19
+ # array = [a, [b, c]]
18
20
  #
19
21
  # @example EnforcedStyle: space
20
22
  # # The `space` style enforces that array literals have
@@ -22,9 +24,11 @@ module RuboCop
22
24
  #
23
25
  # # bad
24
26
  # array = [a, b, c, d]
27
+ # array = [ a, [ b, c ]]
25
28
  #
26
29
  # # good
27
30
  # array = [ a, b, c, d ]
31
+ # array = [ a, [ b, c ] ]
28
32
  #
29
33
  # @example EnforcedStyle: compact
30
34
  # # The `compact` style normally requires a space inside
@@ -32,6 +36,7 @@ module RuboCop
32
36
  # # or right brackets are collapsed together in nested arrays.
33
37
  #
34
38
  # # bad
39
+ # array = [a, b, c, d]
35
40
  # array = [ a, [ b, c ] ]
36
41
  # array = [
37
42
  # [ a ],
@@ -39,6 +44,7 @@ module RuboCop
39
44
  # ]
40
45
  #
41
46
  # # good
47
+ # array = [ a, b, c, d ]
42
48
  # array = [ a, [ b, c ]]
43
49
  # array = [[ a ],
44
50
  # [ b, c ]]
@@ -82,6 +82,10 @@ module RuboCop
82
82
  include RangeHelp
83
83
  extend AutoCorrector
84
84
 
85
+ def self.autocorrect_incompatible_with
86
+ [Style::BlockDelimiters]
87
+ end
88
+
85
89
  def on_block(node)
86
90
  return if node.keywords?
87
91
 
@@ -12,9 +12,11 @@ module RuboCop
12
12
  #
13
13
  # # bad
14
14
  # h = {a: 1, b: 2}
15
+ # foo = {{ a: 1 } => { b: { c: 2 }}}
15
16
  #
16
17
  # # good
17
18
  # h = { a: 1, b: 2 }
19
+ # foo = { { a: 1 } => { b: { c: 2 } } }
18
20
  #
19
21
  # @example EnforcedStyle: no_space
20
22
  # # The `no_space` style enforces that hash literals have
@@ -22,9 +24,11 @@ module RuboCop
22
24
  #
23
25
  # # bad
24
26
  # h = { a: 1, b: 2 }
27
+ # foo = {{ a: 1 } => { b: { c: 2 }}}
25
28
  #
26
29
  # # good
27
30
  # h = {a: 1, b: 2}
31
+ # foo = {{a: 1} => {b: {c: 2}}}
28
32
  #
29
33
  # @example EnforcedStyle: compact
30
34
  # # The `compact` style normally requires a space inside
@@ -22,7 +22,6 @@ module RuboCop
22
22
  include Interpolation
23
23
  include SurroundingSpace
24
24
  include ConfigurableEnforcedStyle
25
- include RangeHelp
26
25
  extend AutoCorrector
27
26
 
28
27
  MSG = '%<command>s space inside string interpolation.'