rubocop 1.51.0 → 1.52.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +20 -2
  4. data/lib/rubocop/cop/base.rb +1 -1
  5. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  6. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +0 -1
  7. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -1
  8. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -2
  9. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  10. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +1 -2
  11. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  12. data/lib/rubocop/cop/lint/missing_super.rb +3 -0
  13. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  14. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  15. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  16. data/lib/rubocop/cop/lint/useless_assignment.rb +4 -1
  17. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  18. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  19. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  20. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  21. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  22. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  23. data/lib/rubocop/cop/style/class_equality_comparison.rb +17 -39
  24. data/lib/rubocop/cop/style/collection_compact.rb +6 -0
  25. data/lib/rubocop/cop/style/dir.rb +1 -1
  26. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  27. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  28. data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -2
  29. data/lib/rubocop/cop/style/file_read.rb +2 -2
  30. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  31. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  32. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  33. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -2
  34. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  35. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  36. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  37. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  38. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  39. data/lib/rubocop/cop/style/require_order.rb +2 -1
  40. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  41. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  42. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  43. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  44. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  45. data/lib/rubocop/cop/variable_force/assignment.rb +29 -1
  46. data/lib/rubocop/cop/variable_force.rb +1 -0
  47. data/lib/rubocop/server/client_command/exec.rb +2 -1
  48. data/lib/rubocop/version.rb +8 -4
  49. data/lib/rubocop.rb +4 -0
  50. metadata +13 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0863dd1792c6296e51bcdbbc4503423cbc61f66c40a7120b405f4eaf999349be'
4
- data.tar.gz: a4998dfeef1e7f82ffac34fb409494859b28afba9ce6bb007f6ca5870a5e371b
3
+ metadata.gz: 84bada99408af7ceb29d5c6bb4e188f61b27a78cb52639bcbbb144a289ebbc92
4
+ data.tar.gz: 930174d41acdfd3e0f7da8ef80c496ce7e5b68e5b00312d692a2cd93605fa70a
5
5
  SHA512:
6
- metadata.gz: 1ff6067cf16502e16e5bf6691717f97b5f0cf34bdd03e0d893ee90185af1a26d5622c394b5b586530a9d596f8f92cdff4b5eb351d305fc8a2206906f903c9606
7
- data.tar.gz: 2ab3c9a30731adbd8818bfce7fba9f346ac8f66a3b0a52fe2ee65094a7ed580f617fa776664f59df71d6229cf35e3e9ad74a557ec6a760dcbc6d85ae1008a2bb
6
+ metadata.gz: 9c1f475617dc4826cef3c543ed35e65117bd93ff6f80605adc2096a06ddb38f9171a95800685a92103924600158ac306c27c9168cea787d5f11dc0616bd1a9ba
7
+ data.tar.gz: 9aaba3f7148469ce255ee22950f7c11542ca1e8480388493ab90c728831e47eef306372c42769a535beaba95d2d715c4b59161852689468cbd3fcd2c2236a535
data/README.md CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
53
  in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 1.51', require: false
56
+ gem 'rubocop', '~> 1.52', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -2484,10 +2484,9 @@ Lint/UselessRuby2Keywords:
2484
2484
  Lint/UselessSetterCall:
2485
2485
  Description: 'Checks for useless setter call to a local variable.'
2486
2486
  Enabled: true
2487
- SafeAutoCorrect: false
2487
+ Safe: false
2488
2488
  VersionAdded: '0.13'
2489
2489
  VersionChanged: '1.2'
2490
- Safe: false
2491
2490
 
2492
2491
  Lint/UselessTimes:
2493
2492
  Description: 'Checks for useless `Integer#times` calls.'
@@ -3363,6 +3362,7 @@ Style/CollectionCompact:
3363
3362
  Safe: false
3364
3363
  VersionAdded: '1.2'
3365
3364
  VersionChanged: '1.3'
3365
+ AllowedReceivers: []
3366
3366
 
3367
3367
  # Align with the style guide.
3368
3368
  Style/CollectionMethods:
@@ -4383,6 +4383,7 @@ Style/MultipleComparison:
4383
4383
  VersionAdded: '0.49'
4384
4384
  VersionChanged: '1.1'
