rubocop 1.91.0 → 1.92.2

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 (278) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +4 -1
  4. data/lib/rubocop/cached_data.rb +47 -7
  5. data/lib/rubocop/changed_files.rb +35 -13
  6. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  7. data/lib/rubocop/cli/command/execute_runner.rb +2 -2
  8. data/lib/rubocop/cli/command/explain.rb +34 -0
  9. data/lib/rubocop/cli/command/show_cops.rb +6 -0
  10. data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
  11. data/lib/rubocop/cli.rb +3 -2
  12. data/lib/rubocop/comment_config.rb +17 -8
  13. data/lib/rubocop/config.rb +0 -4
  14. data/lib/rubocop/config_loader.rb +6 -3
  15. data/lib/rubocop/config_loader_resolver.rb +37 -12
  16. data/lib/rubocop/config_obsoletion/removed_cop.rb +1 -1
  17. data/lib/rubocop/config_obsoletion.rb +9 -0
  18. data/lib/rubocop/config_validator.rb +11 -0
  19. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  20. data/lib/rubocop/cop/badge.rb +1 -1
  21. data/lib/rubocop/cop/base.rb +42 -21
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
  23. data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
  24. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  25. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  26. data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
  27. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
  28. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  29. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +25 -4
  30. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
  31. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
  32. data/lib/rubocop/cop/documentation.rb +1 -1
  33. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  34. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
  35. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
  36. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  37. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  38. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  39. data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
  40. data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
  41. data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
  42. data/lib/rubocop/cop/layout/class_structure.rb +29 -7
  43. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  44. data/lib/rubocop/cop/layout/dot_position.rb +25 -15
  45. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
  46. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  47. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  48. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  49. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
  50. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  51. data/lib/rubocop/cop/layout/end_alignment.rb +21 -25
  52. data/lib/rubocop/cop/layout/extra_spacing.rb +21 -6
  53. data/lib/rubocop/cop/layout/first_argument_indentation.rb +27 -1
  54. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
  55. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +16 -8
  56. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  57. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  58. data/lib/rubocop/cop/layout/hash_alignment.rb +16 -12
  59. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +7 -3
  60. data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
  61. data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
  62. data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
  63. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  64. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
  65. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  66. data/lib/rubocop/cop/layout/line_length.rb +176 -26
  67. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
  68. data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
  69. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +9 -0
  70. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
  71. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +30 -5
  72. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  73. data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
  74. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
  75. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  76. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  77. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +6 -11
  78. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
  79. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
  80. data/lib/rubocop/cop/layout/space_before_block_braces.rb +16 -1
  81. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
  82. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -9
  83. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
  84. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
  85. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  86. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
  87. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
  88. data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
  89. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
  90. data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
  91. data/lib/rubocop/cop/lint/literal_as_condition.rb +15 -0
  92. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
  93. data/lib/rubocop/cop/lint/loop.rb +24 -2
  94. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +71 -11
  95. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
  96. data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
  97. data/lib/rubocop/cop/lint/number_conversion.rb +3 -1
  98. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
  99. data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
  100. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +39 -9
  101. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
  102. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
  103. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
  104. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
  105. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
  106. data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
  107. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  108. data/lib/rubocop/cop/lint/void.rb +8 -1
  109. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  110. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  111. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  112. data/lib/rubocop/cop/mixin/alignment.rb +4 -0
  113. data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -19
  114. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +8 -2
  115. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  116. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  117. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  118. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
  119. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  120. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +41 -6
  121. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +26 -2
  122. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  123. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  124. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
  125. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  126. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  127. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +17 -2
  128. data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
  129. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
  130. data/lib/rubocop/cop/mixin/statement_modifier.rb +39 -5
  131. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  132. data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
  133. data/lib/rubocop/cop/mixin.rb +2 -0
  134. data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
  135. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  136. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  137. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  138. data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
  139. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  140. data/lib/rubocop/cop/offense.rb +59 -3
  141. data/lib/rubocop/cop/registry.rb +1 -1
  142. data/lib/rubocop/cop/security/json_load.rb +16 -4
  143. data/lib/rubocop/cop/style/access_modifier_declarations.rb +37 -2
  144. data/lib/rubocop/cop/style/alias.rb +18 -5
  145. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  146. data/lib/rubocop/cop/style/and_or.rb +37 -10
  147. data/lib/rubocop/cop/style/arguments_forwarding.rb +32 -3
  148. data/lib/rubocop/cop/style/attr.rb +3 -4
  149. data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
  150. data/lib/rubocop/cop/style/block_delimiters.rb +35 -3
  151. data/lib/rubocop/cop/style/case_equality.rb +14 -3
  152. data/lib/rubocop/cop/style/case_like_if.rb +6 -3
  153. data/lib/rubocop/cop/style/class_and_module_children.rb +57 -16
  154. data/lib/rubocop/cop/style/class_methods_definitions.rb +15 -0
  155. data/lib/rubocop/cop/style/collection_querying.rb +79 -46
  156. data/lib/rubocop/cop/style/combinable_loops.rb +89 -11
  157. data/lib/rubocop/cop/style/concat_array_literals.rb +58 -7
  158. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
  159. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +65 -9
  160. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  161. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  162. data/lib/rubocop/cop/style/empty_method.rb +3 -1
  163. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
  164. data/lib/rubocop/cop/style/endless_method.rb +104 -11
  165. data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
  166. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  167. data/lib/rubocop/cop/style/float_division.rb +37 -2
  168. data/lib/rubocop/cop/style/for.rb +53 -2
  169. data/lib/rubocop/cop/style/format_string.rb +28 -6
  170. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  171. data/lib/rubocop/cop/style/guard_clause.rb +31 -22
  172. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
  173. data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
  174. data/lib/rubocop/cop/style/hash_lookup_method.rb +42 -9
  175. data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
  176. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  177. data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
  178. data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -26
  179. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
  180. data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
  181. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  182. data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
  183. data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
  184. data/lib/rubocop/cop/style/lambda.rb +34 -1
  185. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  186. data/lib/rubocop/cop/style/map_into_array.rb +1 -2
  187. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +80 -13
  188. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +26 -2
  189. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
  190. data/lib/rubocop/cop/style/method_def_parentheses.rb +38 -4
  191. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  192. data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
  193. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  194. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  195. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
  196. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  197. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  198. data/lib/rubocop/cop/style/mutable_constant.rb +52 -7
  199. data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
  200. data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
  201. data/lib/rubocop/cop/style/nested_modifier.rb +27 -8
  202. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  203. data/lib/rubocop/cop/style/next.rb +24 -10
  204. data/lib/rubocop/cop/style/nil_comparison.rb +16 -4
  205. data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
  206. data/lib/rubocop/cop/style/not.rb +10 -5
  207. data/lib/rubocop/cop/style/numeric_predicate.rb +28 -5
  208. data/lib/rubocop/cop/style/one_line_conditional.rb +13 -2
  209. data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
  210. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
  211. data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
  212. data/lib/rubocop/cop/style/raise_args.rb +80 -11
  213. data/lib/rubocop/cop/style/reduce_to_hash.rb +47 -33
  214. data/lib/rubocop/cop/style/redundant_begin.rb +45 -5
  215. data/lib/rubocop/cop/style/redundant_condition.rb +30 -13
  216. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -0
  217. data/lib/rubocop/cop/style/redundant_exception.rb +27 -11
  218. data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -1
  219. data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
  220. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
  221. data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -1
  222. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
  223. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +20 -0
  224. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
  225. data/lib/rubocop/cop/style/redundant_self.rb +9 -1
  226. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
  227. data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
  228. data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
  229. data/lib/rubocop/cop/style/require_order.rb +25 -8
  230. data/lib/rubocop/cop/style/rescue_modifier.rb +11 -9
  231. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  232. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  233. data/lib/rubocop/cop/style/sample.rb +9 -8
  234. data/lib/rubocop/cop/style/self_assignment.rb +12 -15
  235. data/lib/rubocop/cop/style/semicolon.rb +16 -5
  236. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
  237. data/lib/rubocop/cop/style/single_line_methods.rb +42 -4
  238. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
  239. data/lib/rubocop/cop/style/string_concatenation.rb +21 -4
  240. data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
  241. data/lib/rubocop/cop/style/super_arguments.rb +3 -0
  242. data/lib/rubocop/cop/style/symbol_proc.rb +24 -6
  243. data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
  244. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
  245. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  246. data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
  247. data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
  248. data/lib/rubocop/cop/team.rb +10 -5
  249. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  250. data/lib/rubocop/cop/variable_force/variable.rb +14 -1
  251. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  252. data/lib/rubocop/formatter/formatter_set.rb +4 -0
  253. data/lib/rubocop/formatter/json_formatter.rb +71 -1
  254. data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
  255. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  256. data/lib/rubocop/formatter/sarif_formatter.rb +12 -7
  257. data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
  258. data/lib/rubocop/lsp/routes.rb +23 -23
  259. data/lib/rubocop/lsp/runtime.rb +47 -11
  260. data/lib/rubocop/lsp/stdin_runner.rb +11 -5
  261. data/lib/rubocop/lsp.rb +5 -2
  262. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  263. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  264. data/lib/rubocop/mcp/scope.rb +65 -0
  265. data/lib/rubocop/mcp/server.rb +184 -76
  266. data/lib/rubocop/mcp/source_files.rb +35 -0
  267. data/lib/rubocop/offense_limit.rb +30 -0
  268. data/lib/rubocop/options.rb +45 -10
  269. data/lib/rubocop/plugin/configuration_integrator.rb +36 -8
  270. data/lib/rubocop/remote_config.rb +4 -1
  271. data/lib/rubocop/result_cache.rb +20 -13
  272. data/lib/rubocop/runner.rb +110 -42
  273. data/lib/rubocop/server/cache.rb +6 -6
  274. data/lib/rubocop/target_ruby.rb +21 -9
  275. data/lib/rubocop/util.rb +69 -0
  276. data/lib/rubocop/version.rb +1 -1
  277. data/lib/rubocop.rb +5 -0
  278. metadata +16 -5
