rubocop 1.53.0 → 1.60.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 (236) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +5 -3
  4. data/config/default.yml +80 -11
  5. data/config/obsoletion.yml +5 -0
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
  7. data/lib/rubocop/cli.rb +1 -1
  8. data/lib/rubocop/config.rb +0 -2
  9. data/lib/rubocop/config_finder.rb +2 -2
  10. data/lib/rubocop/config_loader.rb +0 -1
  11. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  12. data/lib/rubocop/config_obsoletion.rb +11 -8
  13. data/lib/rubocop/config_validator.rb +0 -2
  14. data/lib/rubocop/cop/autocorrect_logic.rb +3 -1
  15. data/lib/rubocop/cop/base.rb +7 -1
  16. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  17. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  18. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  19. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  20. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  21. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  22. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  23. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  24. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  25. data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -21
  26. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  27. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  28. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  29. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  30. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  31. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  32. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  33. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  34. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  35. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  36. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +26 -3
  37. data/lib/rubocop/cop/layout/end_alignment.rb +12 -2
  38. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  39. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  40. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  41. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  42. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
  43. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  44. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  45. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  46. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  47. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  48. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  49. data/lib/rubocop/cop/layout/redundant_line_break.rb +15 -4
  50. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  51. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  52. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  53. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  54. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  55. data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
  56. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  57. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  58. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  59. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  60. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  61. data/lib/rubocop/cop/lint/debugger.rb +18 -4
  62. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  63. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  64. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
  65. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  66. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  67. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  68. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  69. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  70. data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -1
  71. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  72. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  73. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  74. data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
  75. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +10 -0
  76. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -0
  77. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +63 -4
  78. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
  79. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  80. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
  81. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  82. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  83. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  84. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  85. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  86. data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
  87. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  88. data/lib/rubocop/cop/lint/to_enum_arguments.rb +5 -3
  89. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  90. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  91. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  92. data/lib/rubocop/cop/lint/useless_assignment.rb +38 -12
  93. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  94. data/lib/rubocop/cop/lint/void.rb +46 -21
  95. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  96. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  97. data/lib/rubocop/cop/metrics/class_length.rb +8 -3
  98. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  99. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
  100. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  101. data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
  102. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  103. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  104. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
  105. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  106. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
  107. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  108. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  109. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  110. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  111. data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
  112. data/lib/rubocop/cop/naming/constant_name.rb +1 -2
  113. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  114. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  115. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  116. data/lib/rubocop/cop/registry.rb +4 -4
  117. data/lib/rubocop/cop/security/open.rb +2 -2
  118. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  119. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  120. data/lib/rubocop/cop/style/alias.rb +9 -8
  121. data/lib/rubocop/cop/style/arguments_forwarding.rb +355 -63
  122. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  123. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  124. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  125. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  126. data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
  127. data/lib/rubocop/cop/style/case_like_if.rb +4 -4
  128. data/lib/rubocop/cop/style/class_check.rb +1 -0
  129. data/lib/rubocop/cop/style/class_equality_comparison.rb +7 -0
  130. data/lib/rubocop/cop/style/collection_compact.rb +7 -6
  131. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  132. data/lib/rubocop/cop/style/combinable_loops.rb +17 -9
  133. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  134. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  135. data/lib/rubocop/cop/style/date_time.rb +5 -4
  136. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  137. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  138. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  139. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  140. data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
  141. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  142. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  143. data/lib/rubocop/cop/style/for.rb +1 -1
  144. data/lib/rubocop/cop/style/format_string.rb +24 -3
  145. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  146. data/lib/rubocop/cop/style/guard_clause.rb +26 -0
  147. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  148. data/lib/rubocop/cop/style/hash_each_methods.rb +83 -10
  149. data/lib/rubocop/cop/style/hash_except.rb +2 -1
  150. data/lib/rubocop/cop/style/identical_conditional_branches.rb +28 -3
  151. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  152. data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
  153. data/lib/rubocop/cop/style/invertible_unless_condition.rb +39 -2
  154. data/lib/rubocop/cop/style/lambda.rb +3 -3
  155. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  156. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
  157. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  158. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +22 -6
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  160. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  161. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  162. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  163. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  164. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  165. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +2 -4
  166. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  167. data/lib/rubocop/cop/style/next.rb +1 -1
  168. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  169. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  170. data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
  171. data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
  172. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  173. data/lib/rubocop/cop/style/redundant_argument.rb +9 -3
  174. data/lib/rubocop/cop/style/redundant_begin.rb +9 -1
  175. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -9
  176. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
  177. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  178. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  179. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  180. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  181. data/lib/rubocop/cop/style/redundant_filter_chain.rb +22 -5
  182. data/lib/rubocop/cop/style/redundant_line_continuation.rb +10 -1
  183. data/lib/rubocop/cop/style/redundant_parentheses.rb +63 -21
  184. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +18 -4
  185. data/lib/rubocop/cop/style/redundant_return.rb +8 -3
  186. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  187. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +5 -0
  188. data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
  189. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  190. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  191. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  192. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +23 -9
  193. data/lib/rubocop/cop/style/sample.rb +2 -1
  194. data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
  195. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  196. data/lib/rubocop/cop/style/semicolon.rb +8 -3
  197. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  198. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  199. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  200. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  201. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  202. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  203. data/lib/rubocop/cop/style/strip.rb +7 -4
  204. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  205. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  206. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  207. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  208. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  209. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  210. data/lib/rubocop/cop/utils/regexp_ranges.rb +26 -13
  211. data/lib/rubocop/cop/variable_force/assignment.rb +14 -5
  212. data/lib/rubocop/cops_documentation_generator.rb +11 -1
  213. data/lib/rubocop/ext/regexp_node.rb +9 -4
  214. data/lib/rubocop/file_finder.rb +4 -7
  215. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  216. data/lib/rubocop/formatter/html_formatter.rb +5 -4
  217. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  218. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  219. data/lib/rubocop/formatter.rb +1 -1
  220. data/lib/rubocop/lsp/routes.rb +42 -19
  221. data/lib/rubocop/lsp/runtime.rb +22 -2
  222. data/lib/rubocop/lsp/server.rb +10 -4
  223. data/lib/rubocop/magic_comment.rb +12 -10
  224. data/lib/rubocop/options.rb +0 -8
  225. data/lib/rubocop/result_cache.rb +4 -1
  226. data/lib/rubocop/rspec/shared_contexts.rb +8 -3
  227. data/lib/rubocop/rspec/support.rb +1 -0
  228. data/lib/rubocop/runner.rb +6 -4
  229. data/lib/rubocop/server/client_command/exec.rb +1 -1
  230. data/lib/rubocop/string_interpreter.rb +3 -3
  231. data/lib/rubocop/target_finder.rb +7 -3
  232. data/lib/rubocop/target_ruby.rb +9 -5
  233. data/lib/rubocop/version.rb +1 -1
  234. data/lib/rubocop.rb +6 -0
  235. metadata +20 -13
  236. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -14,12 +14,15 @@ module RuboCop