4385
4385
  AllowMethodComparison: true
4386
+ ComparisonsThreshold: 2
4386
4387
 
4387
4388
  Style/MutableConstant:
4388
4389
  Description: 'Do not assign mutable objects to constants.'
@@ -4805,6 +4806,11 @@ Style/RedundantArgument:
4805
4806
  # String#chomp!
4806
4807
  chomp!: "\n"
4807
4808
 
4809
+ Style/RedundantArrayConstructor:
4810
+ Description: 'Checks for the instantiation of array using redundant `Array` constructor.'
4811
+ Enabled: pending
4812
+ VersionAdded: '1.52'
4813
+
4808
4814
  Style/RedundantAssignment:
4809
4815
  Description: 'Checks for redundant assignment before returning.'
4810
4816
  Enabled: true
@@ -4876,6 +4882,13 @@ Style/RedundantFileExtensionInRequire:
4876
4882
  Enabled: true
4877
4883
  VersionAdded: '0.88'
4878
4884
 
4885
+ Style/RedundantFilterChain:
4886
+ Description: >-
4887
+ Identifies usages of `any?`, `empty?`, `none?` or `one?` predicate methods chained to
4888
+ `select`/`filter`/`find_all` and change them to use predicate method instead.
4889
+ Enabled: pending
4890
+ VersionAdded: '1.52'
4891
+
4879
4892
  Style/RedundantFreeze:
4880
4893
  Description: "Checks usages of Object#freeze on immutable objects."
4881
4894
  Enabled: true
@@ -4923,6 +4936,11 @@ Style/RedundantRegexpCharacterClass:
4923
4936
  Enabled: true
4924
4937
  VersionAdded: '0.85'
4925
4938
 
4939
+ Style/RedundantRegexpConstructor:
4940
+ Description: 'Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.'
4941
+ Enabled: pending
4942
+ VersionAdded: '1.52'
4943
+
4926
4944
  Style/RedundantRegexpEscape:
4927
4945
  Description: 'Checks for redundant escapes in Regexps.'
4928
4946
  Enabled: true
@@ -284,7 +284,7 @@ module RuboCop
284
284
  # @api private
285
285
  def self.callbacks_needed
286
286
  @callbacks_needed ||= public_instance_methods.select do |m|
287
- m.match?(/^on_|^after_/) &&
287
+ m.start_with?(/on_|after_/) &&
288
288
  !Base.method_defined?(m) # exclude standard "callbacks" like 'on_begin_investigation'
289
289
  end
290
290
  end
@@ -12,6 +12,13 @@ module RuboCop
12
12
  # ....
13
13
  # end
14
14
  #
15
+ # # bad
16
+ # #
17
+ # # Checks ...
18
+ # class SomeCop < Base
19
+ # ...
20
+ # end
21
+ #
15
22
  # # good
16
23
  # # Checks ...
17
24
  # class SomeCop < Base
@@ -21,27 +28,47 @@ module RuboCop
21
28
  class CopDescription < Base
22
29
  extend AutoCorrector
23
30
 
24
- MSG = 'Description should be started with %<suggestion>s instead of `This cop ...`.'
31
+ MSG_STARTS_WITH_WRONG_WORD =
32
+ 'Description should be started with %<suggestion>s instead of `This cop ...`.'
33
+ MSG_STARTS_WITH_EMPTY_COMMENT_LINE =
34
+ 'Description should not start with an empty comment line.'
25
35
 
26
36
  SPECIAL_WORDS = %w[is can could should will would must may].freeze
27
37
  COP_DESC_OFFENSE_REGEX =
28
38
  /^\s+# This cop (?<special>#{SPECIAL_WORDS.join('|')})?\s*(?<word>.+?) .*/.freeze
29
39
  REPLACEMENT_REGEX = /^\s+# This cop (#{SPECIAL_WORDS.join('|')})?\s*(.+?) /.freeze
40
+ EMPTY_COMMENT_LINE_REGEX = /\A\s*#\s*\n\z/.freeze
30
41
 
31
- # rubocop:disable Metrics/CyclomaticComplexity
32
42
  def on_class(node)
33
43
  return unless (module_node = node.parent) && node.parent_class
34
44
 
