rubocop 1.51.0 → 1.54.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +62 -3
  4. data/lib/rubocop/cli/command/lsp.rb +19 -0
  5. data/lib/rubocop/cli.rb +3 -0
  6. data/lib/rubocop/config_loader_resolver.rb +4 -3
  7. data/lib/rubocop/cop/base.rb +1 -1
  8. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  9. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  10. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  11. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  12. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  13. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +3 -3
  14. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  15. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  16. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  17. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  18. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  19. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  20. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  21. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  22. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  23. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -1
  24. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  25. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -1
  26. data/lib/rubocop/cop/lint/debugger.rb +9 -5
  27. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  28. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  29. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -2
  30. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  31. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  32. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +1 -2
  33. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  34. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  35. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  36. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  37. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  38. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  39. data/lib/rubocop/cop/lint/redundant_require_statement.rb +8 -3
  40. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  41. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  42. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  43. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  44. data/lib/rubocop/cop/lint/useless_assignment.rb +4 -1
  45. data/lib/rubocop/cop/lint/void.rb +12 -18
  46. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  47. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +30 -2
  48. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  49. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  50. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  51. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  52. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  53. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  54. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  55. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +3 -3
  56. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  57. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  58. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  59. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  60. data/lib/rubocop/cop/style/block_delimiters.rb +3 -3
  61. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  62. data/lib/rubocop/cop/style/class_equality_comparison.rb +17 -39
  63. data/lib/rubocop/cop/style/collection_compact.rb +6 -0
  64. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
  65. data/lib/rubocop/cop/style/dir.rb +1 -1
  66. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  67. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  68. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  69. data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -2
  70. data/lib/rubocop/cop/style/file_read.rb +2 -2
  71. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  72. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  73. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  74. data/lib/rubocop/cop/style/identical_conditional_branches.rb +6 -2
  75. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  76. data/lib/rubocop/cop/style/invertible_unless_condition.rb +1 -1
  77. data/lib/rubocop/cop/style/lambda.rb +3 -3
  78. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -4
  79. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  80. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  81. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  82. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  83. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  84. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  85. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
  86. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  87. data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -2
  88. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  89. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  90. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  91. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  92. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +3 -1
  93. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  94. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -0
  95. data/lib/rubocop/cop/style/require_order.rb +2 -1
  96. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  97. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +81 -0
  98. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  99. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  100. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  101. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  102. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  103. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  104. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  105. data/lib/rubocop/cop/util.rb +1 -1
  106. data/lib/rubocop/cop/utils/regexp_ranges.rb +100 -0
  107. data/lib/rubocop/cop/variable_force/assignment.rb +43 -4
  108. data/lib/rubocop/cop/variable_force.rb +1 -0
  109. data/lib/rubocop/cops_documentation_generator.rb +1 -1
  110. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  111. data/lib/rubocop/lsp/logger.rb +22 -0
  112. data/lib/rubocop/lsp/routes.rb +231 -0
  113. data/lib/rubocop/lsp/runtime.rb +82 -0
  114. data/lib/rubocop/lsp/server.rb +66 -0
  115. data/lib/rubocop/lsp/severity.rb +27 -0
  116. data/lib/rubocop/options.rb +11 -1
  117. data/lib/rubocop/server/client_command/exec.rb +2 -1
  118. data/lib/rubocop/version.rb +8 -4
  119. data/lib/rubocop.rb +12 -0
  120. metadata +36 -5
@@ -113,9 +113,15 @@ module RuboCop
113
113
  def check_var(node)
114
114
  return unless node.variable? || node.const_type?
115
115
 
116
- add_offense(node.loc.name,
117
- message: format(VAR_MSG, var: node.loc.name.source)) do |corrector|
118
- autocorrect_void_var(corrector, node)
116
+ if node.const_type? && node.special_keyword?
117
+ add_offense(node, message: format(VAR_MSG, var: node.source)) do |corrector|
118
+ autocorrect_void_expression(corrector, node)
119
+ end
120
+ else
121
+ add_offense(node.loc.name,
122
+ message: format(VAR_MSG, var: node.loc.name.source)) do |corrector|
123
+ autocorrect_void_expression(corrector, node)
124
+ end
119
125
  end
