rubocop 1.57.2 → 1.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +87 -15
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
  8. data/lib/rubocop/cli/command/lsp.rb +2 -2
  9. data/lib/rubocop/cli.rb +6 -1
  10. data/lib/rubocop/config.rb +4 -2
  11. data/lib/rubocop/config_finder.rb +12 -2
  12. data/lib/rubocop/config_loader.rb +0 -1
  13. data/lib/rubocop/config_obsoletion.rb +11 -8
  14. data/lib/rubocop/config_validator.rb +14 -7
  15. data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
  16. data/lib/rubocop/cop/base.rb +17 -2
  17. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  18. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  19. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  20. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  21. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  22. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  23. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -4
  24. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  25. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  26. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  27. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +123 -29
  28. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  29. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  31. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  32. data/lib/rubocop/cop/layout/end_alignment.rb +8 -2
  33. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  34. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  35. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  37. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
  39. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -3
  40. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  41. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  42. data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
  43. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  44. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  45. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  46. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  47. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  48. data/lib/rubocop/cop/lint/debugger.rb +2 -1
  49. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  50. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  51. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
  52. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  53. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  54. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  55. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  56. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  57. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  58. data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
  59. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +54 -6
  60. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
  61. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  62. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  63. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
  64. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  65. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  66. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  67. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  68. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  69. data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
  70. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  71. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  72. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  73. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  74. data/lib/rubocop/cop/lint/void.rb +20 -2
  75. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  76. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  77. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  78. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  79. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  80. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  81. data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
  82. data/lib/rubocop/cop/naming/constant_name.rb +1 -2
  83. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  84. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  85. data/lib/rubocop/cop/registry.rb +1 -1
  86. data/lib/rubocop/cop/security/open.rb +2 -2
  87. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  88. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  89. data/lib/rubocop/cop/style/arguments_forwarding.rb +152 -21
  90. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  91. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  92. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  93. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  94. data/lib/rubocop/cop/style/class_check.rb +1 -0
  95. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  96. data/lib/rubocop/cop/style/collection_compact.rb +18 -8
  97. data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
  98. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  99. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
  100. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -7
  101. data/lib/rubocop/cop/style/date_time.rb +5 -4
  102. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  103. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  104. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  105. data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
  106. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  107. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  108. data/lib/rubocop/cop/style/for.rb +2 -0
  109. data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
  110. data/lib/rubocop/cop/style/hash_except.rb +2 -1
  111. data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
  112. data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
  113. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  114. data/lib/rubocop/cop/style/invertible_unless_condition.rb +44 -2
  115. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  116. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  117. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
  118. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  119. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  120. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  121. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  122. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  123. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
  124. data/lib/rubocop/cop/style/next.rb +1 -1
  125. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  126. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  127. data/lib/rubocop/cop/style/object_then.rb +5 -3
  128. data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
  129. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  130. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  131. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  132. data/lib/rubocop/cop/style/redundant_argument.rb +4 -3
  133. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  134. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +4 -3
  135. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
  136. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  137. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  138. data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -7
  139. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -10
  140. data/lib/rubocop/cop/style/redundant_return.rb +7 -1
  141. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  142. data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
  143. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  144. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  145. data/lib/rubocop/cop/style/sample.rb +3 -4
  146. data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
  147. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  148. data/lib/rubocop/cop/style/semicolon.rb +8 -0
  149. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -2
  150. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  151. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  152. data/lib/rubocop/cop/style/strip.rb +7 -4
  153. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  154. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  155. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  156. data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
  157. data/lib/rubocop/cops_documentation_generator.rb +15 -3
  158. data/lib/rubocop/directive_comment.rb +10 -8
  159. data/lib/rubocop/ext/regexp_node.rb +9 -4
  160. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  161. data/lib/rubocop/formatter/html_formatter.rb +31 -12
  162. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  163. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  164. data/lib/rubocop/formatter.rb +1 -1
  165. data/lib/rubocop/lsp/logger.rb +1 -1
  166. data/lib/rubocop/lsp/routes.rb +2 -2
  167. data/lib/rubocop/lsp/runtime.rb +1 -1
  168. data/lib/rubocop/lsp/server.rb +5 -2
  169. data/lib/rubocop/lsp/severity.rb +1 -1
  170. data/lib/rubocop/lsp.rb +29 -0
  171. data/lib/rubocop/magic_comment.rb +1 -1
  172. data/lib/rubocop/options.rb +11 -8
  173. data/lib/rubocop/path_util.rb +6 -2
  174. data/lib/rubocop/result_cache.rb +0 -1
  175. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  176. data/lib/rubocop/rspec/expect_offense.rb +8 -8
  177. data/lib/rubocop/rspec/shared_contexts.rb +40 -15
  178. data/lib/rubocop/rspec/support.rb +2 -0
  179. data/lib/rubocop/runner.rb +10 -3
  180. data/lib/rubocop/server/cache.rb +1 -2
  181. data/lib/rubocop/server/client_command/exec.rb +0 -1
  182. data/lib/rubocop/server/server_command/exec.rb +0 -1
  183. data/lib/rubocop/target_finder.rb +84 -78
  184. data/lib/rubocop/target_ruby.rb +82 -80
  185. data/lib/rubocop/version.rb +18 -3
  186. data/lib/rubocop.rb +4 -0
  187. metadata +18 -10
  188. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -26,10 +26,18 @@ module RuboCop
