rubocop 1.48.1 → 1.52.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +59 -12
  4. data/lib/rubocop/cli/command/execute_runner.rb +7 -2
  5. data/lib/rubocop/cli.rb +6 -6
  6. data/lib/rubocop/config.rb +5 -1
  7. data/lib/rubocop/config_loader.rb +8 -8
  8. data/lib/rubocop/config_obsoletion.rb +2 -2
  9. data/lib/rubocop/cop/autocorrect_logic.rb +28 -12
  10. data/lib/rubocop/cop/base.rb +5 -1
  11. data/lib/rubocop/cop/cop.rb +2 -2
  12. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  13. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  14. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  15. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -1
  16. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  17. data/lib/rubocop/cop/internal_affairs/cop_description.rb +33 -9
  18. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +2 -2
  19. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +1 -1
  20. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  21. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +29 -2
  22. data/lib/rubocop/cop/layout/class_structure.rb +1 -0
  23. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +0 -1
  24. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  25. data/lib/rubocop/cop/layout/empty_lines.rb +1 -1
  26. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -0
  27. data/lib/rubocop/cop/layout/end_alignment.rb +5 -1
  28. data/lib/rubocop/cop/layout/extra_spacing.rb +6 -1
  29. data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
  30. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +25 -34
  31. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +7 -19
  32. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +42 -52
  33. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +38 -55
  34. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  35. data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +8 -27
  37. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +7 -26
  38. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +4 -21
  39. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +6 -30
  40. data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -7
  41. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
  42. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  43. data/lib/rubocop/cop/layout/space_inside_parens.rb +2 -2
  44. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  45. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +3 -3
  46. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +122 -0
  47. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  48. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
  49. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  50. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  51. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  52. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  53. data/lib/rubocop/cop/lint/missing_super.rb +3 -0
  54. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  55. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  56. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  57. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  58. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -1
  59. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +35 -15
  60. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  61. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  62. data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -1
  63. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  64. data/lib/rubocop/cop/lint/unreachable_loop.rb +3 -3
  65. data/lib/rubocop/cop/lint/useless_assignment.rb +59 -1
  66. data/lib/rubocop/cop/lint/useless_method_definition.rb +10 -2
  67. data/lib/rubocop/cop/lint/void.rb +69 -9
  68. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  69. data/lib/rubocop/cop/metrics/class_length.rb +1 -0
  70. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  71. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  72. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  73. data/lib/rubocop/cop/mixin/comments_help.rb +7 -3
  74. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  75. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  76. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  77. data/lib/rubocop/cop/naming/ascii_identifiers.rb +1 -1
  78. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  79. data/lib/rubocop/cop/naming/inclusive_language.rb +23 -4
  80. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +22 -7
  81. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  82. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  83. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  84. data/lib/rubocop/cop/style/attr.rb +11 -1
  85. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  86. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -2
  87. data/lib/rubocop/cop/style/class_equality_comparison.rb +51 -40
  88. data/lib/rubocop/cop/style/collection_compact.rb +19 -6
  89. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  90. data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
  91. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  92. data/lib/rubocop/cop/style/copyright.rb +6 -3
  93. data/lib/rubocop/cop/style/data_inheritance.rb +75 -0
  94. data/lib/rubocop/cop/style/dir.rb +1 -1
  95. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  96. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
  97. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  98. data/lib/rubocop/cop/style/documentation.rb +1 -1
  99. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  100. data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
  101. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  102. data/lib/rubocop/cop/style/file_empty.rb +3 -3
  103. data/lib/rubocop/cop/style/file_read.rb +2 -2
  104. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  105. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  106. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  107. data/lib/rubocop/cop/style/hash_except.rb +23 -12
  108. data/lib/rubocop/cop/style/hash_syntax.rb +4 -1
  109. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  110. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  111. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  112. data/lib/rubocop/cop/style/if_unless_modifier.rb +41 -12
  113. data/lib/rubocop/cop/style/invertible_unless_condition.rb +9 -5
  114. data/lib/rubocop/cop/style/map_to_hash.rb +4 -1
  115. data/lib/rubocop/cop/style/map_to_set.rb +4 -1
  116. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -9
  117. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +43 -36
  118. data/lib/rubocop/cop/style/multiline_method_signature.rb +6 -3
  119. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  120. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  121. data/lib/rubocop/cop/style/parallel_assignment.rb +26 -18
  122. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -3
  123. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  124. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  125. data/lib/rubocop/cop/style/redundant_fetch_block.rb +6 -4
  126. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  127. data/lib/rubocop/cop/style/redundant_line_continuation.rb +183 -0
  128. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  129. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  130. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -2
  131. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  132. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  133. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -3
  134. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  135. data/lib/rubocop/cop/style/require_order.rb +11 -5
  136. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  137. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  138. data/lib/rubocop/cop/style/semicolon.rb +12 -1
  139. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  140. data/lib/rubocop/cop/style/sole_nested_conditional.rb +5 -3
  141. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  142. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  143. data/lib/rubocop/cop/style/trailing_body_on_class.rb +1 -0
  144. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  145. data/lib/rubocop/cop/style/unless_logical_operators.rb +1 -0
  146. data/lib/rubocop/cop/team.rb +1 -1
  147. data/lib/rubocop/cop/variable_force/assignment.rb +33 -1
  148. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  149. data/lib/rubocop/cop/variable_force.rb +1 -0
  150. data/lib/rubocop/cops_documentation_generator.rb +10 -3
  151. data/lib/rubocop/ext/regexp_node.rb +1 -1
  152. data/lib/rubocop/ext/regexp_parser.rb +1 -1
  153. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  154. data/lib/rubocop/options.rb +4 -1
  155. data/lib/rubocop/result_cache.rb +2 -2
  156. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  157. data/lib/rubocop/server/cache.rb +1 -1
  158. data/lib/rubocop/server/client_command/exec.rb +2 -1
  159. data/lib/rubocop/server/helper.rb +1 -1
  160. data/lib/rubocop/server/server_command/exec.rb +1 -1
  161. data/lib/rubocop/target_ruby.rb +3 -2
  162. data/lib/rubocop/version.rb +10 -6
  163. data/lib/rubocop.rb +8 -0
  164. metadata +20 -12
