rubocop 0.73.0 → 0.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/bin/console +1 -0
  4. data/config/default.yml +332 -295
  5. data/lib/rubocop.rb +46 -30
  6. data/lib/rubocop/ast/builder.rb +1 -0
  7. data/lib/rubocop/ast/node.rb +6 -8
  8. data/lib/rubocop/ast/node/block_node.rb +2 -0
  9. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +1 -12
  10. data/lib/rubocop/ast/node/return_node.rb +24 -0
  11. data/lib/rubocop/cli.rb +11 -227
  12. data/lib/rubocop/cli/command.rb +21 -0
  13. data/lib/rubocop/cli/command/auto_genenerate_config.rb +105 -0
  14. data/lib/rubocop/cli/command/base.rb +33 -0
  15. data/lib/rubocop/cli/command/execute_runner.rb +76 -0
  16. data/lib/rubocop/cli/command/init_dotfile.rb +45 -0
  17. data/lib/rubocop/cli/command/show_cops.rb +73 -0
  18. data/lib/rubocop/cli/command/version.rb +17 -0
  19. data/lib/rubocop/cli/environment.rb +21 -0
  20. data/lib/rubocop/comment_config.rb +5 -4
  21. data/lib/rubocop/config.rb +28 -537
  22. data/lib/rubocop/config_loader.rb +21 -3
  23. data/lib/rubocop/config_loader_resolver.rb +4 -3
  24. data/lib/rubocop/config_obsoletion.rb +275 -0
  25. data/lib/rubocop/config_validator.rb +246 -0
  26. data/lib/rubocop/cop/autocorrect_logic.rb +2 -2
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +4 -4
  28. data/lib/rubocop/cop/commissioner.rb +15 -7
  29. data/lib/rubocop/cop/cop.rb +33 -9
  30. data/lib/rubocop/cop/corrector.rb +8 -7
  31. data/lib/rubocop/cop/correctors/alignment_corrector.rb +43 -17
  32. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  33. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  34. data/lib/rubocop/cop/correctors/space_corrector.rb +1 -2
  35. data/lib/rubocop/cop/generator.rb +3 -3
  36. data/lib/rubocop/cop/generator/configuration_injector.rb +9 -4
  37. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  38. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  39. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +59 -0
  40. data/lib/rubocop/cop/layout/{align_arguments.rb → argument_alignment.rb} +1 -1
  41. data/lib/rubocop/cop/layout/{align_array.rb → array_alignment.rb} +1 -1
  42. data/lib/rubocop/cop/layout/{indent_assignment.rb → assignment_indentation.rb} +11 -2
  43. data/lib/rubocop/cop/layout/block_alignment.rb +2 -2
  44. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  45. data/lib/rubocop/cop/layout/comment_indentation.rb +10 -13
  46. data/lib/rubocop/cop/layout/empty_comment.rb +7 -16
  47. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +22 -7
  48. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +2 -2
  49. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +2 -2
  50. data/lib/rubocop/cop/layout/end_of_line.rb +8 -3
  51. data/lib/rubocop/cop/layout/extra_spacing.rb +15 -60
  52. data/lib/rubocop/cop/layout/{indent_first_argument.rb → first_argument_indentation.rb} +12 -10
  53. data/lib/rubocop/cop/layout/{indent_first_array_element.rb → first_array_element_indentation.rb} +4 -4
  54. data/lib/rubocop/cop/layout/{indent_first_hash_element.rb → first_hash_element_indentation.rb} +4 -4
  55. data/lib/rubocop/cop/layout/{indent_first_parameter.rb → first_parameter_indentation.rb} +3 -3
  56. data/lib/rubocop/cop/layout/{align_hash.rb → hash_alignment.rb} +8 -4
  57. data/lib/rubocop/cop/layout/{indent_heredoc.rb → heredoc_indentation.rb} +2 -2
  58. data/lib/rubocop/cop/layout/indentation_width.rb +19 -5
  59. data/lib/rubocop/cop/layout/{leading_blank_lines.rb → leading_empty_lines.rb} +1 -1
  60. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  61. data/lib/rubocop/cop/layout/multiline_block_layout.rb +24 -2
  62. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -1
  63. data/lib/rubocop/cop/layout/{align_parameters.rb → parameter_alignment.rb} +1 -1
  64. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -0
  65. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +5 -1
  66. data/lib/rubocop/cop/layout/space_around_keyword.rb +12 -0
  67. data/lib/rubocop/cop/layout/space_around_operators.rb +43 -24
  68. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -7
  69. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +8 -5
  70. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +7 -0
  71. data/lib/rubocop/cop/layout/space_inside_parens.rb +6 -6
  72. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +24 -40
  73. data/lib/rubocop/cop/layout/{trailing_blank_lines.rb → trailing_empty_lines.rb} +1 -1
  74. data/lib/rubocop/cop/layout/trailing_whitespace.rb +18 -2
  75. data/lib/rubocop/cop/lint/assignment_in_condition.rb +17 -4
  76. data/lib/rubocop/cop/lint/debugger.rb +1 -3
  77. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +1 -1
  78. data/lib/rubocop/cop/lint/{duplicated_key.rb → duplicate_hash_key.rb} +1 -1
  79. data/lib/rubocop/cop/lint/empty_interpolation.rb +4 -4
  80. data/lib/rubocop/cop/lint/erb_new_arguments.rb +61 -4
  81. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +10 -36
  82. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  83. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -8
  84. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +2 -2
  85. data/lib/rubocop/cop/lint/{multiple_compare.rb → multiple_comparison.rb} +1 -1
  86. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  87. data/lib/rubocop/cop/lint/{unneeded_cop_disable_directive.rb → redundant_cop_disable_directive.rb} +24 -24
  88. data/lib/rubocop/cop/lint/{unneeded_cop_enable_directive.rb → redundant_cop_enable_directive.rb} +6 -8
  89. data/lib/rubocop/cop/lint/{unneeded_require_statement.rb → redundant_require_statement.rb} +1 -1
  90. data/lib/rubocop/cop/lint/{unneeded_splat_expansion.rb → redundant_splat_expansion.rb} +12 -7
  91. data/lib/rubocop/cop/lint/{string_conversion_in_interpolation.rb → redundant_string_coercion.rb} +7 -7
  92. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
  93. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  94. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +5 -6
  95. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +91 -0
  96. data/lib/rubocop/cop/lint/{handle_exceptions.rb → suppressed_exception.rb} +1 -1
  97. data/lib/rubocop/cop/lint/unused_block_argument.rb +22 -6
  98. data/lib/rubocop/cop/lint/unused_method_argument.rb +23 -5
  99. data/lib/rubocop/cop/lint/useless_access_modifier.rb +57 -23
  100. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  101. data/lib/rubocop/cop/lint/void.rb +7 -26
  102. data/lib/rubocop/cop/message_annotator.rb +16 -7
  103. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  104. data/lib/rubocop/cop/metrics/line_length.rb +48 -42
  105. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  106. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +23 -6
  107. data/lib/rubocop/cop/migration/department_name.rb +44 -0
  108. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  109. data/lib/rubocop/cop/mixin/documentation_comment.rb +0 -2
  110. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  111. data/lib/rubocop/cop/mixin/{hash_alignment.rb → hash_alignment_styles.rb} +1 -1
  112. data/lib/rubocop/cop/mixin/interpolation.rb +27 -0
  113. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  114. data/lib/rubocop/cop/mixin/nil_methods.rb +4 -4
  115. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +87 -0
  116. data/lib/rubocop/cop/mixin/statement_modifier.rb +5 -2
  117. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -5
  118. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -6
  119. data/lib/rubocop/cop/naming/{uncommunicative_block_param_name.rb → block_parameter_name.rb} +3 -3
  120. data/lib/rubocop/cop/naming/file_name.rb +12 -5
  121. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -5
  122. data/lib/rubocop/cop/naming/method_name.rb +12 -1
  123. data/lib/rubocop/cop/naming/{uncommunicative_method_param_name.rb → method_parameter_name.rb} +3 -3
  124. data/lib/rubocop/cop/naming/predicate_name.rb +6 -6
  125. data/lib/rubocop/cop/naming/variable_name.rb +1 -0
  126. data/lib/rubocop/cop/offense.rb +18 -7
  127. data/lib/rubocop/cop/registry.rb +22 -1
  128. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -0
  129. data/lib/rubocop/cop/style/alias.rb +1 -1
  130. data/lib/rubocop/cop/style/array_join.rb +1 -1
  131. data/lib/rubocop/cop/style/attr.rb +2 -2
  132. data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
  133. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +35 -16
  134. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  135. data/lib/rubocop/cop/style/comment_annotation.rb +5 -5
  136. data/lib/rubocop/cop/style/commented_keyword.rb +16 -30
  137. data/lib/rubocop/cop/style/conditional_assignment.rb +5 -7
  138. data/lib/rubocop/cop/style/constant_visibility.rb +13 -2
  139. data/lib/rubocop/cop/style/copyright.rb +11 -7
  140. data/lib/rubocop/cop/style/documentation_method.rb +44 -0
  141. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +10 -4
  142. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
  143. data/lib/rubocop/cop/style/empty_literal.rb +2 -2
  144. data/lib/rubocop/cop/style/empty_method.rb +5 -5
  145. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  146. data/lib/rubocop/cop/style/even_odd.rb +1 -1
  147. data/lib/rubocop/cop/style/expand_path_arguments.rb +1 -1
  148. data/lib/rubocop/cop/style/format_string.rb +10 -7
  149. data/lib/rubocop/cop/style/format_string_token.rb +19 -68
  150. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +28 -33
  151. data/lib/rubocop/cop/style/guard_clause.rb +39 -10
  152. data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
  153. data/lib/rubocop/cop/style/if_unless_modifier.rb +58 -15
  154. data/lib/rubocop/cop/style/infinite_loop.rb +5 -4
  155. data/lib/rubocop/cop/style/inverse_methods.rb +19 -13
  156. data/lib/rubocop/cop/style/ip_addresses.rb +4 -4
  157. data/lib/rubocop/cop/style/lambda.rb +0 -2
  158. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -10
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -25
  160. data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -9
  161. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  162. data/lib/rubocop/cop/style/mixin_usage.rb +11 -1
  163. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  164. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  165. data/lib/rubocop/cop/style/nested_modifier.rb +22 -4
  166. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +5 -5
  167. data/lib/rubocop/cop/style/next.rb +5 -5
  168. data/lib/rubocop/cop/style/non_nil_check.rb +21 -9
  169. data/lib/rubocop/cop/style/numeric_literals.rb +7 -3
  170. data/lib/rubocop/cop/style/option_hash.rb +3 -3
  171. data/lib/rubocop/cop/style/or_assignment.rb +6 -1
  172. data/lib/rubocop/cop/style/parentheses_around_condition.rb +14 -0
  173. data/lib/rubocop/cop/style/{unneeded_capital_w.rb → redundant_capital_w.rb} +1 -1
  174. data/lib/rubocop/cop/style/{unneeded_condition.rb → redundant_condition.rb} +3 -3
  175. data/lib/rubocop/cop/style/{unneeded_interpolation.rb → redundant_interpolation.rb} +1 -1
  176. data/lib/rubocop/cop/style/redundant_parentheses.rb +16 -7
  177. data/lib/rubocop/cop/style/{unneeded_percent_q.rb → redundant_percent_q.rb} +1 -1
  178. data/lib/rubocop/cop/style/redundant_return.rb +39 -29
  179. data/lib/rubocop/cop/style/redundant_self.rb +18 -1
  180. data/lib/rubocop/cop/style/{unneeded_sort.rb → redundant_sort.rb} +5 -5
  181. data/lib/rubocop/cop/style/rescue_modifier.rb +24 -0
  182. data/lib/rubocop/cop/style/safe_navigation.rb +23 -3
  183. data/lib/rubocop/cop/style/semicolon.rb +13 -2
  184. data/lib/rubocop/cop/style/single_line_methods.rb +8 -1
  185. data/lib/rubocop/cop/style/special_global_vars.rb +5 -7
  186. data/lib/rubocop/cop/style/ternary_parentheses.rb +19 -0
  187. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +4 -6
  188. data/lib/rubocop/cop/style/trivial_accessors.rb +5 -5
  189. data/lib/rubocop/cop/style/variable_interpolation.rb +6 -16
  190. data/lib/rubocop/cop/team.rb +5 -0
  191. data/lib/rubocop/cop/util.rb +1 -1
  192. data/lib/rubocop/cop/utils/format_string.rb +120 -0
  193. data/lib/rubocop/cop/variable_force.rb +7 -5
  194. data/lib/rubocop/cop/variable_force/variable.rb +15 -2
  195. data/lib/rubocop/core_ext/string.rb +0 -24
  196. data/lib/rubocop/formatter/clang_style_formatter.rb +9 -6
  197. data/lib/rubocop/formatter/emacs_style_formatter.rb +22 -9
  198. data/lib/rubocop/formatter/file_list_formatter.rb +1 -1
  199. data/lib/rubocop/formatter/formatter_set.rb +16 -15
  200. data/lib/rubocop/formatter/pacman_formatter.rb +80 -0
  201. data/lib/rubocop/formatter/simple_text_formatter.rb +16 -4
  202. data/lib/rubocop/formatter/tap_formatter.rb +18 -7
  203. data/lib/rubocop/magic_comment.rb +4 -0
  204. data/lib/rubocop/node_pattern.rb +3 -1
  205. data/lib/rubocop/options.rb +17 -22
  206. data/lib/rubocop/path_util.rb +1 -1
  207. data/lib/rubocop/processed_source.rb +5 -1
  208. data/lib/rubocop/rake_task.rb +1 -0
  209. data/lib/rubocop/result_cache.rb +22 -8
  210. data/lib/rubocop/rspec/expect_offense.rb +4 -1
  211. data/lib/rubocop/runner.rb +55 -32
  212. data/lib/rubocop/target_finder.rb +12 -6
  213. data/lib/rubocop/version.rb +1 -1
  214. metadata +47 -32
  215. data/lib/rubocop/cop/mixin/ignored_method_patterns.rb +0 -19
  216. data/lib/rubocop/cop/mixin/safe_mode.rb +0 -22