26
26
  MSG = 'Precede `%<method>s` with a `@!method` YARD directive.'
27
27
  MSG_WRONG_NAME = '`@!method` YARD directive has invalid method name, ' \
28
28
  'use `%<expected>s` instead of `%<actual>s`.'
29
+ MSG_MISSING_SCOPE_SELF = 'Follow the `@!method` YARD directive with ' \
30
+ '`@!scope class` if it is a class method.'
31
+ MSG_WRONG_SCOPE_SELF = 'Do not use the `@!scope class` YARD directive if it ' \
32
+ 'is not a class method.'
29
33
  MSG_TOO_MANY = 'Multiple `@!method` YARD directives found for this matcher.'
30
34
 
31
35
  RESTRICT_ON_SEND = %i[def_node_matcher def_node_search].to_set.freeze
32
- REGEXP = /^\s*#\s*@!method\s+(?<method_name>[a-z0-9_]+[?!]?)(?:\((?<args>.*)\))?/.freeze
36
+ REGEXP_METHOD = /
37
+ ^\s*\#\s*
38
+ @!method\s+(?<receiver>self\.)?(?<method_name>[a-z0-9_]+[?!]?)(?:\((?<args>.*)\))?
39
+ /x.freeze
40
+ REGEXP_SCOPE = /^\s*\#\s*@!scope class/.freeze
33
41
 
34
42
  # @!method pattern_matcher?(node)
35
43
  def_node_matcher :pattern_matcher?, <<~PATTERN
@@ -40,62 +48,131 @@ module RuboCop
40
48
  return if node.arguments.none?
41
49
  return unless valid_method_name?(node)
42
50
 
43
- actual_name = node.arguments.first.value
51
+ actual_name = node.first_argument.value.to_s
52
+
53
+ # Ignore cases where the method has a receiver that isn't self
54
+ return if actual_name.include?('.') && !actual_name.start_with?('self.')
55
+
44
56
  directives = method_directives(node)
45
57
  return too_many_directives(node) if directives.size > 1
46
58
 
47
- directive = directives.first
48
- return if directive_correct?(directive, actual_name)
49
-
50
- register_offense(node, directive, actual_name)
59
+ process_directive(node, actual_name, directives.first)
51
60
  end
52
61
 
53
62
  private
54
63
 
55
64
  def valid_method_name?(node)
56
- node.arguments.first.str_type? || node.arguments.first.sym_type?
65
+ node.first_argument.str_type? || node.first_argument.sym_type?
57
66
  end
58
67
 
59
68
  def method_directives(node)
60
69
  comments = processed_source.ast_with_comments[node]
61
-
62
- comments.filter_map do |comment|
63
- match = comment.text.match(REGEXP)
70
+ group_comments(comments).filter_map do |comment_method, comment_scope|
71
+ match = comment_method.text.match(REGEXP_METHOD)
64
72
  next unless match
65
73
 