@@ -20,9 +20,14 @@ module RuboCop
20
20
  # # good
21
21
  # fooBar = 1
22
22
  #
23
+ # @example AllowedIdentifiers: ['fooBar']
24
+ # # good (with EnforcedStyle: snake_case)
25
+ # fooBar = 1
26
+ #
23
27
  # @example AllowedPatterns: ['_v\d+\z']
24
- # # good
28
+ # # good (with EnforcedStyle: camelCase)
25
29
  # :release_v1
30
+ #
26
31
  class VariableName < Base
27
32
  include AllowedIdentifiers
28
33
  include ConfigurableNaming
@@ -92,6 +92,7 @@ module RuboCop
92
92
  comment_line?(processed_source[node.first_line - 2])
93
93
  end
94
94
 
95
+ # rubocop:disable Metrics/CyclomaticComplexity
95
96
  def groupable_accessor?(node)
96
97
  return true unless (previous_expression = node.left_siblings.last)
97
98
 
@@ -104,8 +105,11 @@ module RuboCop
104
105
 
105
106
  return true unless previous_expression.send_type?
106
107
 
107
- previous_expression.attribute_accessor? || previous_expression.access_modifier?
108
+ previous_expression.attribute_accessor? ||
109
+ previous_expression.access_modifier? ||
110
+ node.first_line - previous_expression.last_line > 1 # there is a space between nodes
108
111
  end
112
+ # rubocop:enable Metrics/CyclomaticComplexity
109
113
 
110
114
  def class_send_elements(class_node)
111
115
  class_def = class_node.body
@@ -24,7 +24,7 @@ module RuboCop
24
24
  def on_send(node)
25
25
  return unless node.command?(:attr) && node.arguments?
26
26
  # check only for method definitions in class/module body