@@ -48,9 +48,7 @@ module RuboCop
48
48
  if style == :require_space
49
49
  corrector.insert_before(children[1].source_range, ' ')
50
50
  else
51
- space_range = range_between(children[0].source_range.end_pos,
52
- children[1].source_range.begin_pos)
53
- corrector.remove(space_range)
51
+ corrector.remove(space_after_arrow(lambda_node))
54
52
  end
55
53
  end
56
54
  end
@@ -62,10 +60,14 @@ module RuboCop
62
60
  end
63
61
 
64
62
  def space_after_arrow?(lambda_node)
65
- arrow = lambda_node.parent.children[0]
66
- parentheses = lambda_node.parent.children[1]
67
- (parentheses.source_range.begin_pos - arrow.source_range.end_pos)
68
- .positive?
63
+ !space_after_arrow(lambda_node).empty?
64
+ end
65
+
66
+ def space_after_arrow(lambda_node)
67
+ arrow = lambda_node.parent.children[0].source_range
68
+ parentheses = lambda_node.parent.children[1].source_range
69
+
70
+ arrow.end.join(parentheses.begin)
69
71
  end
70
72
 
71
73
  def range_of_offense(node)
@@ -132,7 +132,7 @@ module RuboCop
132
132
  line, col = line_and_column_for(token)