120
126
  end
121
127
 
@@ -123,7 +129,7 @@ module RuboCop
123
129
  return if !node.literal? || node.xstr_type? || node.range_type?
124
130
 
125
131
  add_offense(node, message: format(LIT_MSG, lit: node.source)) do |corrector|
126
- autocorrect_void_literal(corrector, node)
132
+ autocorrect_void_expression(corrector, node)
127
133
  end
128
134
  end
129
135
 
@@ -131,7 +137,7 @@ module RuboCop
131
137
  return unless node.self_type?
132
138
 
133
139
  add_offense(node, message: SELF_MSG) do |corrector|
134
- autocorrect_void_self(corrector, node)
140
+ autocorrect_void_expression(corrector, node)
135
141
  end
136
142
  end
137
143
 
@@ -144,7 +150,7 @@ module RuboCop
144
150
  end
145
151
 
146
152
  def check_nonmutating(node)
147
- return unless node.respond_to?(:method_name)
153
+ return if !node.send_type? && !node.block_type? && !node.numblock_type?
148
154
 
149
155
  method_name = node.method_name
150
156
  return unless NONMUTATING_METHODS.include?(method_name)
@@ -181,18 +187,6 @@ module RuboCop
181
187
  end
182
188
  end
183
189
 
184
- def autocorrect_void_var(corrector, node)
185
- corrector.remove(range_with_surrounding_space(range: node.loc.name, side: :left))
186
- end
187
-
188
- def autocorrect_void_literal(corrector, node)
189
- corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
190
- end
191
-
192
- def autocorrect_void_self(corrector, node)
193
- corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
194
- end
195
-
196
190
  def autocorrect_void_expression(corrector, node)
197
191
  corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
198
192
  end
@@ -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)
@@ -63,7 +63,7 @@ module RuboCop
63
63
  types
64
64
  end
65
65
 
66
- def code_length(node)
66
+ def code_length(node) # rubocop:disable Metrics/MethodLength
67
67
  if classlike_node?(node)
68
68
  classlike_code_length(node)
69
69
  elsif heredoc_node?(node)
@@ -72,7 +72,14 @@ module RuboCop
72
72
  body = extract_body(node)
73
73
  return 0 unless body
74
74
 
75
- body.source.each_line.count { |line| !irrelevant_line?(line) }
75
+ source =
76
+ if node_with_heredoc?(body)
77
+ source_from_node_with_heredoc(body)
78
+ else
79
+ body.source.lines
80
+ end
81
+
82
+ source.count { |line| !irrelevant_line?(line) }
76
83
  end
77
84
  end
78
85
 
@@ -175,6 +182,27 @@ module RuboCop
175
182
  def another_args?(node)
176
183
  node.call_type? && node.arguments.count > 1
177
184
  end
185
+
186
+ def node_with_heredoc?(node)
187
+ node.each_descendant(:str, :dstr).any? { |descendant| heredoc_node?(descendant) }
188
+ end
189
+
190
+ def source_from_node_with_heredoc(node)
191
+ last_line = -1
192
+ node.each_descendant do |descendant|
193
+ next unless descendant.source
194
+
195
+ descendant_last_line =
196
+ if heredoc_node?(descendant)
197
+ descendant.loc.heredoc_end.line
198
+ else
199
+ descendant.last_line
200
+ end
201
+
202
+ last_line = [last_line, descendant_last_line].max
203
+ end
204
+ @processed_source[(node.first_line - 1)..(last_line - 1)]
205
+ end
178
206
  end
179
207
  end
180
208
  end
@@ -16,7 +16,7 @@ module RuboCop
16
16
  # The token that makes up a disable comment.
17
17
  # The allowed specification for comments after `# rubocop: disable` is
18
18
  # `DepartmentName/CopName` or` all`.
19
- DISABLING_COPS_CONTENT_TOKEN = %r{[A-z]+/[A-z]+|all}.freeze
19
+ DISABLING_COPS_CONTENT_TOKEN = %r{[A-Za-z]+/[A-Za-z]+|all}.freeze
20
20
 