27
- return if node.parent && !node.parent.class_type? && !class_eval?(node.parent)
27
+ return if allowed_context?(node)
28
28
 
29
29
  message = message(node)
30
30
  add_offense(node.loc.selector, message: message) do |corrector|
@@ -34,6 +34,16 @@ module RuboCop
34
34
 
35
35
  private
36
36
 
37
+ def allowed_context?(node)
38
+ return false unless (class_node = node.each_ancestor(:class, :block).first)
39
+
40
+ (!class_node.class_type? && !class_eval?(class_node)) || define_attr_method?(class_node)
41
+ end
42
+
43
+ def define_attr_method?(node)
44
+ node.each_descendant(:def).any? { |def_node| def_node.method?(:attr) }
45
+ end
46
+
37
47
  def autocorrect(corrector, node)
38
48
  attr_name, setter = *node.arguments
39
49
 
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- #
7
- # This cop checks for BEGIN blocks.
6
+ # Checks for BEGIN blocks.
8
7
  #
9
8
  # @example
10
9
  # # bad
@@ -11,7 +11,7 @@ module RuboCop
11
11
  #
12
12
  # Moving from compact to nested children requires knowledge of whether the
13
13
  # outer parent is a module or a class. Moving from nested to compact requires
14
- # verification that the outer parent is defined elsewhere. Rubocop does not
14
+ # verification that the outer parent is defined elsewhere. RuboCop does not
15
15
  # have the knowledge to perform either operation safely and thus requires
16
16
  # manual oversight.
17
17
  #
@@ -139,7 +139,7 @@ module RuboCop
139
139
  end
140
140
 
141
141
  def check_style(node, body)
142
- return if node.identifier.children[0]&.cbase_type?
142
+ return if node.identifier.namespace&.cbase_type?
143
143
 
144
144
  if style == :nested
145
145
  check_nested_style(node)
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Style
6
6
  # Enforces the use of `Object#instance_of?` instead of class comparison
7
7
  # for equality.
8
- # `==`, `equal?`, and `eql?` methods are allowed by default.
8
+ # `==`, `equal?`, and `eql?` custom method definitions are allowed by default.
9
9
  # These are customizable with `AllowedMethods` option.
10
10
  #
11
11
  # @example
@@ -18,45 +18,31 @@ module RuboCop
18
18
  # # good
19
19
  # var.instance_of?(Date)
20
20
  #
21
- # @example AllowedMethods: [] (default)
21
+ # @example AllowedMethods: ['==', 'equal?', 'eql?'] (default)
22
22
  # # good
23
- # var.instance_of?(Date)
23
+ # def ==(other)
24
+ # self.class == other.class && name == other.name
25
+ # end
24
26
  #
25
- # # bad
26
- # var.class == Date
27
- # var.class.equal?(Date)
28
- # var.class.eql?(Date)
29
- # var.class.name == 'Date'
27
+ # def equal?(other)
28
+ # self.class.equal?(other.class) && name.equal?(other.name)
29
+ # end
30
30
  #
31
- # @example AllowedMethods: [`==`]
32
- # # good
33
- # var.instance_of?(Date)
34
- # var.class == Date
35
- # var.class.name == 'Date'
36
- #
37
- # # bad
38
- # var.class.equal?(Date)
39
- # var.class.eql?(Date)
31
+ # def eql?(other)
32
+ # self.class.eql?(other.class) && name.eql?(other.name)
33
+ # end
40
34
  #
41
35
  # @example AllowedPatterns: [] (default)
42
- # # good
43
- # var.instance_of?(Date)
44
- #
45
36
  # # bad
46
- # var.class == Date
47
- # var.class.equal?(Date)
48
- # var.class.eql?(Date)
49
- # var.class.name == 'Date'
37
+ # def eq(other)
38
+ # self.class.eq(other.class) && name.eq(other.name)
39
+ # end
50
40
  #
51
41
  # @example AllowedPatterns: ['eq']
52
42
  # # good