@@ -72,6 +72,22 @@ module RuboCop
72
72
 
73
73
  MSG = 'Line is too long. [%<length>d/%<max>d]'
74
74
 
75
+ # A trailing backslash, or a trailing unicode, hex, octal, meta or control escape whose
76
+ # payload may be incomplete. An even run of backslashes is complete on its own.
77
+ # Meta and control prefixes chain (`\M-\C-x`, `\c\M-x`), so a whole chain is one escape,
78
+ # and a braced unicode escape may hold several space-separated codepoints.
79
+ ESCAPE_SEQUENCE_TAIL = /
80
+ (?<!\\)(?:\\\\)*
81
+ (
82
+ \\(?:(?:[MC]-|c)\\)*
83
+ (?:u\{[\da-f\x20]*|u[\da-f]{0,4}|x[\da-f]{0,2}|[0-7]{0,3}|[MC]-?|c)?
84
+ )\z
85
+ /xi.freeze
86
+
87
+ def self.autocorrect_incompatible_with
88
+ [Style::MethodCallWithArgsParentheses, Style::MethodDefParentheses]
89
+ end
90
+
75
91
  def on_block(node)
76
92
  check_for_breakable_block(node)
77
93
  end
@@ -106,8 +122,10 @@ module RuboCop
106
122
  def on_new_investigation
107
123
  @breakable_range_by_line_index = {}
108
124
  @breakable_string_delimiters = {}
125
+ @breakable_strings = {}
109
126
  @endless_methods_by_line = {}
110
127
  @heredocs = nil
128
+ @heredoc_openers = nil
111
129
 
112
130
  return unless processed_source.raw_source.include?(';')
113
131
 
@@ -191,35 +209,69 @@ module RuboCop
191
209
  def check_for_breakable_node(node)
192
210
  breakable_node = extract_breakable_node(node, max)
193
211
  return if breakable_node.nil?
212
+ return if compact_nested_array_break?(node, breakable_node)
194
213
 
195
214
  line_index = breakable_node.first_line - 1
196
215
  range = breakable_node.source_range
197
216
 
198
217
  existing = breakable_range_by_line_index[line_index]
199
- return if existing
218
+ return if existing || after_heredoc_opener?(range)
200
219
 
201
220
  breakable_range_by_line_index[line_index] = range
202
221
  end
203
222
 
223
+ def after_heredoc_opener?(range)
224
+ heredoc_openers.any? do |opener|
225
+ opener.line == range.line && opener.begin_pos < range.begin_pos
226
+ end
227
+ end
228
+
229
+ def heredoc_openers
230
+ ast = processed_source.ast
231
+ return [] if ast.nil?
232
+
233
+ @heredoc_openers ||= ast.each_node(:any_str).select(&:heredoc?).map(&:source_range)
234
+ end
235
+
236
+ def compact_nested_array_break?(node, breakable_node)
237
+ return false if !node.array_type? || !node.square_brackets?
238
+ return false unless breakable_node.equal?(node.children.first)
239
+ return false unless breakable_node.source.start_with?('[')
240
+
241
+ compact_array_brackets_enforced?
242
+ end
243
+
244
+ def compact_array_brackets_enforced?
245
+ return false unless config.cop_enabled?('Layout/SpaceInsideArrayLiteralBrackets')
246
+
247
+ config.for_cop('Layout/SpaceInsideArrayLiteralBrackets')['EnforcedStyle'] == 'compact'
248
+ end
249
+
204
250
  def check_for_breakable_semicolons(processed_source)
205
251
  tokens = processed_source.tokens.select { |t| t.type == :tSEMI }
206
252
  tokens.reverse_each do |token|
207
253
  range = breakable_range_after_semicolon(token)
208
- breakable_range_by_line_index[range.line - 1] = range if range
254
+ next if range.nil? || after_heredoc_opener?(range)
255
+
256
+ breakable_range_by_line_index[range.line - 1] = range
209
257
  end
210
258
  end
211
259
 
212
260
  def check_for_breakable_block(block_node)
213
261
  return unless block_node.single_line?
214
- return if receiver_contains_heredoc?(block_node)
215
262
 
216
263
  line_index = block_node.loc.line - 1
264
+ return if breakable_string_delimiters[line_index]
265
+
217
266
  range = breakable_block_range(block_node)
218
267
  pos = range.begin_pos + 1
268
+ range = range_between(pos, pos + 1)
269
+ return if after_heredoc_opener?(range)
219
270
 
220
- breakable_range_by_line_index[line_index] = range_between(pos, pos + 1)
271
+ breakable_range_by_line_index[line_index] = range
221
272
  end
222
273
 
274
+ # rubocop:disable-next Metrics/AbcSize
223
275
  def check_for_breakable_str(node)
224
276
  line_index = node.loc.line - 1
225
277
  return if breakable_range_by_line_index[line_index]
@@ -230,6 +282,7 @@ module RuboCop
230
282
 
231
283
  breakable_range_by_line_index[line_index] = range_between(pos, pos + 1)
232
284
  breakable_string_delimiters[line_index] = delimiter
285
+ breakable_strings[line_index] = node
233
286
  end
234
287
 
235
288
  def check_for_breakable_dstr(node) # rubocop:disable Metrics/AbcSize
@@ -253,7 +306,8 @@ module RuboCop
253
306
  !node.heredoc? &&
254
307
  # TODO: strings inside hashes, kwargs and arrays are currently ignored,
255
308
  # but could be considered in the future
256
- !node.parent&.type?(:pair, :kwoptarg, :array)
309
+ !node.parent&.type?(:pair, :kwoptarg, :array) &&
310
+ !after_heredoc_opener?(node.source_range)
257
311
  end
258
312
 
259
313
  def breakable_block_range(block_node)
@@ -282,7 +336,33 @@ module RuboCop
282
336
  return if source_range.last_column < max
283
337
  return unless (pos = breakable_string_range(node))
284
338
 
285
- pos.end_pos unless pos.end_pos == source_range.begin_pos
339
+ content_begin_pos = node.loc?(:begin) ? node.loc.begin.end_pos : source_range.begin_pos
340
+ if blank_left_part?(node, content_begin_pos, pos)
341
+ pos = breakable_string_range_at_limit(source_range)
342
+ end
343
+ pos.end_pos if pos && leaves_two_parts?(node, content_begin_pos, pos)
344
+ end
345
+
346
+ def leaves_two_parts?(node, content_begin_pos, pos)
347
+ pos.end_pos > content_begin_pos && !blank_rest?(node, pos.end_pos)
348
+ end
349
+
350
+ def blank_left_part?(node, content_begin_pos, pos)
351
+ return false unless pos.end_pos > content_begin_pos
352
+ return false unless starts_after_quote?(node)
353
+
354
+ blank_between?(content_begin_pos, pos.end_pos)
355
+ end
356
+
357
+ def starts_after_quote?(node)
358
+ return true if node.loc?(:begin)
359
+
360
+ quote = node.parent&.loc&.begin if node.parent&.dstr_type?
361
+ quote ? quote.end_pos == node.source_range.begin_pos : false
362
+ end
363
+
364
+ def blank_between?(begin_pos, end_pos)
365
+ range_between(begin_pos, end_pos).source.strip.empty?
286
366
  end
287
367
 
288
368
  # Locate where to break a string that is too long, ensuring that escape characters
@@ -294,24 +374,57 @@ module RuboCop
294
374
  relevant_substr = largest_possible_string(node)
295
375
 
296
376
  if (space_pos = breakable_space_position(node, relevant_substr))
297
- source_range.resize(space_pos + 1)
298
- elsif (escape_pos = relevant_substr.rindex(/\\(u[\da-f]{0,4}|x[\da-f]{0,2})?\z/))
377
+ # A space can separate codepoints inside a braced unicode escape.
378
+ escape_pos = escape_sequence_start(relevant_substr[0..space_pos])
379
+ source_range.resize(escape_pos || (space_pos + 1))
380
+ elsif (escape_pos = escape_sequence_start(relevant_substr))
299
381
  source_range.resize(escape_pos)
300
382
  else
301
- adjustment = max - source_range.last_column - 3
302
- return if adjustment.abs > source_range.size
303
-
304
- source_range.adjust(end_pos: adjustment)
383
+ breakable_string_range_at_limit(source_range)
305
384
  end
306
385
  end
307
386
 
308
387
  def breakable_space_position(node, substr)
309
388
  limit = string_content_length(node) - 1
310
- space_pos = substr.rindex(/\s/)
311
- space_pos = substr[0, limit].rindex(/\s/) if space_pos && space_pos + 1 > limit
389
+ space_pos = space_before_word(node, substr.length - 1)
390
+ space_pos = space_before_word(node, limit - 1) if space_pos && space_pos + 1 > limit
312
391
  space_pos
313
392
  end
314
393
 
394
+ def space_before_word(node, max_pos)
395
+ return if max_pos.negative?
396
+
397
+ node.source.rindex(/\s(?=\S)/, max_pos)
398
+ end
399
+
400
+ def escape_sequence_start(text)
401
+ text.match(ESCAPE_SEQUENCE_TAIL)&.begin(1)
402
+ end
403
+
404
+ def breakable_string_range_at_limit(source_range)
405
+ adjustment = max - source_range.last_column - 3
406
+ return if adjustment.abs > source_range.size
407
+
408
+ cut = source_range.adjust(end_pos: adjustment)
409
+ cut = cut.resize(size_before_whitespace_run(source_range.source, cut.size))
410
+ escape_pos = escape_sequence_start(cut.source)
411
+
412
+ escape_pos ? source_range.resize(escape_pos) : cut
413
+ end
414
+
415
+ def size_before_whitespace_run(text, size)
416
+ return size if size.zero?
417
+ return size unless text[size]&.match?(/\s/)
418
+
419
+ text.rindex(/\S/, size - 1) || size
420
+ end
421
+
422
+ def blank_rest?(node, break_pos)
423
+ offset = break_pos - node.source_range.begin_pos
424
+
425
+ node.source[offset...string_content_length(node)].strip.empty?
426
+ end
427
+
315
428
  def string_content_length(node)
316
429
  content_end = node.loc?(:end) ? node.loc.end.begin_pos : node.source_range.end_pos
317
430
 
@@ -320,7 +433,18 @@ module RuboCop
320
433
 
321
434
  def breakable_dstr_begin_position(node)
322
435
  source_range = node.source_range
323
- source_range.begin_pos if source_range.column < max && source_range.last_column >= max
436
+ return unless source_range.column < max && source_range.last_column >= max
437
+ return if opens_string?(node)
438
+
439
+ source_range.begin_pos
440
+ end
441
+
442
+ def opens_string?(begin_node)
443
+ quote = begin_node.parent.loc.begin
444
+
445
+ return false unless quote
446
+
447
+ blank_between?(quote.end_pos, begin_node.source_range.begin_pos)
324
448
  end
325
449
 
326
450
  def breakable_range_by_line_index
@@ -335,6 +459,10 @@ module RuboCop
335
459
  @breakable_string_delimiters ||= {}
336
460
  end
337
461
 
462
+ def breakable_strings
463
+ @breakable_strings ||= {}
464
+ end
465
+
338
466
  def heredocs
339
467
  @heredocs ||= extract_heredocs(processed_source.ast)
340
468
  end
@@ -391,8 +519,36 @@ module RuboCop
391
519
  "\n"
392
520
  end
393
521
 
394
- corrector.insert_before(breakable_range, insertion) unless breakable_range.nil?
522
+ break_ranges(line_index).each do |range|
523
+ corrector.insert_before(range, insertion)
524
+ end
525
+ end
526
+ end
527
+
528
+ def break_ranges(line_index)
529
+ return [] if breakable_range.nil?
530
+ return [breakable_range] unless (node = breakable_strings[line_index])&.loc?(:end)
531
+
532
+ string_break_ranges(node, breakable_string_delimiters[line_index])
533
+ end
534
+
535
+ def string_break_ranges(node, delimiter)
536
+ ranges = [breakable_range]
537
+ pos = breakable_range.begin_pos
538
+
539
+ while (pos = next_string_break_position(node, pos, delimiter))
540
+ ranges << range_between(pos, pos + 1)
395
541
  end
542
+
543
+ ranges
544
+ end
545
+
546
+ def next_string_break_position(node, pos, delimiter)
547
+ rest = parse("#{delimiter}#{node.source_range.with(begin_pos: pos).source}").ast
548
+ return unless rest&.str_type?
549
+ return unless (rest_pos = breakable_string_position(rest))
550
+
551
+ pos + rest_pos - delimiter.length
396
552
  end
397
553
 
398
554
  def excess_range(uri_range, line, line_index)
@@ -511,16 +667,10 @@ module RuboCop
511
667
  # `Max` - end delimiter (quote) - continuation characters (space and slash)
512
668
  max_length = max - 3
513
669
  # Offset by the string's starting column so the broken line actually fits
514
- # within `Max`. When on the same line as its parent, use the column difference;
515
- # otherwise the string is indented on its own line, so subtract that indentation.
516
- # (Without this, an indented string under a multi-line parent never shortens
517
- # below `Max` and the autocorrect loops, inserting empty `"" \` fragments.)
518
- max_length -= if same_line?(node, node.parent)
519
- column_offset_between(node.loc, node.parent.loc)
520
- else
521
- node.loc.column
522
- end
523
- node.source[0...(max_length)]
670
+ # within `Max`, whatever precedes the string on its line.
671
+ max_length -= node.loc.column
672
+
673
+ node.source[0, [max_length, 0].max]
524
674
  end
525
675
  end
526
676
  end
@@ -106,6 +106,18 @@ module RuboCop
106
106
  ALWAYS_SAME_LINE_MESSAGE = 'The closing array brace must be on the ' \
107
107
  'same line as the last array element.'
108
108
 
109
+ # Moving the closing bracket after a hash literal or method call element while
110
+ # `Layout/MultilineHashBraceLayout` or `Layout/MultilineMethodCallBraceLayout` moves
111
+ # that element's closing brace in the same pass places the bracket after whatever
112
+ # follows the moved brace, such as a comment.
113
+ # Moving it while `Style/ConcatArrayLiterals` removes the brackets in the same pass
114
+ # leaves the bracket behind.
115
+ def self.autocorrect_incompatible_with
116
+ [
117
+ Layout::MultilineHashBraceLayout, Layout::MultilineMethodCallBraceLayout, Style::ConcatArrayLiterals
118
+ ]
119
+ end
120
+
109
121
  def on_array(node)
110
122
  check_brace_layout(node)
111
123
  end
@@ -56,6 +56,13 @@ module RuboCop
56
56
  ARG_MSG = 'Block argument expression is not on the same line as the block start.'
57
57
  PIPE_SIZE = '|'.length
58
58
 
59
+ # `Style/Lambda` moves the block arguments of `lambda` into `->(...)`, and
60
+ # `Style/ItBlockParameter` and `Style/HashEachMethods` remove some or all of them,
61
+ # in the same pass, while this cop moves them next to the block start.
62
+ def self.autocorrect_incompatible_with
63
+ [Style::HashEachMethods, Style::ItBlockParameter, Style::Lambda]
64
+ end
65
+
59
66
  def on_block(node)
60
67
  return if node.single_line?
61
68
 
@@ -155,7 +162,7 @@ module RuboCop
155
162
  end
156
163
 
157
164
  def include_trailing_comma?(args)
158
- arg_count = args.each_descendant(:arg).to_a.size
165
+ arg_count = args.each_descendant.count(&:argument_type?)
159
166
  arg_count == 1 && args.source.include?(',')
160
167
  end
161
168
  end
@@ -106,6 +106,15 @@ module RuboCop
106
106
  ALWAYS_SAME_LINE_MESSAGE = 'Closing hash brace must be on the same ' \
107
107
  'line as the last hash element.'
108
108
 
109
+ # Moving the closing brace after a method call value while
110
+ # `Layout/MultilineMethodCallBraceLayout` moves that call's closing parenthesis
111
+ # before a comment in the same pass places the brace after the comment.
112
+ # Moving it while `Style/HashAsLastArrayItem` or `Style/RedundantDoubleSplatHashBraces`
113
+ # removes the braces in the same pass leaves the brace behind.
114
+ def self.autocorrect_incompatible_with
115
+ [Layout::MultilineMethodCallBraceLayout, Style::HashAsLastArrayItem, Style::RedundantDoubleSplatHashBraces]
116
+ end
117
+
109
118
  def on_hash(node)
110
119
  check_brace_layout(node)
111
120
  end
@@ -106,6 +106,12 @@ module RuboCop
106
106
  ALWAYS_SAME_LINE_MESSAGE = 'Closing method call brace must be on ' \
107
107
  'the same line as the last argument.'
108
108
 
109
+ # Moving the closing parenthesis and removing it under `omit_parentheses` in the same pass
110
+ # leaves the moved parenthesis behind.
111
+ def self.autocorrect_incompatible_with
112
+ [Style::MethodCallWithArgsParentheses]
113
+ end
114
+
109
115
  def on_send(node)
110
116
  check_brace_layout(node)
111
117
  end
@@ -73,14 +73,28 @@ module RuboCop
73
73
  end
74
74
 
75
75
  def find_pair_ancestor(node)
76
+ child = node
76
77
  node.each_ancestor do |ancestor|
77
78
  return ancestor if ancestor.pair_type?
78
79
  break if grouped_expression?(ancestor) || inside_arg_list_parentheses?(node, ancestor)
80
+ break if inside_body?(ancestor, child)
81
+
82
+ child = ancestor
79
83
  end
80
84
 
81
85
  nil
82
86
  end
83
87
 
88
+ # A block, `begin`, `if` or loop body is a separate set of statements, so
89
+ # a method chain in it is not the value of a hash pair the body is nested in.
90
+ # The send node of a block is still part of the value.
91
+ def inside_body?(ancestor, child)
92
+ return !child.equal?(ancestor.send_node) if ancestor.any_block_type?
93
+ return !ancestor.ternary? if ancestor.if_type?
94
+
95
+ ancestor.type?(:kwbegin, :while, :until, :for)
96
+ end
97
+
84
98
  def unwrap_block_node(node)
85
99
  node&.any_block_type? ? node.send_node : node
86
100
  end
@@ -88,7 +102,7 @@ module RuboCop
88
102
  def autocorrect(corrector, node)
89
103
  if @send_node.block_node
90
104
  correct_selector_only(corrector, node)
91
- correct_block(corrector, @send_node.block_node)
105
+ correct_block(corrector, @send_node.block_node, node.first_line)
92
106
  else
93
107
  AlignmentCorrector.correct(corrector, processed_source, node, @column_delta)
94
108
  end
@@ -100,10 +114,21 @@ module RuboCop
100
114
  AlignmentCorrector.correct(corrector, processed_source, selector_range, @column_delta)
101
115
  end
102
116
 
103
- def correct_block(corrector, block_node)
104
- AlignmentCorrector.correct(corrector, processed_source, block_node.body, @column_delta)
105
- end_range = range_by_whole_lines(block_node.loc.end, include_final_newline: false)
106
- AlignmentCorrector.correct(corrector, processed_source, end_range, @column_delta)
117
+ def correct_block(corrector, block_node, selector_line)
118
+ lines_to_shift = block_lines(block_node) - [selector_line]
119
+
120
+ lines_to_shift.each do |line|
121
+ line_range = processed_source.buffer.line_range(line)
122
+
123
+ AlignmentCorrector.correct(corrector, processed_source, line_range, @column_delta)
124
+ end
125
+ end
126
+
127
+ def block_lines(block_node)
128
+ body = block_node.body
129
+ lines = body ? (body.first_line..body.last_line).to_a : []
130
+
131
+ (lines << block_node.loc.end.line).uniq
107
132
  end
108
133
 
109
134
  def relevant_node?(send_node)
@@ -118,6 +118,10 @@ module RuboCop
118
118
  ALWAYS_SAME_LINE_MESSAGE = 'Closing method definition brace must be ' \
119
119
  'on the same line as the last parameter.'
120
120
 
121
+ def self.autocorrect_incompatible_with
122
+ [Style::MultilineMethodSignature]
123
+ end
124
+
121
125
  def on_def(node)
122
126
  check_brace_layout(node.arguments)
123
127
  end
@@ -54,6 +54,11 @@ module RuboCop
54
54
 
55
55
  MSG = 'Redundant line break detected.'
56
56
 
57
+ def on_new_investigation
58
+ super
59
+ @offense_line_ranges = []
60
+ end
61
+
57
62
  def on_lvasgn(node)
58
63
  super unless end_with_percent_blank_string?(processed_source)
59
64
  end
@@ -77,12 +82,15 @@ module RuboCop
77
82
  end
78
83
 
79
84
  def check_assignment(node, _rhs)
80
- return unless offense?(node)
85
+ return unless offense?(node) && !part_of_ignored_node?(node)
81
86
 
82
87
  register_offense(node)
83
88
  end
84
89
 
85
90
  def register_offense(node)
91
+ line_range = joined_line_range(node)
92
+ return if too_long_as_single_line?(line_range)
93
+
86
94
  # The exact single-line correction is verified to parse equivalently
87
95
  # before the offense is registered, so a join that would change how
88
96
  # the code parses is never reported or offered.
@@ -92,6 +100,19 @@ module RuboCop
92
100
  corrector.replace(node, to_single_line(node.source).strip)
93
101
  end
94
102
  ignore_node(node)
103
+ @offense_line_ranges.reject! { |range| line_range.cover?(range) }
104
+ @offense_line_ranges << line_range
105
+ end
106
+
107
+ # Offenses registered in the same pass that share a line with `node`
108
+ # get joined onto that line too, so the combined line has to fit.
109
+ def joined_line_range(node)
110
+ sharing_ranges = @offense_line_ranges.select do |range|
111
+ range.begin <= node.last_line && node.first_line <= range.end
112
+ end
113
+ lines = [node.first_line, node.last_line, *sharing_ranges.flat_map(&:minmax)]
114
+
115
+ lines.min..lines.max
95
116
  end
96
117
 
97
118
  def apply_reparse_correction(corrector, node)
@@ -22,6 +22,7 @@ module RuboCop
22
22
  # puts 'error'
23
23
  # end
24
24
  class RescueEnsureAlignment < Base
25
+ include Alignment
25
26
  include RangeHelp
26
27
  include EndKeywordAlignment
27
28
  extend AutoCorrector
@@ -74,9 +75,10 @@ module RuboCop
74
75
  # Some inline node is sitting before current node.
75
76
  return nil unless whitespace.source.strip.empty?
76
77
 
77
- new_column = alignment_location.column
78
+ indentation = alignment_indentation(alignment_location)
79
+ return nil if indentation.nil?
78
80
 
79
- corrector.replace(whitespace, ' ' * new_column)
81
+ corrector.replace(whitespace, indentation)
80
82
  end
81
83
 
82
84
  def format_message(alignment_node, alignment_loc, kw_loc)
@@ -91,6 +93,17 @@ module RuboCop
91
93
  )