21
21
  def on_new_investigation
22
22
  processed_source.comments.each do |comment|
@@ -67,7 +67,7 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def contain_unexpected_character_for_department_name?(name)
70
- name.match?(%r{[^A-z/, ]})
70
+ name.match?(%r{[^A-Za-z/, ]})
71
71
  end
72
72
 
73
73
  def qualified_legacy_cop_name(cop_name)
@@ -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
@@ -25,7 +25,7 @@ module RuboCop
25
25
  def comments_contain_disables?(node, cop_name)
26
26
  disabled_ranges = processed_source.disabled_line_ranges[cop_name]
27
27
 
28
- return unless disabled_ranges
28
+ return false unless disabled_ranges
29
29
 
30
30
  node_range = node.source_range.line...find_end_line(node)
31
31
 
@@ -67,7 +67,7 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def variable_alignment?(whole_expression, rhs, end_alignment_style)
70
- return if end_alignment_style == :keyword
70
+ return false if end_alignment_style == :keyword
71
71
 
72
72
  !line_break_before_keyword?(whole_expression, rhs)
73
73
  end
@@ -26,11 +26,15 @@ module RuboCop
26
26
  end
27
27
 
28
28
  def delimiter_string(node)
29
- node.source.match(OPENING_DELIMITER).captures[1]
29
+ return '' unless (match = node.source.match(OPENING_DELIMITER))
30
+
31
+ match.captures[1]
30
32
  end
31
33
 
32
34
  def heredoc_type(node)
33
- node.source.match(OPENING_DELIMITER).captures[0]
35
+ return '' unless (match = node.source.match(OPENING_DELIMITER))
36
+
37
+ match.captures[0]
34
38
  end
35
39
  end
36
40
  end
@@ -9,7 +9,7 @@ module RuboCop
9
9
  private
10
10
 
11
11
  def percent_literal?(node)
12
- return unless (begin_source = begin_source(node))
12
+ return false unless (begin_source = begin_source(node))
13
13
 
14
14
  begin_source.start_with?('%')
15
15
  end
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  def use_block_argument_as_local_variable?(node, last_argument)
112
- return if node.body.nil?
112
+ return false if node.body.nil?
113
113
 
114
114
  node.body.each_descendant(:lvar, :lvasgn).any? do |lvar|
115
115
  !lvar.parent.block_pass_type? && lvar.node_parts[0].to_s == last_argument
@@ -204,14 +204,14 @@ module RuboCop
204
204
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
205
205
  def on_defined?(node)
206
206
  arg = node.arguments.first
207
- return unless arg.ivar_type?
207
+ return false unless arg.ivar_type?
208
208
 
209
209
  method_node, method_name = find_definition(node)
210
- return unless method_node
210
+ return false unless method_node
211
211
 
212
212
  var_name = arg.children.first
213
213
  defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
214
- return if matches?(method_name, ivar_assign)
214
+ return false if matches?(method_name, ivar_assign)
215
215
 
216
216
  suggested_var = suggested_var(method_name)