35
45
  description_beginning = first_comment_line(module_node)
36
46
  return unless description_beginning
37
47
 
38
- start_with_subject = description_beginning.match(COP_DESC_OFFENSE_REGEX)
39
- return unless start_with_subject
48
+ if description_beginning.match?(EMPTY_COMMENT_LINE_REGEX)
49
+ register_offense_for_empty_comment_line(module_node, description_beginning)
50
+ else
51
+ start_with_subject = description_beginning.match(COP_DESC_OFFENSE_REGEX)
52
+ return unless start_with_subject
53
+
54
+ register_offense_for_wrong_word(module_node, description_beginning, start_with_subject)
55
+ end
56
+ end
57
+
58
+ private
40
59
 
60
+ def register_offense_for_empty_comment_line(module_node, description_beginning)
61
+ range = range(module_node, description_beginning)
62
+ add_offense(range, message: MSG_STARTS_WITH_EMPTY_COMMENT_LINE) do |corrector|
63
+ corrector.remove(range)
64
+ end
65
+ end
66
+
67
+ def register_offense_for_wrong_word(module_node, description_beginning, start_with_subject)
41
68
  suggestion = start_with_subject['word']&.capitalize
42
69
  range = range(module_node, description_beginning)
43
70
  suggestion_for_message = suggestion_for_message(suggestion, start_with_subject)
44
- message = format(MSG, suggestion: suggestion_for_message)
71
+ message = format(MSG_STARTS_WITH_WRONG_WORD, suggestion: suggestion_for_message)
45
72
 
46
73
  add_offense(range, message: message) do |corrector|
47
74
  if suggestion && !start_with_subject['special']
@@ -49,9 +76,6 @@ module RuboCop
49
76
  end
50
77
  end
51
78
  end
52
- # rubocop:enable Metrics/CyclomaticComplexity
53
-
54
- private
55
79
 
56
80
  def replace_with_suggestion(corrector, range, suggestion, description_beginning)
57
81
  replacement = description_beginning.gsub(REPLACEMENT_REGEX, "#{suggestion} ")
@@ -3,7 +3,6 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- #
7
6
  # Checks the indentation of here document closings.
8
7
  #
9
8
  # @example
@@ -97,7 +97,8 @@ module RuboCop
97
97
  def wrap_in_parentheses(corrector, node)
98
98
  range = node.loc.selector.end.join(node.first_argument.source_range.begin)
99
99
 
100
- corrector.replace(range, '(')
100
+ corrector.remove(range)
101
+ corrector.insert_before(range, '(')
101
102
  corrector.insert_after(node.last_argument, ')')
102
103
  end
103
104
  end
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- #
7
- # This cop emulates the following Ruby warnings in Ruby 2.6.
6
+ # Emulates the following Ruby warnings in Ruby 2.6.
8
7
  #
9
8
  # [source,console]
10
9
  # ----
@@ -3,7 +3,6 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- #
7
6
  # Prefer `equal?` over `==` when comparing `object_id`.
8
7
  #
9
8
  # `Object#equal?` is provided to compare objects for identity, and in contrast
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- #
7
- # This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
6
+ # Checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
8
7
  #
9
8
  # When an array of IO objects waiting for an exception (the third argument of `IO.select`)
10
9
  # is used as an argument, there is no alternative API, so offenses are not registered.
@@ -58,6 +58,7 @@ module RuboCop
58
58
 
59
59
  def on_class(node)
60
60
  return unless node.parent_class && exception_class?(node.parent_class)
61
+ return if inherit_exception_class_with_omitted_namespace?(node)
61
62
 
62
63
  message = message(node.parent_class)
63
64
 
@@ -87,6 +88,14 @@ module RuboCop
87
88
  class_node.const_name == 'Exception'
88
89
  end
89
90
 
91
+ def inherit_exception_class_with_omitted_namespace?(class_node)
92
+ return false if class_node.parent_class.namespace&.cbase_type?
93
+
94
+ class_node.left_siblings.any? do |sibling|
95
+ sibling.respond_to?(:identifier) && exception_class?(sibling.identifier)
96
+ end
97
+ end
98
+
90
99
  def preferred_base_class
91
100
  PREFERRED_BASE_CLASS[style]