92
94
  end
93
95
 
96
+ # A run of spaces sized to the target column would be turned back into tabs by
97
+ # `Layout/IndentationStyle`, generally landing on a different column, so under
98
+ # tabs the target line's own indentation is reused. There is nothing to reuse
99
+ # when the target does not start its line.
100
+ def alignment_indentation(location)
101
+ return ' ' * location.column unless using_tabs?
102
+ return unless begins_its_line?(location)
103
+
104
+ location.source_line[/\A\s*/]
105
+ end
106
+
94
107
  # rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
95
108
  def alignment_source(node, starting_loc)
96
109
  ending_loc =
@@ -102,7 +115,7 @@ module RuboCop
102
115
  node.loc.name
103
116
  when :sclass
104
117
  node.identifier.source_range
105
- when :masgn
118
+ when :masgn, :op_asgn, :or_asgn, :and_asgn
106
119
  node.lhs.source_range
107
120
  else
108
121
  # It is a wrapper with receiver of object attribute or access modifier.
@@ -25,13 +25,17 @@ module RuboCop
25
25
 
26
26
  MSG = 'Put method call on a separate line if chained to a single line block.'
27
27
 
28
+ # These cops rewrite a method chained to the block in the same pass,
29
+ # which must not start a line of its own.
28
30
  def self.autocorrect_incompatible_with