66
- { node: comment, method_name: match[:method_name], args: match[:args] }
74
+ {
75
+ node_method: comment_method,
76
+ node_scope: comment_scope,
77
+ method_name: match[:method_name],
78
+ args: match[:args],
79
+ receiver: match[:receiver],
80
+ has_scope_directive: comment_scope&.text&.match?(REGEXP_SCOPE)
81
+ }
82
+ end
83
+ end
84
+
85
+ def group_comments(comments)
86
+ result = []
87
+ comments.each.with_index do |comment, index|
88
+ # Grab the scope directive if it is preceded by a method directive
89
+ if comment.text.include?('@!method')
90
+ result << if (next_comment = comments[index + 1])&.text&.include?('@!scope')
91
+ [comment, next_comment]
92
+ else
93
+ [comment, nil]
94
+ end
95
+ end
67
96
  end
97
+ result
68
98
  end
69
99
 
70
100
  def too_many_directives(node)
71
101
  add_offense(node, message: MSG_TOO_MANY)
72
102
  end
73
103
 
74
- def directive_correct?(directive, actual_name)
75
- directive && directive[:method_name] == actual_name.to_s
104
+ def process_directive(node, actual_name, directive)
105
+ return unless (offense_type = directive_offense_type(directive, actual_name))
106
+
107
+ register_offense(offense_type, node, directive, actual_name)
108
+ end
109
+
110
+ def directive_offense_type(directive, actual_name)
111
+ return :missing_directive unless directive
112
+
113
+ return :wrong_scope if wrong_scope(directive, actual_name)
114
+ return :no_scope if no_scope(directive, actual_name)
115
+
116
+ # The method directive being prefixed by 'self.' is always an offense.
117
+ # The matched method_name does not contain the receiver but the
118
+ # def_node_match method name may so it must be removed.
119
+ if directive[:method_name] != remove_receiver(actual_name) || directive[:receiver]
120
+ :wrong_name
121
+ end
122
+ end
123
+
124
+ def wrong_scope(directive, actual_name)
125
+ !actual_name.start_with?('self.') && directive[:has_scope_directive]
126
+ end
127
+
128
+ def no_scope(directive, actual_name)
129
+ actual_name.start_with?('self.') && !directive[:has_scope_directive]
76
130
  end
77
131
 
78
- def register_offense(node, directive, actual_name)
79
- message = formatted_message(directive, actual_name, node.method_name)
132
+ def register_offense(offense_type, node, directive, actual_name)
133
+ message = formatted_message(offense_type, directive, actual_name, node.method_name)
80
134
 
81
135
  add_offense(node, message: message) do |corrector|
82
- if directive
83
- correct_directive(corrector, directive, actual_name)
84
- else
85
- insert_directive(corrector, node, actual_name)
136
+ case offense_type
137
+ when :wrong_name
138
+ correct_method_directive(corrector, directive, actual_name)
139
+ when :wrong_scope
140
+ remove_scope_directive(corrector, directive)
141
+ when :no_scope
142
+ insert_scope_directive(corrector, directive[:node_method])
143
+ when :missing_directive
144
+ insert_method_directive(corrector, node, actual_name)
86
145
  end
87
146
  end
88
147
  end
89
148
 
90
- def formatted_message(directive, actual_name, method_name)
91
- if directive
92
- format(MSG_WRONG_NAME, expected: actual_name, actual: directive[:method_name])
93
- else
149
+ # rubocop:disable Metrics/MethodLength
150
+ def formatted_message(offense_type, directive, actual_name, method_name)
151
+ case offense_type
152
+ when :wrong_name
153
+ # Add the receiver to the name when showing an offense
154
+ current_name = if directive[:receiver]
155
+ directive[:receiver] + directive[:method_name]
156
+ else
157
+ directive[:method_name]
158
+ end
159
+ # The correct name will never include a receiver, remove it
160
+ format(MSG_WRONG_NAME, expected: remove_receiver(actual_name), actual: current_name)
161
+ when :wrong_scope
162
+ MSG_WRONG_SCOPE_SELF
163
+ when :no_scope
164
+ MSG_MISSING_SCOPE_SELF
165
+ when :missing_directive
94
166
  format(MSG, method: method_name)
95
167
  end
96
168
  end
169
+ # rubocop:enable Metrics/MethodLength
170
+
171
+ def remove_receiver(current)
172
+ current.delete_prefix('self.')
173
+ end
97
174
 
98
- def insert_directive(corrector, node, actual_name)
175
+ def insert_method_directive(corrector, node, actual_name)
99
176
  # If the pattern matcher uses arguments (`%1`, `%2`, etc.), include them in the directive