133
133
  return true if col == -1
134
134
 
135
- processed_source.lines[line][0..col].delete(' ').empty?
135
+ processed_source.lines[line][0..col] !~ /\S/
136
136
  end
137
137
 
138
138
  def index_for(node, token)
@@ -210,18 +210,21 @@ module RuboCop
210
210
 
211
211
  def compact_corrections(corrector, node, left, right)
212
212
  if qualifies_for_compact?(node, left, side: :left)
213
- range = side_space_range(range: left.pos, side: :right)
214
- corrector.remove(range)
213
+ compact(corrector, left, :right)
215
214
  elsif !left.space_after?
216
215
  corrector.insert_after(left.pos, ' ')
217
216
  end
218
217
  if qualifies_for_compact?(node, right)
219
- range = side_space_range(range: right.pos, side: :left)
220
- corrector.remove(range)
218
+ compact(corrector, right, :left)
221
219
  elsif !right.space_before?
222
220
  corrector.insert_before(right.pos, ' ')
223
221
  end
224
222
  end
223
+
224
+ def compact(corrector, bracket, side)
225
+ range = side_space_range(range: bracket.pos, side: side)
226
+ corrector.remove(range)
227
+ end
225
228
  end
226
229
  end
227
230
  end
@@ -84,6 +84,13 @@ module RuboCop
84
84
  def on_block(node)