92
101
  end
@@ -11,6 +11,9 @@ module RuboCop
11
11
  # missing method. In other cases, the theoretical ideal handling could be
12
12
  # challenging or verbose for no actual gain.
13
13
  #
14
+ # Autocorrection is not supported because the position of `super` cannot be
15
+ # determined automatically.
16
+ #
14
17
  # @example
15
18
  # # bad
16
19
  # class Employee < Person
@@ -3,7 +3,6 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- #
7
6
  # Checks the proper ordering of magic comments and whether
8
7
  # a magic comment is not placed before a shebang.
9
8
  #
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- #
7
- # This cop checks for `send`, `public_send`, and `__send__` methods
6
+ # Checks for `send`, `public_send`, and `__send__` methods
8
7
  # when using mix-in.
9
8
  #
10
9
  # `include` and `prepend` methods were private methods until Ruby 2.0,
@@ -121,18 +121,12 @@ module RuboCop
121
121
 
122
122
  if rescued_exceptions.any?
123
123
  rescued_exceptions.each_with_object([]) do |exception, converted|
124
- # FIXME: Workaround `rubocop:disable` comment for JRuby.
125
- # https://github.com/jruby/jruby/issues/6642
126
- # rubocop:disable Style/RedundantBegin
127
- begin
128
- RuboCop::Util.silence_warnings do
129
- # Avoid printing deprecation warnings about constants
130
- converted << Kernel.const_get(exception.source)
131
- end
132
- rescue NameError
133
- converted << nil
124
+ RuboCop::Util.silence_warnings do
125
+ # Avoid printing deprecation warnings about constants
126
+ converted << Kernel.const_get(exception.source)
134
127
  end
135
- # rubocop:enable Style/RedundantBegin
128
+ rescue NameError
129
+ converted << nil
136
130
  end
137
131
  else
138
132
  # treat an empty `rescue` as `rescue StandardError`
@@ -132,10 +132,12 @@ module RuboCop
132
132
  node.receiver.nil? && !node.arguments?
133
133
  end
134
134
 
135
+ # rubocop:disable Metrics/AbcSize
135
136
  def autocorrect(corrector, assignment)
136
137
  if assignment.exception_assignment?
137
138
  remove_exception_assignment_part(corrector, assignment.node)
138
- elsif assignment.multiple_assignment?
139
+ elsif assignment.multiple_assignment? || assignment.rest_assignment? ||
140
+ assignment.for_assignment?
139
141
  rename_variable_with_underscore(corrector, assignment.node)
140
142
  elsif assignment.operator_assignment?
141
143
  remove_trailing_character_from_operator(corrector, assignment.node)
@@ -146,6 +148,7 @@ module RuboCop
146
148
  remove_local_variable_assignment_part(corrector, assignment.node)
147
149
  end
148
150
  end
151
+ # rubocop:enable Metrics/AbcSize
149
152
 
150
153
  def remove_exception_assignment_part(corrector, node)
151
154
  corrector.remove(
@@ -117,8 +117,7 @@ module RuboCop
117
117
  end
118
118
 
119
119
  def capturing_variable?(name)
120
- # TODO: Remove `Symbol#to_s` after supporting only Ruby >= 2.7.
121
- name && !name.to_s.start_with?('_')
120
+ name && !name.start_with?('_')
122
121
  end
123
122
 
124
123
  def branch?(node)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This module encapsulates the ability to allow certain receivers in a cop.
6
+ module AllowedReceivers
7
+ def allowed_receiver?(receiver)
8
+ receiver_name = receiver_name(receiver)
9
+
10
+ allowed_receivers.include?(receiver_name)
11
+ end
12
+
13
+ def receiver_name(receiver)
14
+ if receiver.receiver && !receiver.receiver.const_type?
15
+ return receiver_name(receiver.receiver)
16
+ end
17
+
18
+ if receiver.send_type?
19
+ if receiver.receiver
20
+ "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
21
+ else
22
+ receiver.method_name.to_s
23
+ end
24
+ else
25
+ receiver.source
26
+ end
27
+ end
28
+
29
+ def allowed_receivers
30
+ cop_config.fetch('AllowedReceivers', [])
31
+ end
32
+ end
33
+ end
34
+ end
@@ -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
@@ -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
@@ -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,53 +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)
24
- #
25
- # # bad
26
- # var.class == Date
27
- # var.class.equal?(Date)
28
- # var.class.eql?(Date)
29
- # var.class.name == 'Date'
30
- # var.class.to_s == 'Date'
31
- # var.class.inspect == 'Date'
23
+ # def ==(other)
24
+ # self.class == other.class && name == other.name
25
+ # end
32
26
  #