14
14
  # Check for unparenthesized args' preceding and trailing whitespaces.
15
15
  remove_unparenthesized_whitespace(corrector)
16
16
 
17
- # Avoid correcting to `lambdado` by inserting whitespace
18
- # if none exists before or after the lambda arguments.
19
- insert_separating_space(corrector)
17
+ if block_node.block_type?
18
+ # Avoid correcting to `lambdado` by inserting whitespace
19
+ # if none exists before or after the lambda arguments.
20
+ insert_separating_space(corrector)
21
+
22
+ remove_arguments(corrector)
23
+ end
20
24
 
21
25
  replace_selector(corrector)
22
- remove_arguments(corrector)
23
26
 
24
27
  replace_delimiters(corrector)
25
28
 
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # The parameter name given is transformed into a method name (eg. `Max`
9
9
  # becomes `self.max=` and `MinDigits` becomes `self.min_digits=`).
10
10
  def exclude_limit(parameter_name, method_name: transform(parameter_name))
11
- define_method("#{method_name}=") do |value|
11
+ define_method(:"#{method_name}=") do |value|
12
12
  cfg = config_to_allow_offenses
13
13
  cfg[:exclude_limit] ||= {}
14
14
  current_max = cfg[:exclude_limit][parameter_name]
@@ -43,7 +43,7 @@ module RuboCop
43
43
  def on_block(block_node)