85
85
  return if node.keywords?
86
86
 
87
+ # Do not register an offense for multi-line empty braces. That means
88
+ # preventing auto-correction to single-line empty braces. It will
89
+ # conflict with auto-correction by `Layout/SpaceInsideBlockBraces` cop
90
+ # if auto-corrected to a single-line empty braces.
91
+ # See: https://github.com/rubocop-hq/rubocop/issues/7363
92
+ return if node.body.nil? && node.multiline?
93
+
87
94
  left_brace = node.loc.begin
88
95
  right_brace = node.loc.end
89
96
 
@@ -72,7 +72,7 @@ module RuboCop
72
72
  # If the second token is a comment, that means that a line break
73
73
  # follows, and that the rules for space inside don't apply.
74
74
  next if token2.comment?
75
- next unless token2.line == token1.line && token1.space_after?
75
+ next unless same_line?(token1, token2) && token1.space_after?
76
76
 
77
77
  yield range_between(token1.end_pos, token2.begin_pos)
78
78
  end
@@ -82,17 +82,18 @@ module RuboCop
82
82
  tokens.each_cons(2) do |token1, token2|
83
83
  next if can_be_ignored?(token1, token2)
84
84
 
85
- next unless token2.line == token1.line && !token1.space_after?
86
-
87
85
  if token1.left_parens?