29
- [Style::MapToHash]
31
+ [Style::FloatDivision, Style::MapToHash, Style::MapToSet, Style::NilComparison, Style::RedundantSort]
30
32
  end
31
33
 
32
34
  def on_send(node)
33
35
  range = offending_range(node)
34
- add_offense(range) { |corrector| corrector.insert_before(range, "\n") } if range
36
+ return if !range || heredoc_opened_before?(node.receiver, range)
37
+
38
+ add_offense(range) { |corrector| corrector.insert_before(range, "\n") }
35
39
  end
36
40
  alias on_csend on_send
37
41
 
@@ -63,6 +67,10 @@ module RuboCop
63
67
  # l.(1) has no selector, so we use the opening parenthesis instead
64
68
  node.loc.selector || node.loc.begin
65
69
  end
70
+
71
+ def heredoc_opened_before?(receiver, range)
72
+ receiver.each_node(:any_str).any? { |str| str.heredoc? && str.first_line == range.line }
73
+ end
66
74
  end
67
75
  end
68
76
  end
@@ -20,6 +20,7 @@ module RuboCop
20
20
 
21
21
  def on_send(node)
22
22
  return unless node.prefix_bang? && whitespace_after_operator?(node)
23
+ return if unary_tilde?(node.receiver)
23
24
 