33
- # @example AllowedMethods: [`==`]
34
- # # good
35
- # var.instance_of?(Date)
36
- # var.class == Date
37
- # var.class.name == 'Date'
38
- # var.class.to_s == 'Date'
39
- # var.class.inspect == 'Date'
27
+ # def equal?(other)
28
+ # self.class.equal?(other.class) && name.equal?(other.name)
29
+ # end
40
30
  #
41
- # # bad
42
- # var.class.equal?(Date)
43
- # var.class.eql?(Date)
31
+ # def eql?(other)
32
+ # self.class.eql?(other.class) && name.eql?(other.name)
33
+ # end
44
34
  #
45
35
  # @example AllowedPatterns: [] (default)
46
- # # good
47
- # var.instance_of?(Date)
48
- #
49
36
  # # bad
50
- # var.class == Date
51
- # var.class.equal?(Date)
52
- # var.class.eql?(Date)
53
- # var.class.name == 'Date'
54
- # var.class.to_s == 'Date'
55
- # var.class.inspect == 'Date'
37
+ # def eq(other)
38
+ # self.class.eq(other.class) && name.eq(other.name)
39
+ # end
56
40
  #
57
41
  # @example AllowedPatterns: ['eq']
58
42
  # # good
59
- # var.instance_of?(Date)
60
- # var.class.equal?(Date)
61
- # var.class.eql?(Date)
62
- #
63
- # # bad
64
- # var.class == Date
65
- # var.class.name == 'Date'
66
- # var.class.to_s == 'Date'
67
- # var.class.inspect == 'Date'
43
+ # def eq(other)
44
+ # self.class.eq(other.class) && name.eq(other.name)
45
+ # end
68
46
  #
69
47
  class ClassEqualityComparison < Base
70
48
  include RangeHelp
@@ -35,7 +35,12 @@ module RuboCop
35
35
  # # good
36
36
  # hash.compact!
37
37
  #
38
+ # @example AllowedReceivers: ['params']
39
+ # # good
40
+ # params.reject(&:nil?)
41
+ #
38
42
  class CollectionCompact < Base
43
+ include AllowedReceivers
39
44
  include RangeHelp
40
45
  extend AutoCorrector
41
46
  extend TargetRubyVersion
@@ -76,6 +81,7 @@ module RuboCop
76
81
 
77
82
  def on_send(node)
78
83
  return unless (range = offense_range(node))
84
+ return if allowed_receiver?(node.receiver)
79
85
  if (target_ruby_version <= 3.0 || node.method?(:delete_if)) && to_enum_method?(node)
80
86
  return
81
87
  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
@@ -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`; ' \
@@ -41,8 +41,7 @@ module RuboCop
41
41
  return unless (regexp = exact_regexp_match(node))
42
42
 
43
43
  parsed_regexp = Regexp::Parser.parse(regexp)
44
- tokens = parsed_regexp.map(&:token)
45
- return unless tokens[0] == :bos && tokens[1] == :literal && tokens[2] == :eos
44
+ return unless exact_match_pattern?(parsed_regexp)
46
45
 
47
46
  prefer = "#{node.receiver.source} #{new_method(node)} '#{parsed_regexp[1].text}'"
48
47
 
@@ -53,6 +52,13 @@ module RuboCop
53
52
 
54
53
  private
55
54
 
55
+ def exact_match_pattern?(parsed_regexp)
56
+ tokens = parsed_regexp.map(&:token)
57
+ return false unless tokens[0] == :bos && tokens[1] == :literal && tokens[2] == :eos
58
+
59
+ !parsed_regexp[1].quantifier
60
+ end
61
+
56
62
  def new_method(node)
57
63
  node.method?(:!~) ? '!=' : '=='
58
64
  end