88
86
  yield range_between(token2.begin_pos, token2.begin_pos + 1)
89
-
90
87
  elsif token2.right_parens?
91
88
  yield range_between(token2.begin_pos, token2.end_pos)
92
89
  end
93
90
  end
94
91
  end
95
92
 
93
+ def same_line?(token1, token2)
94
+ token1.line == token2.line
95
+ end
96
+
96
97
  def parens?(token1, token2)
97
98
  token1.left_parens? || token2.right_parens?
98
99
  end
@@ -104,8 +105,7 @@ module RuboCop
104
105
  # follows, and that the rules for space inside don't apply.
105
106
  return true if token2.comment?
106
107
 
107
- # Ignore empty parens. # TODO: Could be configurable.
108
- return true if token1.left_parens? && token2.right_parens?
108
+ return true unless same_line?(token1, token2) && !token1.space_after?
109
109
  end
110
110
  end
111
111
  end
@@ -19,61 +19,45 @@ module RuboCop
19
19
  # # good
20
20
  # var = "This is the #{ space } example"
21
21
  class SpaceInsideStringInterpolation < Cop
22
+ include Interpolation
23
+ include SurroundingSpace
22
24
  include ConfigurableEnforcedStyle
23
25
  include RangeHelp
24
26
 
25
27
  NO_SPACE_MSG = 'Space inside string interpolation detected.'
26
- SPACE_MSG = 'Missing space around string interpolation detected.'
28
+ SPACE_MSG = 'Missing space inside string interpolation detected.'
27
29
 
28
- def on_dstr(node)
29
- each_style_violation(node) do |final_node|
30
- add_offense(final_node)
31
- end
32
- end
30
+ def on_interpolation(begin_node)
31
+ return if begin_node.multiline?
33
32
 
34
- def autocorrect(node)
35
- new_source = style == :no_space ? node.source : " #{node.source} "
36
- lambda do |corrector|
37
- corrector.replace(
38
- range_with_surrounding_space(range: node.source_range),
39
- new_source
40
- )
33
+ delims = delimiters(begin_node)
34
+ return if empty_brackets?(*delims)
35
+
36
+ if style == :no_space
37
+ no_space_offenses(begin_node, *delims, NO_SPACE_MSG)
38
+ else
39
+ space_offenses(begin_node, *delims, SPACE_MSG)
41
40
  end
42
41
  end
43
42
 
44
- private
45
-
46
- def each_style_violation(node)
47
- node.each_child_node(:begin) do |begin_node|
48
- final_node = begin_node.children.last
49
- next unless final_node
43
+ def autocorrect(begin_node)
44
+ lambda do |corrector|
45
+ delims = delimiters(begin_node)
50
46
 
51
- if style == :no_space && space_on_any_side?(final_node)
52
- yield final_node
53
- elsif style == :space && !space_on_each_side?(final_node)
54
- yield final_node
47
+ if style == :no_space
48
+ SpaceCorrector.remove_space(processed_source, corrector, *delims)
49
+ else
50
+ SpaceCorrector.add_space(processed_source, corrector, *delims)
55
51
  end
56
52
  end
57
53
  end
58
54
 