24
25
  add_offense(node) do |corrector|
25
26
  corrector.remove(
@@ -33,6 +34,10 @@ module RuboCop
33
34
  def whitespace_after_operator?(node)
34
35
  node.receiver.source_range.begin_pos - node.source_range.begin_pos > 1
35
36
  end
37
+
38
+ def unary_tilde?(receiver)
39
+ receiver.send_type? && receiver.unary_operation? && receiver.method?(:~)
40
+ end
36
41
  end
37
42
  end
38
43
  end
@@ -6,7 +6,8 @@ module RuboCop
6
6
  # Checks the spacing inside and after block parameters pipes. Line breaks
7
7
  # inside parameter pipes are checked by `Layout/MultilineBlockLayout` and
8
8
  # not by this cop. Spaces inside a lambda's parameter parentheses are left
9
- # to `Layout/SpaceInsideParens` when that cop enforces a conflicting style.
9
+ # to `Layout/SpaceInsideParens` when that cop is enabled, so the examples
10
+ # below apply to a lambda only when it is not.
10
11
  #
11
12
  # @example EnforcedStyleInsidePipes: no_space (default)
12
13
  # # bad
@@ -35,7 +36,7 @@ module RuboCop
35
36
 
36
37
  return unless node.arguments? && pipes?(arguments)
37
38
 
38
- check_inside_pipes(arguments) unless conflicting_space_inside_parens_style?(arguments)
39
+ check_inside_pipes(arguments) unless checked_by_space_inside_parens?(arguments)
39
40
  check_after_closing_pipe(arguments) if node.body
40
41
  check_each_arg(arguments)
41
42
  end
@@ -54,14 +55,8 @@ module RuboCop
54
55
  'EnforcedStyleInsidePipes'
55
56
  end
56
57
 
57
- def conflicting_space_inside_parens_style?(arguments)
58
- return false unless arguments.loc.begin.source == '('
59
-
60
- case config.for_enabled_cop('Layout/SpaceInsideParens')['EnforcedStyle']
61
- when 'no_space' then style == :space
62
- when 'space', 'compact' then style == :no_space
63
- else false
64
- end
58
+ def checked_by_space_inside_parens?(arguments)
59
+ arguments.loc.begin.source == '(' && config.cop_enabled?('Layout/SpaceInsideParens')
65
60
  end
66
61
 
67
62
  def check_inside_pipes(arguments)
@@ -153,7 +148,7 @@ module RuboCop
153
148
  if node
154
149
  corrector.insert_before(node, ' ')
155
150
  else
156
- corrector.insert_after(target, ' ')
151
+ corrector.insert_after(range_between(space_begin_pos, space_begin_pos), ' ')
157
152
  end
158
153
  end
159
154
  end
@@ -209,6 +209,7 @@ module RuboCop
209
209
  end
210
210
 
211
211
  return unless space_after_missing?(range)
212
+ return if block_brace_with_no_space_style?(node, range)
212
213
 
213
214
  add_offense(range, message: format(MSG_AFTER, range: range.source)) do |corrector|
214
215
  corrector.insert_after(range, ' ')
@@ -233,6 +234,15 @@ module RuboCop
233
234
  !/[\s;,#\\)}\].]/.match?(char)
234
235
  end
235
236
 
237
+ def block_brace_with_no_space_style?(node, range)
238
+ return false unless (parent = node.parent)
239
+ return false unless parent.any_block_type? && parent.loc.begin&.begin_pos == range.end_pos
240
+
241
+ space_before_block_braces_config = config.for_cop('Layout/SpaceBeforeBlockBraces')
242
+ space_before_block_braces_config.fetch('Enabled', true) &&
243
+ space_before_block_braces_config['EnforcedStyle'] == 'no_space'
244
+ end
245
+
236
246
  def accepted_opening_delimiter?(range, char)
237
247
  return true unless char
238
248