44
44
  return unless gem_specification(block_node)
45
45
 
46
- block_parameter = block_node.arguments.first.source
46
+ block_parameter = block_node.first_argument.source
47
47
 
48
48
  assignment = block_node.descendants.detect do |node|
49
49
  use_deprecated_attributes?(node, block_parameter)
@@ -65,7 +65,7 @@ module RuboCop
65
65
  lhs, _op, _rhs = *node
66
66
  [lhs, attribute]
67
67
  else
68
- [node, "#{attribute}=".to_sym]
68
+ [node, :"#{attribute}="]
69
69
  end
70
70
  end
71
71
 
@@ -45,7 +45,15 @@ module RuboCop
45
45
  #
46
46
  # spec.add_runtime_dependency 'rspec'
47
47
  #
48
- # # good only if TreatCommentsAsGroupSeparators is true
48
+ # @example TreatCommentsAsGroupSeparators: true (default)
49
+ # # good
50
+ # # For code quality
51
+ # spec.add_dependency 'rubocop'
52
+ # # For tests
53
+ # spec.add_dependency 'rspec'
54
+ #
55
+ # @example TreatCommentsAsGroupSeparators: false
56
+ # # bad
49
57
  # # For code quality
50
58
  # spec.add_dependency 'rubocop'
51
59
  # # For tests
@@ -67,7 +67,7 @@ module RuboCop
67
67
 
68
68
  def require_path
69
69
  path = source_path.relative_path_from(root_file_path.dirname)
70
- path.to_s.sub('.rb', '')
70
+ path.to_s.delete_suffix('.rb')
71
71
  end
72
72
  end
73
73
  end
@@ -26,9 +26,7 @@ module RuboCop
26
26
  # expect_no_offenses('...')
27
27
  # end
28
28
  class ExampleDescription < Base
29
- class << self
30
- attr_accessor :descriptions
31
- end
29
+ extend AutoCorrector
32
30
 
33
31
  MSG = 'Description does not match use of `%<method_name>s`.'
34
32
 
@@ -39,21 +37,31 @@ module RuboCop
39
37
  expect_no_corrections
40
38
  ].to_set.freeze
41
39
 