100
177
  arguments = pattern_arguments(node.arguments[1].source)
101
178
 
@@ -107,6 +184,14 @@ module RuboCop
107
184
  corrector.insert_before(range, directive)
108
185
  end
109
186
 
187
+ def insert_scope_directive(corrector, node)
188
+ range = range_with_surrounding_space(node.source_range, side: :left, newlines: false)
189
+ indentation = range.source.match(/^\s*/)[0]
190
+ directive = "\n#{indentation}# @!scope class"
191
+
192
+ corrector.insert_after(node, directive)
193
+ end
194
+
110
195
  def pattern_arguments(pattern)
111
196
  arguments = %w[node]
112
197
  max_pattern_var = pattern.scan(/(?<=%)\d+/).map(&:to_i).max
@@ -134,12 +219,21 @@ module RuboCop
134
219
  end
135
220
  end
136
221
 
137
- def correct_directive(corrector, directive, actual_name)
138
- correct = "@!method #{actual_name}"
139
- regexp = /@!method\s+#{Regexp.escape(directive[:method_name])}/
222
+ def correct_method_directive(corrector, directive, actual_name)
223
+ correct = "@!method #{remove_receiver(actual_name)}"
224
+ current_name = (directive[:receiver] || '') + directive[:method_name]
225
+ regexp = /@!method\s+#{Regexp.escape(current_name)}/
226
+
227
+ replacement = directive[:node_method].text.gsub(regexp, correct)
228
+ corrector.replace(directive[:node_method], replacement)
229
+ end
140
230
 
141
- replacement = directive[:node].text.gsub(regexp, correct)
142
- corrector.replace(directive[:node], replacement)
231
+ def remove_scope_directive(corrector, directive)
232
+ range = range_by_whole_lines(
233
+ directive[:node_scope].source_range,
234
+ include_final_newline: true
235
+ )
236
+ corrector.remove(range)
143
237
  end
144
238
  end
145
239
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for redundant arguments of `RuboCop::RSpec::ExpectOffense`'s methods.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # expect_no_offenses('code', keyword: keyword)
12
+ #
13
+ # # good
14
+ # expect_no_offenses('code')
15
+ #
16
+ class RedundantExpectOffenseArguments < Base
17
+ extend AutoCorrector
18
+
19
+ MSG = 'Remove the redundant arguments.'
20
+ RESTRICT_ON_SEND = %i[expect_no_offenses].freeze
21
+
22
+ def on_send(node)
23
+ return if node.arguments.one? || !node.arguments[1]&.hash_type?
24
+
25
+ range = node.first_argument.source_range.end.join(node.last_argument.source_range.end)
26
+
27
+ add_offense(range) do |corrector|
28
+ corrector.remove(range)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -12,6 +12,7 @@ require_relative 'internal_affairs/location_line_equality_comparison'
12
12
  require_relative 'internal_affairs/method_name_end_with'
13
13
  require_relative 'internal_affairs/method_name_equal'
14
14
  require_relative 'internal_affairs/node_destructuring'
15
+ require_relative 'internal_affairs/node_first_or_last_argument'
15
16
  require_relative 'internal_affairs/node_matcher_directive'
16
17
  require_relative 'internal_affairs/node_type_predicate'
17
18
  require_relative 'internal_affairs/numblock_handler'
@@ -19,6 +20,7 @@ require_relative 'internal_affairs/offense_location_keyword'
19
20
  require_relative 'internal_affairs/processed_source_buffer_name'
20
21
  require_relative 'internal_affairs/redundant_context_config_parameter'
21
22
  require_relative 'internal_affairs/redundant_described_class_as_subject'
23
+ require_relative 'internal_affairs/redundant_expect_offense_arguments'
22
24
  require_relative 'internal_affairs/redundant_let_rubocop_config_new'
23
25
  require_relative 'internal_affairs/redundant_location_argument'
24
26
  require_relative 'internal_affairs/redundant_message_argument'
@@ -79,7 +79,7 @@ module RuboCop
79
79
 
80
80
  def arguments_with_last_arg_pairs(node)
81
81
  items = node.arguments[0..-2]
82
- last_arg = node.arguments.last
82
+ last_arg = node.last_argument
83
83
 
84
84
  if last_arg.hash_type? && !last_arg.braces?