53
- # var.instance_of?(Date)
54
- # var.class.equal?(Date)
55
- # var.class.eql?(Date)
56
- #
57
- # # bad
58
- # var.class == Date
59
- # var.class.name == 'Date'
43
+ # def eq(other)
44
+ # self.class.eq(other.class) && name.eq(other.name)
45
+ # end
60
46
  #
61
47
  class ClassEqualityComparison < Base
62
48
  include RangeHelp
@@ -64,14 +50,15 @@ module RuboCop
64
50
  include AllowedPattern
65
51
  extend AutoCorrector
66
52
 
67
- MSG = 'Use `instance_of?(%<class_name>s)` instead of comparing classes.'
53
+ MSG = 'Use `instance_of?%<class_argument>s` instead of comparing classes.'
68
54
 
69
55
  RESTRICT_ON_SEND = %i[== equal? eql?].freeze
56
+ CLASS_NAME_METHODS = %i[name to_s inspect].freeze
70
57
 
71
58
  # @!method class_comparison_candidate?(node)
72
59
  def_node_matcher :class_comparison_candidate?, <<~PATTERN
73
60
  (send
74
- {$(send _ :class) (send $(send _ :class) :name)}
61
+ {$(send _ :class) (send $(send _ :class) #class_name_method?)}
75
62
  {:== :equal? :eql?} $_)
76
63
  PATTERN
77
64
 
@@ -83,10 +70,12 @@ module RuboCop
83
70
 
84
71
  class_comparison_candidate?(node) do |receiver_node, class_node|
85
72
  range = offense_range(receiver_node, node)
86
- class_name = class_name(class_node, node)
73
+ class_argument = (class_name = class_name(class_node, node)) ? "(#{class_name})" : ''
74
+
75
+ add_offense(range, message: format(MSG, class_argument: class_argument)) do |corrector|
76
+ next unless class_name
87
77
 
88
- add_offense(range, message: format(MSG, class_name: class_name)) do |corrector|
89
- corrector.replace(range, "instance_of?(#{class_name})")
78
+ corrector.replace(range, "instance_of?#{class_argument}")
90
79
  end
91
80
  end
92
81
  end
@@ -94,19 +83,41 @@ module RuboCop
94
83
  private
95
84
 
96
85
  def class_name(class_node, node)
97
- if node.children.first.method?(:name)
98
- return class_node.receiver.source if class_node.receiver
86
+ if class_name_method?(node.children.first.method_name)
87
+ if (receiver = class_node.receiver) && class_name_method?(class_node.method_name)
88
+ return receiver.source
89
+ end
99
90
 
100
91
  if class_node.str_type?
101
- value = class_node.source.delete('"').delete("'")
102
- value.prepend('::') if class_node.each_ancestor(:class, :module).any?
92
+ value = trim_string_quotes(class_node)
93
+ value.prepend('::') if require_cbase?(class_node)
103
94
  return value
95
+ elsif unable_to_determine_type?(class_node)
96
+ # When a variable or return value of a method is used, it returns nil
97
+ # because the type is not known and cannot be suggested.
98
+ return
104
99
  end
105
100
  end
106
101
 
107
102
  class_node.source
108
103
  end
109
104
 
105
+ def class_name_method?(method_name)
106
+ CLASS_NAME_METHODS.include?(method_name)
107
+ end
108
+
109
+ def require_cbase?(class_node)
110
+ class_node.each_ancestor(:class, :module).any?
111
+ end
112
+
113
+ def unable_to_determine_type?(class_node)
114
+ class_node.variable? || class_node.call_type?
115
+ end
116
+
117
+ def trim_string_quotes(class_node)
118
+ class_node.source.delete('"').delete("'")
119
+ end
120
+
110
121
  def offense_range(receiver_node, node)
111
122
  range_between(receiver_node.loc.selector.begin_pos, node.source_range.end_pos)
112
123
  end
@@ -9,8 +9,8 @@ module RuboCop
9
9
  # @safety
10
10
  # It is unsafe by default because false positives may occur in the
11
11
  # `nil` check of block arguments to the receiver object. Additionally,
12
- # we can't know the type of the receiver object for sure, which may
13
- # result in false positives as well.
12
+ # we can't know the type of the receiver object for sure, which may
13
+ # result in false positives as well.
14
14
  #
15
15
  # For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
16
16
  # and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
@@ -19,7 +19,9 @@ module RuboCop
19
19
  # @example
20
20
  # # bad
21
21
  # array.reject(&:nil?)
22
+ # array.delete_if(&:nil?)
22
23
  # array.reject { |e| e.nil? }
24
+ # array.delete_if { |e| e.nil? }
23
25
  # array.select { |e| !e.nil? }
24
26
  #
25
27
  # # good
@@ -33,17 +35,25 @@ module RuboCop
33
35
  # # good
34
36
  # hash.compact!
35
37
  #
38
+ # @example AllowedReceivers: ['params']
39
+ # # good
40
+ # params.reject(&:nil?)
41
+ #
36
42
  class CollectionCompact < Base
43
+ include AllowedReceivers
37
44
  include RangeHelp
38
45
  extend AutoCorrector
46
+ extend TargetRubyVersion
39
47
 
40
48
  MSG = 'Use `%<good>s` instead of `%<bad>s`.'
41
- RESTRICT_ON_SEND = %i[reject reject! select select!].freeze
49
+ RESTRICT_ON_SEND = %i[reject delete_if reject! select select!].freeze
42
50
  TO_ENUM_METHODS = %i[to_enum lazy].freeze
43
51
 
52
+ minimum_target_ruby_version 2.4
53
+
44
54
  # @!method reject_method_with_block_pass?(node)
45
55
  def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
46
- (send !nil? {:reject :reject!}
56
+ (send !nil? {:reject :delete_if :reject!}
47
57
  (block_pass
48
58
  (sym :nil?)))
49
59
  PATTERN
@@ -52,7 +62,7 @@ module RuboCop
52
62
  def_node_matcher :reject_method?, <<~PATTERN
53
63
  (block
54
64
  (send
55
- !nil? {:reject :reject!})
65
+ !nil? {:reject :delete_if :reject!})
56
66
  $(args ...)
57
67
  (send
58
68
  $(lvar _) :nil?))
@@ -71,7 +81,10 @@ module RuboCop
71
81
 
72
82
  def on_send(node)
73
83
  return unless (range = offense_range(node))
74
- return if target_ruby_version <= 3.0 && to_enum_method?(node)
84
+ return if allowed_receiver?(node.receiver)
85
+ if (target_ruby_version <= 3.0 || node.method?(:delete_if)) && to_enum_method?(node)
86
+ return
87
+ end
75
88
 
76
89
  good = good_method_name(node)
77
90
  message = format(MSG, good: good, bad: range.source)
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for methods invoked via the :: operator instead
7
- # of the . operator (like FileUtils::rmdir instead of FileUtils.rmdir).
6
+ # Checks for methods invoked via the `::` operator instead
7
+ # of the `.` operator (like `FileUtils::rmdir` instead of `FileUtils.rmdir`).
8
8
  #
9
9
  # @example
10
10
  # # bad
@@ -57,38 +57,58 @@ module RuboCop
57
57
  # end
58
58
  #
59
59
  class CombinableLoops < Base
60
+ extend AutoCorrector
61
+
62
+ include RangeHelp
63
+
60
64
  MSG = 'Combine this loop with the previous loop.'
61
65
 
62
66
  def on_block(node)
63
67
  return unless node.parent&.begin_type?
64
68
  return unless collection_looping_method?(node)
69
+ return unless same_collection_looping_block?(node, node.left_sibling)
65
70
 
66
- add_offense(node) if same_collection_looping?(node, node.left_sibling)
71
+ add_offense(node) do |corrector|
72
+ combine_with_left_sibling(corrector, node)
73
+ end
67
74
  end
68
75
 
69
76
  alias on_numblock on_block
70
77
 
71
78
  def on_for(node)
72
79
  return unless node.parent&.begin_type?
80
+ return unless same_collection_looping_for?(node, node.left_sibling)
73
81
 
74
- sibling = node.left_sibling
75
- add_offense(node) if sibling&.for_type? && node.collection == sibling.collection
82
+ add_offense(node) do |corrector|
83
+ combine_with_left_sibling(corrector, node)
84
+ end
76
85
  end
77
86
 
78
87
  private
79
88
 
80
89
  def collection_looping_method?(node)
81
- # TODO: Remove `Symbol#to_s` after supporting only Ruby >= 2.7.
82
- method_name = node.method_name.to_s
90
+ method_name = node.method_name
83
91
  method_name.start_with?('each') || method_name.end_with?('_each')
84
92
  end
85
93
 
86
- def same_collection_looping?(node, sibling)
94
+ def same_collection_looping_block?(node, sibling)
87
95
  (sibling&.block_type? || sibling&.numblock_type?) &&
88
96
  sibling.send_node.method?(node.method_name) &&
89
97
  sibling.receiver == node.receiver &&
90
98
  sibling.send_node.arguments == node.send_node.arguments
91
99
  end
100
+
101
+ def same_collection_looping_for?(node, sibling)
102
+ sibling&.for_type? && node.collection == sibling.collection
103
+ end
104
+
105
+ def combine_with_left_sibling(corrector, node)
106
+ corrector.replace(
107
+ node.left_sibling.body,
108
+ "#{node.left_sibling.body.source}\n#{node.body.source}"
109
+ )
110
+ corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
111
+ end
92
112
  end
93
113
  end
94
114
  end
@@ -350,7 +350,7 @@ module RuboCop
350
350
  end
351
351
 
352
352
  def ternary_condition?(node)
353
- [node, node.children.first].any? { |n| n.if_type? && n.ternary? }
353
+ [node, node.children.first].compact.any? { |n| n.if_type? && n.ternary? }
354
354
  end
355
355
 
356
356
  def lhs_all_match?(branches)
@@ -386,7 +386,7 @@ module RuboCop
386
386
  def allowed_statements?(branches)
387
387
  return false unless branches.all?
388
388
 
389
- statements = branches.map { |branch| tail(branch) }.compact
389
+ statements = branches.filter_map { |branch| tail(branch) }
390
390
 
391
391
  lhs_all_match?(statements) && statements.none?(&:masgn_type?) &&
392
392
  assignment_types_match?(*statements)
@@ -8,8 +8,11 @@ module RuboCop
8
8
  # The default regexp for an acceptable copyright notice can be found in
9
9
  # config/default.yml. The default can be changed as follows:
10
10
  #
11
- # Style/Copyright:
12
- # Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
11
+ # [source,yaml]
12
+ # ----
13
+ # Style/Copyright:
14
+ # Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
15
+ # ----
13
16
  #
14
17
  # This regex string is treated as an unanchored regex. For each file
15
18
  # that RuboCop scans, a comment that matches this regex must be found or
@@ -82,7 +85,7 @@ module RuboCop
82
85
  def notice_found?(processed_source)
83
86
  notice_found = false
84
87
  notice_regexp = Regexp.new(notice)
85
- processed_source.each_token do |token|
88
+ processed_source.tokens.each do |token|
86
89
  break unless token.comment?
87
90
 
88
91
  notice_found = notice_regexp.match?(token.text)
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for inheritance from `Data.define` to avoid creating the anonymous parent class.
7
+ #
8
+ # @safety
9
+ # Autocorrection is unsafe because it will change the inheritance
10
+ # tree (e.g. return value of `Module#ancestors`) of the constant.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # class Person < Data.define(:first_name, :last_name)
15
+ # def age
16
+ # 42
17
+ # end
18
+ # end
19
+ #
20
+ # # good
21
+ # Person = Data.define(:first_name, :last_name) do
22
+ # def age
23
+ # 42
24
+ # end
25
+ # end
26
+ class DataInheritance < Base
27
+ include RangeHelp
28
+ extend AutoCorrector
29
+ extend TargetRubyVersion
30
+
31
+ MSG = "Don't extend an instance initialized by `Data.define`. " \
32
+ 'Use a block to customize the class.'
33
+
34
+ minimum_target_ruby_version 3.2
35
+
36
+ def on_class(node)
37
+ return unless data_define?(node.parent_class)
38
+
39
+ add_offense(node.parent_class.source_range) do |corrector|
40
+ corrector.remove(range_with_surrounding_space(node.loc.keyword, newlines: false))
41
+ corrector.replace(node.loc.operator, '=')
42
+
43
+ correct_parent(node.parent_class, corrector)
44
+ end
45
+ end
46
+
47
+ # @!method data_define?(node)
48
+ def_node_matcher :data_define?, <<~PATTERN
49
+ {(send (const {nil? cbase} :Data) :define ...)
50
+ (block (send (const {nil? cbase} :Data) :define ...) ...)}
51
+ PATTERN
52
+
53
+ private
54
+
55
+ def correct_parent(parent, corrector)
56
+ if parent.block_type?
57
+ corrector.remove(range_with_surrounding_space(parent.loc.end, newlines: false))
58
+ elsif (class_node = parent.parent).body.nil?
59
+ corrector.remove(range_for_empty_class_body(class_node, parent))
60
+ else
61
+ corrector.insert_after(parent, ' do')
62
+ end
63
+ end
64
+
65
+ def range_for_empty_class_body(class_node, data_define)
66
+ if class_node.single_line?
67
+ range_between(data_define.source_range.end_pos, class_node.source_range.end_pos)
68
+ else
69
+ range_by_whole_lines(class_node.loc.end, include_final_newline: true)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for places where the `#__dir__` method can replace more
6
+ # Checks for places where the `#\_\_dir\_\_` method can replace more
7
7
  # complex constructs to retrieve a canonicalized absolute path to the
8
8
  # current file.
9
9
  #
@@ -19,18 +19,16 @@ module RuboCop
19
19
  extend AutoCorrector
20
20
  extend TargetRubyVersion
21
21
 
22
- MSG = 'Use `Dir.empty?(%<arg>s)` instead.'
23
- RESTRICT_ON_SEND = %i[== > empty? none?].freeze
22
+ MSG = 'Use `%<replacement>s` instead.'
23
+ RESTRICT_ON_SEND = %i[== != > empty? none?].freeze
24
24
 
25
25
  minimum_target_ruby_version 2.4
26
26
 
27
27
  # @!method offensive?(node)
28
28
  def_node_matcher :offensive?, <<~PATTERN
29
29
  {
30
- (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :>} (int 2))
31
- (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :>} (int 0))
32
- (send (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) :!) {:== :>} (int 2))
33
- (send (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) :!) {:== :>} (int 0))
30
+ (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :!= :>} (int 2))
31
+ (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :!= :>} (int 0))
34
32
  (send (send $(const {nil? cbase} :Dir) :children $_) :empty?)