217
217
  msg = format(
@@ -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
@@ -35,7 +35,7 @@ module RuboCop
35
35
  unless contents.empty?
36
36
  corrector.replace(
37
37
  contents,
38
- contents.source.gsub(/\A/, '# ').gsub(/\n\n/, "\n#\n").gsub(/\n(?=[^#])/, "\n# ")
38
+ contents.source.gsub(/\A/, '# ').gsub("\n\n", "\n#\n").gsub(/\n(?=[^#])/, "\n# ")
39
39
  )
40
40
  end
41
41
  corrector.remove(eq_end)
@@ -411,7 +411,7 @@ module RuboCop
411
411
  end
412
412
 
413
413
  def correction_would_break_code?(node)
414
- return unless node.keywords?
414
+ return false unless node.keywords?
415
415
 
416
416
  node.send_node.arguments? && !node.send_node.parenthesized?
417
417
  end
@@ -433,7 +433,7 @@ module RuboCop
433
433
  end
434
434
 
435
435
  def return_value_used?(node)
436
- return unless node.parent
436
+ return false unless node.parent
437
437
 
438
438
  # If there are parentheses around the block, check if that
439
439
  # is being used.
@@ -445,7 +445,7 @@ module RuboCop
445
445
  end
446
446
 
447
447
  def return_value_of_scope?(node)
448
- return unless node.parent
448
+ return false unless node.parent
449
449
 
450
450
  conditional?(node.parent) || array_or_range?(node.parent) ||
451
451
  node.parent.children.last == node
@@ -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
@@ -361,7 +361,7 @@ module RuboCop
361
361
  end
362
362
 
363
363
  def assignment_types_match?(*nodes)
364
- return unless assignment_type?(nodes.first)
364
+ return false unless assignment_type?(nodes.first)
365
365
 
366
366
  nodes.map(&:type).uniq.one?
367
367
  end
@@ -440,6 +440,8 @@ module RuboCop
440
440
  module ConditionalCorrectorHelper
441
441
  def remove_whitespace_in_branches(corrector, branch, condition, column)
442
442
  branch.each_node do |child|
443
+ next if child.source_range.nil?
444
+
443
445
  white_space = white_space_range(child, column)
444
446
  corrector.remove(white_space) if white_space.source.strip.empty?
445
447
  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
@@ -108,7 +108,7 @@ module RuboCop
108
108
  comments = heredoc_comment_blocks(arg_node.loc.heredoc_body.line_span)
109
109
  .concat(preceding_comment_blocks(arg_node.parent))
110
110
 
111
- return if comments.none?
111
+ return false if comments.none?
112
112
 
113
113
  regexp = comment_regexp(arg_node)
114
114
  comments.any?(regexp) || regexp.match?(comments.join)
@@ -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
@@ -63,7 +63,7 @@ module RuboCop
63
63
 
64
64
  # @!method block_read?(node)
65
65
  def_node_matcher :block_read?, <<~PATTERN
66
- (block _ (args (arg $_)) (send (lvar $_) :read))
66
+ (block _ (args (arg _name)) (send (lvar _name) :read))
67
67
  PATTERN
68
68
 
69
69
  def on_send(node)
@@ -100,7 +100,7 @@ module RuboCop
100
100
  def file_open_read?(node)
101
101
  return true if send_read?(node)
102
102
 
103
- block_read?(node) { |block_arg, read_lvar| block_arg == read_lvar }
103
+ block_read?(node)
104
104
  end
105
105
 
106
106
  def read_method(mode)
@@ -28,6 +28,7 @@ module RuboCop
28
28
  # execute(sql).keys.each { |v| p v }
29
29
  # execute(sql).values.each { |v| p v }
30
30
  class HashEachMethods < Base
31
+ include AllowedReceivers
31
32
  include Lint::UnusedArgument
32
33
  extend AutoCorrector
33
34
 
@@ -116,28 +117,6 @@ module RuboCop
116
117
  def kv_range(outer_node)
117
118
  outer_node.receiver.loc.selector.join(outer_node.loc.selector)
118
119
  end
119
-
120
- def allowed_receiver?(receiver)
121
- receiver_name = receiver_name(receiver)
122
-
123
- allowed_receivers.include?(receiver_name)
124
- end
125
-
126
- def receiver_name(receiver)
127
- if receiver.send_type?
128
- if receiver.receiver
129
- "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
130
- else
131
- receiver.method_name.to_s
132
- end
133
- else
134
- receiver.source
135
- end
136
- end
137
-
138
- def allowed_receivers
139
- cop_config.fetch('AllowedReceivers', [])
140
- end
141
120
  end
142
121
  end
143
122
  end
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Looks for uses of `_.each_with_object({}) {...}`,
7
- # `_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just
6
+ # Looks for uses of `\_.each_with_object({}) {...}`,
7
+ # `\_.map {...}.to_h`, and `Hash[\_.map {...}]` that are actually just
8
8
  # transforming the keys of a hash, and tries to use a simpler & faster
9
9
  # call to `transform_keys` instead.
10
10
  # It should only be enabled on Ruby version 2.5 or newer.