85
85
  items += last_arg.pairs
@@ -27,9 +27,9 @@ module RuboCop
27
27
  MSG = 'Add an empty line after magic comments.'
28
28
 
29
29
  def on_new_investigation
30
- return unless processed_source.ast &&
31
- (last_magic_comment = last_magic_comment(processed_source))
32
- return if processed_source[last_magic_comment.loc.line].strip.empty?
30
+ return unless (last_magic_comment = last_magic_comment(processed_source))
31
+ return unless (next_line = processed_source[last_magic_comment.loc.line])
32
+ return if next_line.strip.empty?
33
33
 
34
34
  offending_range = offending_range(last_magic_comment)
35
35
 
@@ -46,18 +46,25 @@ module RuboCop
46
46
 
47
47
  # Find the last magic comment in the source file.
48
48
  #
49
- # Take all comments that precede the first line of code, select the
49
+ # Take all comments that precede the first line of code (or just take
50
+ # them all in the case when there is no code), select the
50
51
  # magic comments, and return the last magic comment in the file.
51
52
  #
52
53
  # @return [Parser::Source::Comment] if magic comments exist before code
53
54
  # @return [nil] otherwise
54
55
  def last_magic_comment(source)
55
- source
56
- .comments
57
- .take_while { |comment| comment.loc.line < source.ast.loc.line }
56
+ comments_before_code(source)
58
57
  .reverse
59
58
  .find { |comment| MagicComment.parse(comment.text).any? }
60
59
  end
60
+
61
+ def comments_before_code(source)
62
+ if source.ast
63
+ source.comments.take_while { |comment| comment.loc.line < source.ast.loc.line }
64
+ else
65
+ source.comments
66
+ end
67
+ end
61
68
  end
62
69
  end
63
70
  end
@@ -20,7 +20,9 @@ module RuboCop
20
20
  # This `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`)
21
21
  # by default. On the other hand, `Layout/BeginEndAlignment` cop aligns with
22
22
  # `EnforcedStyleAlignWith: start_of_line` by default due to `||= begin` tends
23
- # to align with the start of the line. These style can be configured by each cop.
23
+ # to align with the start of the line. `Layout/DefEndAlignment` cop also aligns with
24
+ # `EnforcedStyleAlignWith: start_of_line` by default.
25
+ # These style can be configured by each cop.
24
26
  #
25
27
  # @example EnforcedStyleAlignWith: keyword (default)
26
28
  # # bad
@@ -83,7 +85,11 @@ module RuboCop
83
85
  end
84
86
 
85
87
  def on_sclass(node)
86
- check_other_alignment(node)
88
+ if node.parent&.assignment?
89
+ check_asgn_alignment(node.parent, node)
90
+ else
91
+ check_other_alignment(node)
92
+ end
87
93
  end
88
94
 
89
95
  def on_module(node)
@@ -49,19 +49,13 @@ module RuboCop
49
49
 
50
50
  private
51
51
 
52
- def aligned_locations(locs) # rubocop:disable Metrics/AbcSize
52
+ def aligned_locations(locs)
53
53
  return [] if locs.empty?
54
54
 
55
- aligned = Set[locs.first.line, locs.last.line]
56
- locs.each_cons(3) do |before, loc, after|
57
- col = loc.column
58
- aligned << loc.line if col == before.column || col == after.column
55
+ aligned = Set.new
56
+ locs.each_cons(2) do |loc1, loc2|
57
+ aligned << loc1.line << loc2.line if loc1.column == loc2.column
59
58
  end
60
-
61
- # if locs.size > 2 and the size of variable `aligned`
62
- # has not increased from its initial value, there are not aligned lines.
63
- return [] if locs.size > 2 && aligned.size == 2
64
-
65
59
  aligned
66
60
  end
67
61
 
@@ -5,7 +5,10 @@ module RuboCop
5
5
  module Layout
6
6
  # Checks the indentation of the first element in an array literal
7
7
  # where the opening bracket and the first element are on separate lines.
8
- # The other elements' indentations are handled by the ArrayAlignment cop.
8
+ # The other elements' indentations are handled by `Layout/ArrayAlignment` cop.
9
+ #
10
+ # This cop will respect `Layout/ArrayAlignment` and will not work when
11
+ # `EnforcedStyle: with_fixed_indentation` is specified for `Layout/ArrayAlignment`.
9
12
  #