42
- EXPECT_NO_OFFENSES_INCORRECT_DESCRIPTIONS = [
43
- /^(adds|registers|reports|finds) (an? )?offense/,
44
- /^(flags|handles|works)\b/
45
- ].freeze
40
+ EXPECT_NO_OFFENSES_DESCRIPTION_MAPPING = {
41
+ /\A(adds|registers|reports|finds) (an? )?offense/ => 'does not register an offense',
42
+ /\A(flags|handles|works)\b/ => 'does not register'
43
+ }.freeze
44
+
45
+ EXPECT_OFFENSE_DESCRIPTION_MAPPING = {
46
+ /\A(does not|doesn't) (register|find|flag|report)/ => 'registers',
47
+ /\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense',
48
+ /\Aaccepts\b/ => 'registers'
49
+ }.freeze
46
50
 
47
- EXPECT_OFFENSE_INCORRECT_DESCRIPTIONS = [
48
- /^(does not|doesn't) (register|find|flag|report)/,
49
- /^(does not|doesn't) add (a|an|any )?offense/
50
- ].freeze
51
+ EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
52
+ /\A(auto[- ]?)?correct/ => 'does not correct'
53
+ }.freeze
51
54
 
52
- EXPECT_NO_CORRECTIONS_INCORRECT_DESCRIPTIONS = [/^(auto[- ]?)?correct/].freeze
55
+ EXPECT_CORRECTION_DESCRIPTION_MAPPING = {
56
+ /\b(does not|doesn't) (auto[- ]?)?correct/ => 'autocorrects'
57
+ }.freeze
53
58
 
54
- EXPECT_CORRECTION_INCORRECT_DESCRIPTIONS = [
55
- /\b(does not|doesn't) (auto[- ]?)?correct/
56
- ].freeze
59
+ EXAMPLE_DESCRIPTION_MAPPING = {
60
+ expect_no_offenses: EXPECT_NO_OFFENSES_DESCRIPTION_MAPPING,
61
+ expect_offense: EXPECT_OFFENSE_DESCRIPTION_MAPPING,
62
+ expect_no_corrections: EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING,
63
+ expect_correction: EXPECT_CORRECTION_DESCRIPTION_MAPPING
64
+ }.freeze
57
65
 
58
66
  # @!method offense_example?(node)
59
67
  def_node_matcher :offense_example?, <<~PATTERN
@@ -66,21 +74,34 @@ module RuboCop
66
74
 
67
75
  def on_send(node)
68
76
  parent = node.each_ancestor(:block).first
69
- return unless parent && (description = offense_example?(parent))
77
+ return unless parent && (current_description = offense_example?(parent))
70
78
 
71
79
  method_name = node.method_name
72
80
  message = format(MSG, method_name: method_name)
73
81
 
74
- regexp_group = self.class.const_get("#{method_name}_incorrect_descriptions".upcase)
75
- check_description(description, regexp_group, message)
82
+ description_map = EXAMPLE_DESCRIPTION_MAPPING[method_name]
83
+ check_description(current_description, description_map, message)
76
84
  end
77
85
 
78
86
  private
79
87
 
80
- def check_description(description, regexps, message)
81
- return unless regexps.any? { |regexp| regexp.match?(string_contents(description)) }
88
+ def check_description(current_description, description_map, message)
89
+ description_text = string_contents(current_description)
90
+ return unless (new_description = correct_description(description_text, description_map))
91
+
92
+ add_offense(current_description, message: message) do |corrector|
93
+ corrector.replace(current_description, "'#{new_description}'")
94
+ end
95
+ end
96
+
97
+ def correct_description(current_description, description_map)
98
+ description_map.each do |incorrect_description_pattern, preferred_description|
99
+ if incorrect_description_pattern.match?(current_description)
100
+ return current_description.gsub(incorrect_description_pattern, preferred_description)
101
+ end
102
+ end
82
103
 
83
- add_offense(description, message: message)
104
+ nil
84
105
  end
85
106
 
86
107
  def string_contents(node)
@@ -51,7 +51,9 @@ module RuboCop
51
51
 
52
52
  def extract_receiver(node)
53
53
  receiver = node.receiver
54
- receiver = receiver.receiver if receiver.method?(:loc) || receiver.method?(:source_range)
54
+ if receiver.send_type? && (receiver.method?(:loc) || receiver.method?(:source_range))
55
+ receiver = receiver.receiver
56
+ end
55
57
  receiver.source
56
58
  end
57
59
  end
@@ -12,38 +12,37 @@ module RuboCop
12
12
  # # good
13
13
  # node.method?(:do_something)
14
14
  #
15
+ # # bad
16
+ # node.method_name != :do_something
17
+ #
18
+ # # good
19
+ # !node.method?(:do_something)
20
+ #
15
21
  class MethodNameEqual < Base
16
- include RangeHelp
17
22
  extend AutoCorrector
18
23
 
19
- MSG = 'Use `method?(%<method_name>s)` instead of `method_name == %<method_name>s`.'
20
- RESTRICT_ON_SEND = %i[==].freeze
24
+ MSG = 'Use `%<prefer>s` instead.'
25
+ RESTRICT_ON_SEND = %i[== !=].freeze
21
26
 
22
- # @!method method_name?(node)
23
- def_node_matcher :method_name?, <<~PATTERN
27
+ # @!method method_name(node)
28
+ def_node_matcher :method_name, <<~PATTERN
24
29
  (send
25
- $(send
26
- (...) :method_name) :==
27
- $...)
30
+ (send
31
+ (...) :method_name) {:== :!=}
32
+ $_)
28
33
  PATTERN
29
34
 
30
35
  def on_send(node)
31
- method_name?(node) do |method_name_node, method_name_arg|
32
- message = format(MSG, method_name: method_name_arg.first.source)
36
+ method_name(node) do |method_name_arg|
37
+ bang = node.method?(:!=) ? '!' : ''
38
+ prefer = "#{bang}#{node.receiver.receiver.source}.method?(#{method_name_arg.source})"
39
+ message = format(MSG, prefer: prefer)
33
40
 
34
- range = range(method_name_node, node)
35
-
36
- add_offense(range, message: message) do |corrector|
37
- corrector.replace(range, "method?(#{method_name_arg.first.source})")
41
+ add_offense(node, message: message) do |corrector|
42
+ corrector.replace(node, prefer)
38
43
  end
39
44
  end
40
45
  end
41
-
42
- private
43
-
44
- def range(method_name_node, node)
45
- range_between(method_name_node.loc.selector.begin_pos, node.source_range.end_pos)
46
- end
47
46
  end
48
47
  end
49
48
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for the use of `node.arguments.first` or `node.arguments.last` and
7
+ # suggests the use of `node.first_argument` or `node.last_argument` instead.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # node.arguments.first
12
+ # node.arguments[0]
13
+ # node.arguments.last
14
+ # node.arguments[-1]
15
+ #
16
+ # # good
17
+ # node.first_argument
18
+ # node.last_argument
19
+ #
20
+ class NodeFirstOrLastArgument < Base
21
+ extend AutoCorrector
22
+ include RangeHelp
23
+
24
+ MSG = 'Use `#%<correct>s` instead of `#%<incorrect>s`.'
25
+ RESTRICT_ON_SEND = %i[arguments].freeze
26
+
27
+ # @!method arguments_first_or_last?(node)
28
+ def_node_matcher :arguments_first_or_last?, <<~PATTERN
29
+ {
30
+ (send (send !nil? :arguments) ${:first :last})
31
+ (send (send !nil? :arguments) :[] (int ${0 -1}))
32
+ }
33
+ PATTERN
34
+
35
+ def on_send(node)
36
+ arguments_first_or_last?(node.parent) do |end_or_index|
37
+ range = range_between(node.loc.selector.begin_pos, node.parent.source_range.end_pos)
38
+ correct = case end_or_index
39
+ when :first, 0 then 'first_argument'
40
+ when :last, -1 then 'last_argument'
41
+ else raise "Unknown end_or_index: #{end_or_index}"
42
+ end
43
+ message = format(MSG, correct: correct, incorrect: range.source)
44
+
45
+ add_offense(range, message: message) do |corrector|
46
+ corrector.replace(range, correct)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -40,7 +40,7 @@ module RuboCop
40
40
  return if node.arguments.none?
41
41
  return unless valid_method_name?(node)
42
42
 
43
- actual_name = node.arguments.first.value
43
+ actual_name = node.first_argument.value
44
44
  directives = method_directives(node)
45
45
  return too_many_directives(node) if directives.size > 1
46
46
 
@@ -53,7 +53,7 @@ module RuboCop
53
53
  private
54
54
 
55
55
  def valid_method_name?(node)
56
- node.arguments.first.str_type? || node.arguments.first.sym_type?
56
+ node.first_argument.str_type? || node.first_argument.sym_type?
57
57
  end
58
58
 
59
59
  def method_directives(node)
@@ -14,6 +14,12 @@ module RuboCop
14
14
  # node.method_name
15
15
  #
16
16
  # # bad
17
+ # node.send_node.method?(:method_name)
18
+ #
19
+ # # good
20
+ # node.method?(:method_name)
21
+ #
22
+ # # bad
17
23
  # node.send_node.receiver
18
24
  #
19
25
  # # good
@@ -24,11 +30,14 @@ module RuboCop
24
30
  extend AutoCorrector
25
31
 
26
32
  MSG = 'Remove the redundant `send_node`.'
27
- RESTRICT_ON_SEND = %i[method_name receiver].freeze
33
+ RESTRICT_ON_SEND = %i[method_name method? receiver].freeze
28
34
 
29
35
  # @!method dispatch_method(node)
30
36
  def_node_matcher :dispatch_method, <<~PATTERN
31
- (send $(send _ :send_node) _)
37
+ {
38
+ (send $(send _ :send_node) {:method_name :receiver})
39
+ (send $(send _ :send_node) :method? _)
40
+ }
32
41
  PATTERN
33
42
 
34
43
  def on_send(node)
@@ -27,6 +27,8 @@ module RuboCop
27
27
  PATTERN
28
28
 
29
29
  def on_new_investigation
30
+ return if processed_source.blank?
31
+
30
32
  assertions_using_described_class_msg.each { |node| add_offense(node) }
31
33
  end
32
34
 
@@ -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'
@@ -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
@@ -32,7 +32,7 @@ module RuboCop
32
32
  end
33
33
 
34
34
  def on_send(node)
35
- return unless node.dot? || ampersand_dot?(node)
35
+ return unless node.dot? || node.safe_navigation?
36
36
 
37
37
  return correct_style_detected if proper_dot_position?(node)
38
38
 
@@ -133,10 +133,6 @@ module RuboCop
133
133
  # l.(1) has no selector, so we use the opening parenthesis instead
134
134
  node.loc.selector || node.loc.begin
135
135
  end
136
-
137
- def ampersand_dot?(node)
138
- node.loc.respond_to?(:dot) && node.loc.dot && node.loc.dot.is?('&.')
139
- end
140
136
  end
141
137
  end
142
138
  end
@@ -3,7 +3,23 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Enforces empty line after guard clause
6
+ # Enforces empty line after guard clause.
7
+ #
8
+ # This cop allows `# :nocov:` directive after guard clause because
9
+ # SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
10
+ #
11
+ # [source,ruby]
12
+ # ----
13
+ # def foo
14
+ # # :nocov:
15
+ # return if condition
16
+ # # :nocov:
17
+ # bar
18
+ # end
19
+ # ----
20
+ #
21
+ # Refer to SimpleCov's documentation for more details:
22
+ # https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
7
23
  #
8
24
  # @example
9
25
  #
@@ -42,19 +58,22 @@ module RuboCop
42
58
 
43
59
  MSG = 'Add empty line after guard clause.'
44
60
  END_OF_HEREDOC_LINE = 1
61
+ SIMPLE_DIRECTIVE_COMMENT_PATTERN = /\A# *:nocov:\z/.freeze
45
62
 
46
63
  def on_if(node)
47
64
  return if correct_style?(node)
48
65
  return if multiple_statements_on_line?(node)
49
66
 
50
67
  if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
51
- return if next_line_empty_or_enable_directive_comment?(heredoc_line(node, heredoc_node))
68
+ if next_line_empty_or_allowed_directive_comment?(heredoc_line(node, heredoc_node))
69
+ return
70
+ end
52
71
 
53
72
  add_offense(heredoc_node.loc.heredoc_end) do |corrector|
54
73
  autocorrect(corrector, heredoc_node)
55
74
  end
56
75
  else
57
- return if next_line_empty_or_enable_directive_comment?(node.last_line)
76
+ return if next_line_empty_or_allowed_directive_comment?(node.last_line)
58
77
 
59
78
  add_offense(offense_location(node)) { |corrector| autocorrect(corrector, node) }
60
79
  end
@@ -70,7 +89,7 @@ module RuboCop
70
89
  end
71
90
 
72
91
  next_line = node_range.last_line + 1
73
- if next_line_enable_directive_comment?(next_line)
92
+ if next_line_allowed_directive_comment?(next_line)
74
93
  node_range = processed_source.comment_at_line(next_line)
75
94
  end
76
95
 
@@ -88,21 +107,21 @@ module RuboCop
88
107
  node.if_branch&.guard_clause?
89
108
  end
90
109
 
91
- def next_line_empty_or_enable_directive_comment?(line)
110
+ def next_line_empty_or_allowed_directive_comment?(line)
92
111
  return true if next_line_empty?(line)
93
112
 
94
113
  next_line = line + 1
95
- next_line_enable_directive_comment?(next_line) && next_line_empty?(next_line)
114
+ next_line_allowed_directive_comment?(next_line) && next_line_empty?(next_line)
96
115
  end
97
116
 
98
117
  def next_line_empty?(line)
99
118
  processed_source[line].blank?
100
119
  end
101
120
 
102
- def next_line_enable_directive_comment?(line)
121
+ def next_line_allowed_directive_comment?(line)
103
122
  return false unless (comment = processed_source.comment_at_line(line))
104
123
 
105
- DirectiveComment.new(comment).enabled?
124
+ DirectiveComment.new(comment).enabled? || simplecov_directive_comment?(comment)
106
125
  end
107
126
 
108
127
  def next_line_rescue_or_ensure?(node)
@@ -137,7 +156,7 @@ module RuboCop
137
156
  return node if node
138
157
  end
139
158
 
140
- return last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
159
+ last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
141
160
  end
142
161
 
143
162
  def last_heredoc_argument_node(node)
@@ -145,6 +164,8 @@ module RuboCop
145
164
 
146
165
  if node.if_branch.and_type?
147
166
  node.if_branch.children.first
167
+ elsif use_heredoc_in_condition?(node.condition)
168
+ node.condition
148
169
  else
149
170
  node.if_branch.children.last
150
171
  end
@@ -161,6 +182,12 @@ module RuboCop
161
182
  node.respond_to?(:heredoc?) && node.heredoc?
162
183
  end
163
184
 
185
+ def use_heredoc_in_condition?(condition)
186
+ condition.descendants.any? do |descendant|
187
+ descendant.respond_to?(:heredoc?) && descendant.heredoc?
188
+ end
189
+ end
190
+
164
191
  def offense_location(node)
165
192
  if node.loc.respond_to?(:end) && node.loc.end
166
193
  node.loc.end
@@ -175,6 +202,12 @@ module RuboCop
175
202
 
176
203
  parent.begin_type? && parent.single_line?
177
204
  end
205
+
206
+ # SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
207
+ # https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
208
+ def simplecov_directive_comment?(comment)
209
+ SIMPLE_DIRECTIVE_COMMENT_PATTERN.match?(comment.text)
210
+ end
178
211
  end
179
212
  end
180
213
  end
@@ -135,7 +135,8 @@ module RuboCop
135
135
  return if nodes.all?(&:single_line?) && cop_config['AllowAdjacentOneLineDefs']
136
136
 
137
137
  correction_node = nodes.last
138
- location = correction_node.loc.keyword.join(correction_node.loc.name)
138
+
139
+ location = def_location(correction_node)
139
140
  add_offense(location, message: message(correction_node, count: count)) do |corrector|
140
141
  autocorrect(corrector, *nodes, count)
141
142
  end
@@ -159,10 +160,28 @@ module RuboCop
159
160
 
160
161
  private
161
162
 
163
+ def def_location(correction_node)
164
+ if correction_node.block_type?
165
+ correction_node.source_range.join(correction_node.children.first.source_range)
166
+ else
167
+ correction_node.loc.keyword.join(correction_node.loc.name)
168
+ end
169
+ end
170
+
162
171
  def candidate?(node)
163
172
  return false unless node
164
173
 
165
- method_candidate?(node) || class_candidate?(node) || module_candidate?(node)
174
+ method_candidate?(node) || class_candidate?(node) || module_candidate?(node) ||
175
+ macro_candidate?(node)
176
+ end
177
+
178
+ def empty_line_between_macros
179
+ cop_config.fetch('DefLikeMacros', []).map(&:to_sym)
180
+ end
181
+
182
+ def macro_candidate?(node)
183
+ node.block_type? && node.children.first.macro? &&
184
+ empty_line_between_macros.include?(node.children.first.method_name)
166
185
  end
167
186
 
168
187
  def method_candidate?(node)
@@ -226,7 +245,11 @@ module RuboCop
226
245
  end
227
246
 
228
247
  def def_start(node)
229
- node.loc.keyword.line
248
+ if node.block_type? && node.children.first.send_type?
249
+ node.source_range.line
250
+ else
251
+ node.loc.keyword.line
252
+ end
230
253
  end
231
254
 
232
255
  def def_end(node)
@@ -83,7 +83,11 @@ module RuboCop
83
83
  end
84
84
 
85
85
  def on_sclass(node)
86
- check_other_alignment(node)
86
+ if node.parent&.assignment?
87
+ check_asgn_alignment(node.parent, node)
88
+ else
89
+ check_other_alignment(node)
90
+ end
87
91
  end
88
92
 
89
93
  def on_module(node)
@@ -163,7 +167,13 @@ module RuboCop
163
167
  when :keyword
164
168
  node
165
169
  when :variable
166
- alignment_node_for_variable_style(node)
170
+ align_to = alignment_node_for_variable_style(node)
171
+
172
+ while (parent = align_to.parent) && parent.send_type? && same_line?(align_to, parent)
173
+ align_to = parent
174
+ end
175
+
176
+ align_to
167
177
  else
168
178
  start_line_range(node)
169
179
  end
@@ -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