59
- def message(_node)
60
- style == :no_space ? NO_SPACE_MSG : SPACE_MSG
61
- end
62
-
63
- def space_on_any_side?(node)
64
- interp = node.source_range
65
- interp_with_surrounding_space =
66
- range_with_surrounding_space(range: interp)
67
-
68
- interp_with_surrounding_space != interp
69
- end
70
-
71
- def space_on_each_side?(node)
72
- interp = node.source_range
73
- interp_with_surrounding_space =
74
- range_with_surrounding_space(range: interp)
55
+ private
75
56
 
76
- interp_with_surrounding_space.source == " #{interp.source} "
57
+ def delimiters(begin_node)
58
+ left = processed_source.tokens[index_of_first_token(begin_node)]
59
+ right = processed_source.tokens[index_of_last_token(begin_node)]
60
+ [left, right]
77
61
  end
78
62
  end
79
63
  end
@@ -37,7 +37,7 @@ module RuboCop
37
37
  # class Foo; end
38
38
  # # EOF
39
39
  #
40
- class TrailingBlankLines < Cop
40
+ class TrailingEmptyLines < Cop
41
41
  include ConfigurableEnforcedStyle
42
42
  include RangeHelp
43
43
 
@@ -14,6 +14,20 @@ module RuboCop
14
14
  # # good
15
15
  # x = 0
16
16
  #
17
+ # @example AllowInHeredoc: false (default)
18
+ # # The line in this example contains spaces after the 0.
19
+ # # bad
20
+ # code = <<~RUBY
21
+ # x = 0
22
+ # RUBY
23
+ #
24
+ # @example AllowInHeredoc: true
25
+ # # The line in this example contains spaces after the 0.
26
+ # # good
27
+ # code = <<~RUBY
28
+ # x = 0
29
+ # RUBY
30
+ #
17
31
  class TrailingWhitespace < Cop
18
32
  include RangeHelp
19
33
 
@@ -22,11 +36,13 @@ module RuboCop
22
36
  def investigate(processed_source)
23
37
  heredoc_ranges = extract_heredoc_ranges(processed_source.ast)
24
38
  processed_source.lines.each_with_index do |line, index|
39
+ lineno = index + 1
40
+
25
41
  next unless line.end_with?(' ', "\t")
26
- next if skip_heredoc? && inside_heredoc?(heredoc_ranges, index + 1)
42
+ next if skip_heredoc? && inside_heredoc?(heredoc_ranges, lineno)
27
43
 
28
44
  range = source_range(processed_source.buffer,
29
- index + 1,
45
+ lineno,
30
46
  (line.rstrip.length)...(line.length))
31
47
 
32
48
  add_offense(range, location: range)
@@ -6,21 +6,34 @@ module RuboCop
6
6
  # This cop checks for assignments in the conditions of
7
7
  # if/while/until.
8
8
  #
9
- # @example
9
+ # `AllowSafeAssignment` option for safe assignment.
10
+ # By safe assignment we mean putting parentheses around
11
+ # an assignment to indicate "I know I'm using an assignment
12
+ # as a condition. It's not a mistake."
10
13
  #
14
+ # @example
11
15
  # # bad
12
- #
13
16
  # if some_var = true
14
17
  # do_something
15
18
  # end
16
19
  #
17
- # @example
20
+ # # good
21
+ # if some_var == true
22
+ # do_something
23
+ # end
18
24
  #
25
+ # @example AllowSafeAssignment: true (default)
19
26
  # # good
27
+ # if (some_var = true)
28
+ # do_something
29
+ # end
20
30
  #
21
- # if some_var == true
31
+ # @example AllowSafeAssignment: false
32
+ # # bad
33
+ # if (some_var = true)
22
34
  # do_something
23
35
  # end
36
+ #
24
37
  class AssignmentInCondition < Cop
25
38
  include SafeAssignment
26
39
 
@@ -43,7 +43,7 @@ module RuboCop
43
43
  PATTERN
44
44
 
45
45
  def_node_matcher :debugger_call?, <<~PATTERN