35
33
  (send (send $(const {nil? cbase} :Dir) :each_child $_) :none?)
36
34
  }
@@ -38,10 +36,9 @@ module RuboCop
38
36
 
39
37
  def on_send(node)
40
38
  offensive?(node) do |const_node, arg_node|
41
- add_offense(node, message: format(MSG, arg: arg_node.source)) do |corrector|
42
- bang(node)
43
- corrector.replace(node,
44
- "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
39
+ replacement = "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})"
40
+ add_offense(node, message: format(MSG, replacement: replacement)) do |corrector|
41
+ corrector.replace(node, replacement)
45
42
  end
46
43
  end
47
44
  end
@@ -49,10 +46,7 @@ module RuboCop
49
46
  private
50
47
 
51
48
  def bang(node)
52
- if (node.method?(:==) && node.child_nodes.first.method?(:!)) ||
53
- (node.method?(:>) && !node.child_nodes.first.method?(:!))
54
- '!'
55
- end
49
+ '!' if %i[!= >].include? node.method_name
56
50
  end
57
51
  end
58
52
  end
@@ -34,8 +34,8 @@ module RuboCop
34
34
  extend AutoCorrector
35
35
 
36
36
  # rubocop:enable Lint/RedundantCopDisableDirective
37
- MSG = 'Rubocop disable/enable directives are not permitted.'
38
- MSG_FOR_COPS = 'Rubocop disable/enable directives for %<cops>s are not permitted.'
37
+ MSG = 'RuboCop disable/enable directives are not permitted.'
38
+ MSG_FOR_COPS = 'RuboCop disable/enable directives for %<cops>s are not permitted.'
39
39
 
40
40
  def on_new_investigation
41
41
  processed_source.comments.each do |comment|
@@ -111,7 +111,7 @@ module RuboCop
111
111
  return if comments.none?
112
112
 
113
113
  regexp = comment_regexp(arg_node)
114
- comments.any? { |comment| regexp.match?(comment) } || regexp.match?(comments.join)
114
+ comments.any?(regexp) || regexp.match?(comments.join)
115
115
  end
116
116
 
117
117
  def preceding_comment_blocks(node)
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # declarations.
11
11
  #
12
12
  # The documentation requirement is annulled if the class or module has
13
- # a "#:nodoc:" comment next to it. Likewise, "#:nodoc: all" does the
13
+ # a `#:nodoc:` comment next to it. Likewise, `#:nodoc: all` does the
14
14
  # same for all its children.
15
15
  #
16
16
  # @example
@@ -103,12 +103,12 @@ module RuboCop
103
103
  def find_def_node_from_ascendant(node)
104
104
  return unless (parent = node.parent)
105
105
  return parent if parent.def_type? || parent.defs_type?
106
- return node.parent.child_nodes.first if define_mehod?(parent)
106
+ return node.parent.child_nodes.first if define_method?(parent)
107
107
 
108
108
  find_def_node_from_ascendant(node.parent)
109
109
  end
110
110
 
111
- def define_mehod?(node)
111
+ def define_method?(node)
112
112
  return false unless node.block_type?
113
113
 
114
114
  child = node.child_nodes.first
@@ -4,12 +4,12 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Ensures that eval methods (`eval`, `instance_eval`, `class_eval`
7
- # and `module_eval`) are given filename and line number values (`__FILE__`
8
- # and `__LINE__`). This data is used to ensure that any errors raised
7
+ # and `module_eval`) are given filename and line number values (`\_\_FILE\_\_`
8
+ # and `\_\_LINE\_\_`). This data is used to ensure that any errors raised
9
9
  # within the evaluated code will be given the correct identification
10
10
  # in a backtrace.
11
11
  #
12
- # The cop also checks that the line number given relative to `__LINE__` is
12
+ # The cop also checks that the line number given relative to `\_\_LINE\_\_` is
13
13
  # correct.
14
14
  #
15
15
  # This cop will autocorrect incorrect or missing filename and line number
@@ -57,7 +57,7 @@ module RuboCop
57
57
  extend AutoCorrector
58
58
 
59
59
  MSG = 'Pass `__FILE__` and `__LINE__` to `%<method_name>s`.'
60
- MSG_EVAL = 'Pass a binding, `__FILE__` and `__LINE__` to `eval`.'
60
+ MSG_EVAL = 'Pass a binding, `__FILE__`, and `__LINE__` to `eval`.'
61
61
  MSG_INCORRECT_FILE = 'Incorrect file for `%<method_name>s`; ' \
62
62
  'use `%<expected>s` instead of `%<actual>s`.'
63
63
  MSG_INCORRECT_LINE = 'Incorrect line number for `%<method_name>s`; ' \
@@ -210,7 +210,7 @@ module RuboCop
210
210
  def add_offense_for_missing_line(node, code)
211
211
  register_offense(node) do |corrector|
212
212
  line_str = missing_line(node, code)
213
- corrector.insert_after(node.source_range.end, ", #{line_str}")
213
+ corrector.insert_after(node.last_argument.source_range.end, ", #{line_str}")
214
214
  end
215
215
  end
216
216