10
13
  # By default, array literals that are arguments in a method call with
11
14
  # parentheses, and where the opening square bracket of the array is on the
@@ -25,7 +28,7 @@ module RuboCop
25
28
  # # element are on separate lines is indented one step (two spaces) more
26
29
  # # than the position inside the opening parenthesis.
27
30
  #
28
- # #bad
31
+ # # bad
29
32
  # array = [
30
33
  # :value
31
34
  # ]
@@ -33,7 +36,7 @@ module RuboCop
33
36
  # :no_difference
34
37
  # ])
35
38
  #
36
- # #good
39
+ # # good
37
40
  # array = [
38
41
  # :value
39
42
  # ]
@@ -47,7 +50,7 @@ module RuboCop
47
50
  # # separate lines is indented the same as an array literal which is not
48
51
  # # defined inside a method call.
49
52
  #
50
- # #bad
53
+ # # bad
51
54
  # # consistent
52
55
  # array = [
53
56
  # :value
@@ -56,7 +59,7 @@ module RuboCop
56
59
  # :its_like_this
57
60
  # ])
58
61
  #
59
- # #good
62
+ # # good
60
63
  # array = [
61
64
  # :value
62
65
  # ]
@@ -68,13 +71,13 @@ module RuboCop
68
71
  # # The `align_brackets` style enforces that the opening and closing
69
72
  # # brackets are indented to the same position.
70
73
  #
71
- # #bad
74
+ # # bad
72
75
  # # align_brackets
73
76
  # and_now_for_something = [
74
77
  # :completely_different
75
78
  # ]
76
79
  #
77
- # #good
80
+ # # good
78
81
  # # align_brackets
79
82
  # and_now_for_something = [
80
83
  # :completely_different
@@ -93,6 +96,8 @@ module RuboCop
93
96
  end
94
97
 
95
98
  def on_send(node)
99
+ return if style != :consistent && enforce_first_argument_with_fixed_indentation?
100
+
96
101
  each_argument_node(node, :array) do |array_node, left_parenthesis|
97
102
  check(array_node, left_parenthesis)
98
103
  end
@@ -174,6 +179,16 @@ module RuboCop
174
179
  'where the left bracket is.'
175
180
  end
176
181
  end
182
+
183
+ def enforce_first_argument_with_fixed_indentation?
184
+ return false unless array_alignment_config['Enabled']
185
+
186
+ array_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
187
+ end
188
+
189
+ def array_alignment_config
190
+ config.for_cop('Layout/ArrayAlignment')
191
+ end
177
192
  end
178
193
  end
179
194
  end
@@ -72,7 +72,7 @@ module RuboCop
72
72
  return if ignored_node?(def_node)
73
73
 
74
74
  left_parenthesis = def_node.arguments.loc.begin
75
- first_elem = def_node.arguments.first
75
+ first_elem = def_node.first_argument
76
76
  return unless first_elem
77
77
  return if same_line?(first_elem, left_parenthesis)
78
78
 
@@ -182,7 +182,7 @@ module RuboCop
182
182
  end
183
183
 
184
184
  def add_correct_closing_paren(node, corrector)
185
- corrector.insert_after(node.arguments.last, ')')
185
+ corrector.insert_after(node.last_argument, ')')
186
186
  end
187
187
 
188
188
  def remove_incorrect_closing_paren(node, corrector)
@@ -271,7 +271,7 @@ module RuboCop
271
271
  def add_correct_external_trailing_comma(node, corrector)
272
272
  return unless external_trailing_comma?(node)
273
273
 
274
- corrector.insert_after(node.arguments.last, ',')
274
+ corrector.insert_after(node.last_argument, ',')
275
275
  end
276
276
 
277
277
  def remove_incorrect_external_trailing_comma(node, corrector)
@@ -8,7 +8,7 @@ module RuboCop
8
8
  #
9
9
  # Note: When ``Layout/LineLength``'s `AllowHeredoc` is false (not default),
10
10
  # this cop does not add any offenses for long here documents to
11
- # avoid `Layout/LineLength`'s offenses.
11
+ # avoid ``Layout/LineLength``'s offenses.
12
12
  #
13
13
  # @example
14
14
  # # bad
@@ -107,7 +107,7 @@ module RuboCop
107
107
  return false unless line.end_with?("\\\n")