46
- {(send {nil? #kernel?} {:debugger :byebug} ...)
46
+ {(send {nil? #kernel?} {:debugger :byebug :remote_byebug} ...)
47
47
  (send (send {#kernel? nil?} :binding)
48
48
  {:pry :remote_pry :pry_remote} ...)
49
49
  (send (const {nil? (cbase)} :Pry) :rescue ...)
@@ -56,8 +56,6 @@ module RuboCop
56
56
  (send (send {#kernel? nil?} :binding) :irb ...)
57
57
  PATTERN
58
58
 
59
- def_node_matcher :pry_rescue?, '(send (const nil? :Pry) :rescue ...)'
60
-
61
59
  def on_send(node)
62
60
  return unless debugger_call?(node) || binding_irb?(node)
63
61
 
@@ -33,7 +33,7 @@ module RuboCop
33
33
 
34
34
  # @param [DefNode] node a constructor definition
35
35
  def check(node)
36
- return unless node.method_name == :initialize
36
+ return unless node.method?(:initialize)
37
37
 
38
38
  check_body(node.body)
39
39
  end
@@ -18,7 +18,7 @@ module RuboCop
18
18
  # # good
19
19
  #
20
20
  # hash = { food: 'apple', other_food: 'orange' }
21
- class DuplicatedKey < Cop
21
+ class DuplicateHashKey < Cop
22
22
  include Duplication
23
23
 
24
24
  MSG = 'Duplicated key in hash literal.'
@@ -17,12 +17,12 @@ module RuboCop
17
17
  #
18
18
  # "result is #{some_result}"
19
19
  class EmptyInterpolation < Cop
20
+ include Interpolation
21
+
20
22
  MSG = 'Empty interpolation detected.'
21
23
 
22
- def on_dstr(node)
23
- node.each_child_node(:begin) do |begin_node|
24
- add_offense(begin_node) if begin_node.children.empty?
25
- end
24
+ def on_interpolation(begin_node)
25
+ add_offense(begin_node) if begin_node.children.empty?
26
26
  end
27
27
 
28
28
  def autocorrect(node)
@@ -61,6 +61,7 @@ module RuboCop
61
61
  #
62
62
  class ErbNewArguments < Cop
63
63
  extend TargetRubyVersion
64
+ include RangeHelp
64
65
 
65
66
  minimum_target_ruby_version 2.6
66
67
 
@@ -85,22 +86,78 @@ module RuboCop
85
86
  erb_new_with_non_keyword_arguments(node) do |arguments|
86
87
  return if correct_arguments?(arguments)
87
88
 
88
- 1.upto(3) do |i|
89
- next if !arguments[i] || arguments[i].hash_type?
89
+ arguments[1..3].each_with_index do |argument, i|
90
+ next if !argument || argument.hash_type?
90
91
 
91
- message = format(MESSAGES[i - 1], arg_value: arguments[i].source)
92
+ message = format(MESSAGES[i], arg_value: argument.source)
92
93
 
93
94
  add_offense(
94
- node, location: arguments[i].source_range, message: message
95
+ node, location: argument.source_range, message: message
95
96
  )
96
97
  end
97
98
  end
98
99
  end
99
100
 
101
+ def autocorrect(node)
102
+ str_arg = node.arguments[0].source
103
+
104
+ kwargs = build_kwargs(node)
105
+ overridden_kwargs = override_by_legacy_args(kwargs, node)
106
+
107
+ good_arguments = [
108
+ str_arg, overridden_kwargs
109
+ ].flatten.compact.join(', ')
110
+
111
+ lambda do |corrector|
112
+ corrector.replace(arguments_range(node), good_arguments)
113
+ end
114
+ end
115
+
116
+ private
117
+
100
118
  def correct_arguments?(arguments)
101
119
  arguments.size == 1 ||
102
120
  arguments.size == 2 && arguments[1].hash_type?
103
121
  end
122
+
123
+ def build_kwargs(node)
124
+ return [nil, nil] unless node.arguments.last.hash_type?
125
+
126
+ trim_mode_arg, eoutvar_arg = nil
127
+
128
+ node.arguments.last.pairs.each do |pair|
129
+ case pair.key.source
130
+ when 'trim_mode'
131
+ trim_mode_arg = "trim_mode: #{pair.value.source}"
132
+ when 'eoutvar'
133
+ eoutvar_arg = "eoutvar: #{pair.value.source}"
134
+ end
135
+ end
136
+
137
+ [trim_mode_arg, eoutvar_arg]
138
+ end
139
+
140
+ def override_by_legacy_args(kwargs, node)
141
+ arguments = node.arguments
142
+ overridden_kwargs = kwargs.dup
143
+
144
+ if arguments[2]
145
+ overridden_kwargs[0] = "trim_mode: #{arguments[2].source}"
146
+ end
147
+
148
+ if arguments[3] && !arguments[3].hash_type?
149
+ overridden_kwargs[1] = "eoutvar: #{arguments[3].source}"
150
+ end
151
+
152
+ overridden_kwargs
153
+ end
154
+
155
+ def arguments_range(node)
156
+ arguments = node.arguments
157
+
158
+ range_between(arguments.first.source_range.begin_pos,
159
+ arguments.last.source_range.end_pos)
160
+ end
104
161
  end
105
162
  end
106
163
  end
@@ -22,16 +22,10 @@ module RuboCop
22
22
  # http://rubular.com/r/CvpbxkcTzy
23
23
  MSG = "Number of arguments (%<arg_num>i) to `%<method>s` doesn't " \
24
24
  'match the number of fields (%<field_num>i).'
25
- FIELD_REGEX =
26
- /(%(([\s#+-0\*]*)(\d*)?(\.\d+)?[bBdiouxXeEfgGaAcps]|%))/.freeze
27
- NAMED_FIELD_REGEX = /%\{[_a-zA-Z][_a-zA-Z]+\}/.freeze
25
+
28
26
  KERNEL = 'Kernel'
29
27
  SHOVEL = '<<'
30
- PERCENT = '%'
31
- PERCENT_PERCENT = '%%'
32
- DIGIT_DOLLAR_FLAG = /%(\d+)\$/.freeze
33
28
  STRING_TYPES = %i[str dstr].freeze
34
- NAMED_INTERPOLATION = /%(?:<\w+>|\{\w+\})/.freeze
35
29
 
36
30
  def on_send(node)
37
31
  return unless offending_node?(node)
@@ -44,7 +38,7 @@ module RuboCop
44
38
  def offending_node?(node)
45
39
  return false unless called_on_string?(node)
46
40
  return false unless method_with_format_args?(node)
47
- return false if named_mode?(node) || splat_args?(node)
41
+ return false if splat_args?(node)
48
42
 
49
43
  num_of_format_args, num_of_expected_fields = count_matches(node)
50
44
 
@@ -70,16 +64,6 @@ module RuboCop
70
64
  sprintf?(node) || format?(node) || percent?(node)
71
65
  end
72
66
 
73
- def named_mode?(node)
74
- relevant_node = if sprintf?(node) || format?(node)
75
- node.first_argument
76
- elsif percent?(node)
77
- node.receiver
78
- end
79
-
80
- !relevant_node.source.scan(NAMED_FIELD_REGEX).empty?
81
- end
82
-
83
67
  def splat_args?(node)
84
68
  return false if percent?(node)
85
69
 
@@ -127,27 +111,17 @@ module RuboCop
127
111
 
128
112
  def expected_fields_count(node)
129
113
  return :unknown unless node.str_type?
130
- return 1 if node.source =~ NAMED_INTERPOLATION
131
114
 
132
- max_digit_dollar_num = max_digit_dollar_num(node)
133
- return max_digit_dollar_num if max_digit_dollar_num&.nonzero?
115
+ format_string = RuboCop::Cop::Utils::FormatString.new(node.source)
116
+ return 1 if format_string.named_interpolation?
134
117
 
135
- node
136
- .source
137
- .scan(FIELD_REGEX)
138
- .reject { |x| x.first == PERCENT_PERCENT }
139
- .reduce(0) { |acc, elem| acc + arguments_count(elem[2]) }
140
- end
141
-
142
- def max_digit_dollar_num(node)
143
- node.source.scan(DIGIT_DOLLAR_FLAG).map do |digit_dollar_num|
144
- digit_dollar_num.first.to_i
145
- end.max
146
- end
118
+ max_digit_dollar_num = format_string.max_digit_dollar_num
119
+ return max_digit_dollar_num if max_digit_dollar_num&.nonzero?
147
120
 
148
- # number of arguments required for the format sequence
149
- def arguments_count(format)
150
- format.scan('*').count + 1
121
+ format_string
122
+ .format_sequences
123
+ .reject(&:percent?)
124
+ .reduce(0) { |acc, seq| acc + seq.arity }
151
125
  end
152
126
 
153
127
  def format?(node)