108
108
 
109
109
  # Ensure backslash isn't part of a token spanning to the next line.
110
- node.children.none? { |c| c.first_line == line_num && c.multiline? }
110
+ node.children.none? { |c| (c.first_line...c.last_line).cover?(line_num) && c.multiline? }
111
111
  end
112
112
 
113
113
  def autocorrect(corrector, offense_range, insert_pos, spaces)
@@ -62,6 +62,7 @@ module RuboCop
62
62
 
63
63
  register_offense(node)
64
64
  end
65
+ alias on_csend on_send
65
66
 
66
67
  private
67
68
 
@@ -83,8 +84,20 @@ module RuboCop
83
84
  end
84
85
 
85
86
  def offense?(node)
86
- node.multiline? && !too_long?(node) && suitable_as_single_line?(node) &&
87
- !configured_to_not_be_inspected?(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?
89
+
90
+ !index_access_call_chained?(node) && !configured_to_not_be_inspected?(node)
91
+ end
92
+
93
+ def require_backslash?(node)
94
+ processed_source.lines[node.loc.operator.line - 1].end_with?('\\')
95
+ end
96
+
97
+ def index_access_call_chained?(node)
98
+ return false unless node.send_type? && node.method?(:[])
99
+
100
+ node.children.first.send_type? && node.children.first.method?(:[])
88
101
  end
89
102
 
90
103
  def configured_to_not_be_inspected?(node)
@@ -135,7 +148,7 @@ module RuboCop
135
148
  .gsub(/" *\\\n\s*'/, %q(" + ')) # Double quote, backslash, and then single quote
136
149
  .gsub(/' *\\\n\s*"/, %q(' + ")) # Single quote, backslash, and then double quote
137
150
  .gsub(/(["']) *\\\n\s*\1/, '') # Double or single quote, backslash, then same quote
138
- .gsub(/\n\s*(?=\.\w)/, '') # Extra space within method chaining
151
+ .gsub(/\n\s*(?=(&)?\.\w)/, '') # Extra space within method chaining which includes `&.`
139
152
  .gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
140
153
  end
141
154
 
@@ -29,7 +29,7 @@ module RuboCop
29
29
  MSG = '`%<kw_loc>s` at %<kw_loc_line>d, %<kw_loc_column>d is not ' \
30
30
  'aligned with `%<beginning>s` at ' \
31
31
  '%<begin_loc_line>d, %<begin_loc_column>d.'
32
- ANCESTOR_TYPES = %i[kwbegin def defs class module block].freeze
32
+ ANCESTOR_TYPES = %i[kwbegin def defs class module block numblock].freeze
33
33
  ANCESTOR_TYPES_WITH_ACCESS_MODIFIERS = %i[def defs].freeze
34
34
  ALTERNATIVE_ACCESS_MODIFIERS = %i[public_class_method private_class_method].freeze
35
35
 
@@ -95,7 +95,7 @@ module RuboCop
95
95
  def alignment_source(node, starting_loc)
96
96
  ending_loc =
97
97
  case node.type
98
- when :block, :kwbegin
98
+ when :block, :numblock, :kwbegin
99
99
  node.loc.begin
100
100
  when :def, :defs, :class, :module,
101
101
  :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
@@ -104,8 +104,8 @@ module RuboCop
104
104
  mlhs_node, = *node
105
105
  mlhs_node.source_range
106
106
  else
107
- # It is a wrapper with access modifier.
108
- node.child_nodes.first.loc.name
107
+ # It is a wrapper with receiver of object attribute or access modifier.
108
+ node.receiver&.source_range || node.child_nodes.first.loc.name
109
109
  end
110
110
 
111
111
  range_between(starting_loc.begin_pos, ending_loc.end_pos).source
@@ -25,10 +25,15 @@ module RuboCop
25
25
 
26
26
  MSG = 'Put method call on a separate line if chained to a single line block.'
27
27
 
28
+ def self.autocorrect_incompatible_with
29
+ [Style::MapToHash]
30
+ end
31
+
28
32
  def on_send(node)
29
33
  range = offending_range(node)
30
34
  add_offense(range) { |corrector| corrector.insert_before(range, "\n") } if range
31
35
  end
36
+ alias on_csend on_send
32
37
 
33
38
  private
34
39