rubocop 1.50.2 → 1.54.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +80 -6
  4. data/lib/rubocop/cli/command/lsp.rb +19 -0
  5. data/lib/rubocop/cli.rb +3 -0
  6. data/lib/rubocop/config.rb +4 -0
  7. data/lib/rubocop/config_loader_resolver.rb +4 -3
  8. data/lib/rubocop/config_obsoletion.rb +2 -2
  9. data/lib/rubocop/cop/base.rb +5 -1
  10. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  11. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  12. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  13. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  14. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  15. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  16. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  17. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +5 -5
  18. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  19. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  20. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  21. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  22. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  23. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  24. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  25. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  26. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  27. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  28. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -1
  29. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  30. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  31. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  32. data/lib/rubocop/cop/lint/debugger.rb +9 -5
  33. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  34. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  35. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
  36. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  37. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  38. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  39. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  40. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  41. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  42. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  43. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  44. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  45. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  46. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  47. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  48. data/lib/rubocop/cop/lint/redundant_require_statement.rb +8 -3
  49. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  50. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  51. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  52. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  53. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  54. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  55. data/lib/rubocop/cop/lint/useless_assignment.rb +59 -1
  56. data/lib/rubocop/cop/lint/void.rb +57 -7
  57. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  58. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +30 -2
  59. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  60. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  61. data/lib/rubocop/cop/mixin/comments_help.rb +7 -3
  62. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  63. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  64. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  65. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  66. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  67. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  68. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +25 -10
  69. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  70. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  71. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  72. data/lib/rubocop/cop/style/attr.rb +11 -1
  73. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  74. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  75. data/lib/rubocop/cop/style/block_delimiters.rb +3 -3
  76. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  77. data/lib/rubocop/cop/style/class_equality_comparison.rb +17 -39
  78. data/lib/rubocop/cop/style/collection_compact.rb +16 -6
  79. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  80. data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
  81. data/lib/rubocop/cop/style/conditional_assignment.rb +5 -3
  82. data/lib/rubocop/cop/style/copyright.rb +5 -2
  83. data/lib/rubocop/cop/style/dir.rb +1 -1
  84. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  85. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  86. data/lib/rubocop/cop/style/documentation.rb +1 -1
  87. data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
  88. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  89. data/lib/rubocop/cop/style/file_read.rb +2 -2
  90. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  91. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  92. data/lib/rubocop/cop/style/hash_except.rb +19 -8
  93. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  94. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  95. data/lib/rubocop/cop/style/identical_conditional_branches.rb +6 -2
  96. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  97. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  98. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  99. data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -6
  100. data/lib/rubocop/cop/style/lambda.rb +3 -3
  101. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -4
  102. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  103. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  104. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  105. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  106. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  107. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  108. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  109. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
  110. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  111. data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -3
  112. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  113. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  114. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  115. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  116. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +3 -1
  117. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  118. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -0
  119. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  120. data/lib/rubocop/cop/style/require_order.rb +11 -5
  121. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  122. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +81 -0
  123. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  124. data/lib/rubocop/cop/style/semicolon.rb +12 -1
  125. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  126. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  127. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  128. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  129. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  130. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  131. data/lib/rubocop/cop/team.rb +1 -1
  132. data/lib/rubocop/cop/util.rb +1 -1
  133. data/lib/rubocop/cop/utils/regexp_ranges.rb +100 -0
  134. data/lib/rubocop/cop/variable_force/assignment.rb +47 -4
  135. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  136. data/lib/rubocop/cop/variable_force.rb +1 -0
  137. data/lib/rubocop/cops_documentation_generator.rb +1 -1
  138. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  139. data/lib/rubocop/lsp/logger.rb +22 -0
  140. data/lib/rubocop/lsp/routes.rb +231 -0
  141. data/lib/rubocop/lsp/runtime.rb +82 -0
  142. data/lib/rubocop/lsp/server.rb +66 -0
  143. data/lib/rubocop/lsp/severity.rb +27 -0
  144. data/lib/rubocop/options.rb +11 -1
  145. data/lib/rubocop/result_cache.rb +1 -1
  146. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  147. data/lib/rubocop/server/client_command/exec.rb +2 -1
  148. data/lib/rubocop/target_ruby.rb +3 -2
  149. data/lib/rubocop/version.rb +10 -6
  150. data/lib/rubocop.rb +13 -0
  151. metadata +38 -6
@@ -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
 
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for exact regexp match inside Regexp literals.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # string =~ /\Astring\z/
12
+ # string === /\Astring\z/
13
+ # string.match(/\Astring\z/)
14
+ # string.match?(/\Astring\z/)
15
+ #
16
+ # # good
17
+ # string == 'string'
18
+ #
19
+ # # bad
20
+ # string !~ /\Astring\z/
21
+ #
22
+ # # good
23
+ # string != 'string'
24
+ #
25
+ class ExactRegexpMatch < Base
26
+ extend AutoCorrector
27
+
28
+ MSG = 'Use `%<prefer>s`.'
29
+ RESTRICT_ON_SEND = %i[=~ === !~ match match?].freeze
30
+
31
+ # @!method exact_regexp_match(node)
32
+ def_node_matcher :exact_regexp_match, <<~PATTERN
33
+ (send
34
+ _ {:=~ :=== :!~ :match :match?}
35
+ (regexp
36
+ (str $_)
37
+ (regopt)))
38
+ PATTERN
39
+
40
+ def on_send(node)
41
+ return unless (regexp = exact_regexp_match(node))
42
+
43
+ parsed_regexp = Regexp::Parser.parse(regexp)
44
+ return unless exact_match_pattern?(parsed_regexp)
45
+
46
+ prefer = "#{node.receiver.source} #{new_method(node)} '#{parsed_regexp[1].text}'"
47
+
48
+ add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
49
+ corrector.replace(node, prefer)
50
+ end
51
+ end
52
+
53
+ private
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
+
62
+ def new_method(node)
63
+ node.method?(:!~) ? '!=' : '=='
64
+ end
65
+ end
66
+ end
67
+ end
68
+ 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)
@@ -187,6 +187,8 @@ module RuboCop
187
187
  if_branch = node.if_branch
188
188
  else_branch = node.else_branch
189
189
 
190
+ corrector.replace(node.loc.begin, "\n") if node.loc.begin&.is?('then')
191
+
190
192
  if if_branch&.send_type? && heredoc?(if_branch.last_argument)
191
193
  autocorrect_heredoc_argument(corrector, node, if_branch, else_branch, guard)
192
194
  elsif else_branch&.send_type? && heredoc?(else_branch.last_argument)
@@ -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
@@ -45,13 +45,13 @@ module RuboCop
45
45
  (block
46
46
  (send _ _)
47
47
  (args
48
- (arg _)
48
+ $(arg _)
49
49
  (arg _))
50
50
  {
51
- (send
51
+ $(send
52
52
  _ {:== :!= :eql? :include?} _)
53
53
  (send
54
- (send
54
+ $(send
55
55
  _ {:== :!= :eql? :include?} _) :!)
56
56
  })
57
57
  PATTERN
@@ -61,13 +61,13 @@ module RuboCop
61
61
  (block
62
62
  (send _ _)
63
63
  (args
64
- (arg _)
64
+ $(arg _)
65
65
  (arg _))
66
66
  {
67
- (send
67
+ $(send
68
68
  _ {:== :!= :eql? :in? :include? :exclude?} _)
69
69
  (send
70
- (send
70
+ $(send
71
71
  _ {:== :!= :eql? :in? :include? :exclude?} _) :!)
72
72
  })
73
73
  PATTERN
@@ -89,13 +89,24 @@ module RuboCop
89
89
 
90
90
  private
91
91
 
92
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
92
93
  def bad_method?(block)
93
94
  if active_support_extensions_enabled?
94
- bad_method_with_active_support?(block)
95
+ bad_method_with_active_support?(block) do |key_arg, send_node|
96
+ if send_node.method?(:in?) && send_node.receiver&.source != key_arg.source
97
+ return false
98
+ end
99
+ return true if !send_node.method?(:include?) && !send_node.method?(:exclude?)
100
+
101
+ send_node.first_argument&.source == key_arg.source
102
+ end
95
103
  else
96
- bad_method_with_poro?(block)
104
+ bad_method_with_poro?(block) do |key_arg, send_node|
105
+ !send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
106
+ end
97
107
  end
98
108
  end
109
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
99
110
 
100
111
  def semantically_except_method?(send, block)
101
112
  body = block.body
@@ -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.
@@ -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 values of a hash, and tries to use a simpler & faster
9
9
  # call to `transform_values` instead.
10
10
  #
@@ -158,13 +158,16 @@ module RuboCop
158
158
  return false unless expressions.size >= 1 && unique_expressions.one?
159
159
 
160
160
  unique_expression = unique_expressions.first
161
- return true unless unique_expression.assignment?
161
+ return true unless unique_expression&.assignment?
162
162
 
163
163
  lhs = unique_expression.child_nodes.first
164
164
  node.condition.child_nodes.none? { |n| n.source == lhs.source if n.variable? }
165
165
  end
166
166
 
167
- def check_expressions(node, expressions, insert_position) # rubocop:disable Metrics/MethodLength
167
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
168
+ def check_expressions(node, expressions, insert_position)
169
+ return if expressions.any?(&:nil?)
170
+
168
171
  inserted_expression = false
169
172
 
170
173
  expressions.each do |expression|
@@ -184,6 +187,7 @@ module RuboCop
184
187
  end
185
188
  end
186
189
  end
190
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
187
191
 
188
192
  def last_child_of_parent?(node)
189
193
  return true unless (parent = node.parent)
@@ -59,11 +59,13 @@ module RuboCop
59
59
  # end
60
60
  #
61
61
  class IfInsideElse < Base
62
+ include IgnoredNode
62
63
  include RangeHelp
63
64
  extend AutoCorrector
64
65
 
65
66
  MSG = 'Convert `if` nested inside `else` to `elsif`.'
66
67
 
68
+ # rubocop:disable Metrics/CyclomaticComplexity
67
69
  def on_if(node)
68
70
  return if node.ternary? || node.unless?
69
71
 
@@ -73,9 +75,13 @@ module RuboCop
73
75
  return if allow_if_modifier_in_else_branch?(else_branch)
74
76
 
75
77
  add_offense(else_branch.loc.keyword) do |corrector|
78
+ next if part_of_ignored_node?(node)
79
+
76
80
  autocorrect(corrector, else_branch)
81
+ ignore_node(node)
77
82
  end
78
83
  end
84
+ # rubocop:enable Metrics/CyclomaticComplexity
79
85
 
80
86
  private
81
87
 
@@ -84,7 +84,10 @@ module RuboCop
84
84
  return unless (msg = message(node))
85
85
 
86
86
  add_offense(node.loc.keyword, message: format(msg, keyword: node.keyword)) do |corrector|
87
+ next if part_of_ignored_node?(node)
88
+
87
89
  autocorrect(corrector, node)
90
+ ignore_node(node)
88
91
  end
89
92
  end
90
93
 
@@ -47,7 +47,7 @@ module RuboCop
47
47
  def correct_elsif(node)
48
48
  <<~RUBY.chop
49
49
  if #{node.condition.source}
50
- #{node.if_branch.source}
50
+ #{node.if_branch&.source}
51
51
  #{build_else_branch(node.else_branch).chop}
52
52
  end
53
53
  RUBY
@@ -56,7 +56,7 @@ module RuboCop
56
56
  def build_else_branch(second_condition)
57
57
  result = <<~RUBY
58
58
  elsif #{second_condition.condition.source}
59
- #{second_condition.if_branch.source}
59
+ #{second_condition.if_branch&.source}
60
60
  RUBY
61
61
 
62
62
  if second_condition.else_branch
@@ -10,12 +10,16 @@ module RuboCop
10
10
  # Methods that can be inverted should be defined in `InverseMethods`. Note that
11
11
  # the relationship of inverse methods needs to be defined in both directions.
12
12
  # For example,
13
- # InverseMethods:
14
- # :!=: :==
15
- # :even?: :odd?
16
- # :odd?: :even?
17
13
  #
18
- # will suggest both `even?` and `odd?` to be inverted, but only `!=` (and not `==`).
14
+ # [source,yaml]
15
+ # ----
16
+ # InverseMethods:
17
+ # :!=: :==
18
+ # :even?: :odd?
19
+ # :odd?: :even?
20
+ # ----
21
+ #
22
+ # will suggest both `even?` and `odd?` to be inverted, but only `!=` (and not `==`).
19
23
  #
20
24
  # @safety
21
25
  # This cop is unsafe because it cannot be guaranteed that the method
@@ -68,7 +72,7 @@ module RuboCop
68
72
  when :begin
69
73
  invertible?(node.children.first)
70
74
  when :send
71
- return if inheritance_check?(node)
75
+ return false if inheritance_check?(node)
72
76
 
73
77
  node.method?(:!) || inverse_methods.key?(node.method_name)
74
78
  when :or, :and
@@ -69,10 +69,10 @@ module RuboCop
69
69
  return unless offending_selector?(node, selector)
70
70
 
71
71
  add_offense(node.send_node.source_range, message: message(node, selector)) do |corrector|
72
- if node.send_node.source == 'lambda'
73
- autocorrect_method_to_literal(corrector, node)
74
- else
72
+ if node.send_node.lambda_literal?
75
73
  LambdaLiteralToMethodCorrector.new(node).call(corrector)
74
+ else
75
+ autocorrect_method_to_literal(corrector, node)
76
76
  end
77
77
  end
78
78
  end
@@ -98,7 +98,7 @@ module RuboCop
98
98
 
99
99
  def call_in_literals?(node)
100
100
  parent = node.parent&.block_type? ? node.parent.parent : node.parent
101
- return unless parent
101
+ return false unless parent
102
102
 
103
103
  parent.pair_type? ||
104
104
  parent.array_type? ||
@@ -109,7 +109,7 @@ module RuboCop
109
109
 
110
110
  def call_in_logical_operators?(node)
111
111
  parent = node.parent&.block_type? ? node.parent.parent : node.parent
112
- return unless parent
112
+ return false unless parent
113
113
 
114
114
  logical_operator?(parent) ||
115
115
  (parent.send_type? &&
@@ -135,8 +135,7 @@ module RuboCop
135
135
  end
136
136
 
137
137
  def call_with_braced_block?(node)
138
- (node.send_type? || node.super_type?) &&
139
- ((node.parent&.block_type? || node.parent&.numblock_type?) && node.parent&.braces?)
138
+ (node.send_type? || node.super_type?) && node.block_node&.braces?
140
139
  end
141
140
 
142
141
  def call_as_argument_or_chain?(node)
@@ -40,6 +40,15 @@ module RuboCop
40
40
  #
41
41
  # # good
42
42
  # foo if [b.lightweight, b.heavyweight].include?(a)
43
+ #
44
+ # @example ComparisonsThreshold: 2 (default)
45
+ # # bad
46
+ # foo if a == 'a' || a == 'b'
47
+ #
48
+ # @example ComparisonsThreshold: 3
49
+ # # good
50
+ # foo if a == 'a' || a == 'b'
51
+ #
43
52
  class MultipleComparison < Base
44
53
  extend AutoCorrector
45
54
 
@@ -58,6 +67,7 @@ module RuboCop
58
67
  return unless node == root_of_or_node
59
68
  return unless nested_variable_comparison?(root_of_or_node)
60
69
  return if @allowed_method_comparison
70
+ return if @compared_elements.size < comparisons_threshold
61
71
 
62
72
  add_offense(node) do |corrector|
63
73
  elements = @compared_elements.join(', ')
@@ -151,6 +161,10 @@ module RuboCop
151
161
  def allow_method_comparison?
152
162
  cop_config.fetch('AllowMethodComparison', true)
153
163
  end
164
+
165
+ def comparisons_threshold
166
+ cop_config.fetch('ComparisonsThreshold', 2)
167
+ end
154
168
  end
155
169
  end
156
170
  end
@@ -121,7 +121,7 @@ module RuboCop
121
121
 
122
122
  def allowed_patterns
123
123
  # Convert the patterns to be anchored
124
- super.map { |regexp| Regexp.new(/\A#{regexp}\z/) }
124
+ super.map { |regexp| /\A#{regexp}\z/ }
125
125
  end
126
126
  end
127
127
  end
@@ -93,7 +93,7 @@ module RuboCop
93
93
  def contains_delimiter?(node, delimiters)
94
94
  delimiters_regexp = Regexp.union(delimiters)
95
95
 
96
- node.children.map { |n| string_source(n) }.compact.any?(delimiters_regexp)
96
+ node.children.filter_map { |n| string_source(n) }.any?(delimiters_regexp)
97
97
  end
98
98
 
99
99
  def string_source(node)
@@ -61,7 +61,7 @@ module RuboCop
61
61
  if style == :verbose
62
62
  "has_#{method_name}"
63
63
  else
64
- method_name.to_s.sub(/has_/, '')
64
+ method_name.to_s.delete_prefix('has_')
65
65
  end
66
66
  end
67
67
 
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for the instantiation of array using redundant `Array` constructor.
7
+ # Autocorrect replaces to array literal which is the simplest and fastest.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Array.new([])
13
+ # Array[]
14
+ # Array([])
15
+ # Array.new(['foo', 'foo', 'foo'])
16
+ # Array['foo', 'foo', 'foo']
17
+ # Array(['foo', 'foo', 'foo'])
18
+ #
19
+ # # good
20
+ # []
21
+ # ['foo', 'foo', 'foo']
22
+ # Array.new(3, 'foo')
23
+ # Array.new(3) { 'foo' }
24
+ #
25
+ class RedundantArrayConstructor < Base
26
+ extend AutoCorrector
27
+
28
+ MSG = 'Remove the redundant `Array` constructor.'
29
+
30
+ RESTRICT_ON_SEND = %i[new [] Array].freeze
31
+
32
+ # @!method redundant_array_constructor(node)
33
+ def_node_matcher :redundant_array_constructor, <<~PATTERN
34
+ {
35
+ (send
36
+ (const {nil? cbase} :Array) :new
37
+ $(array ...))
38
+ (send
39
+ (const {nil? cbase} :Array) :[]
40
+ $...)
41
+ (send
42
+ nil? :Array
43
+ $(array ...))
44
+ }
45
+ PATTERN
46
+
47
+ def on_send(node)
48
+ return unless (array_literal = redundant_array_constructor(node))
49
+
50
+ receiver = node.receiver
51
+ selector = node.loc.selector
52
+
53
+ if node.method?(:new)
54
+ range = receiver.source_range.join(selector)
55
+ replacement = array_literal
56
+ elsif node.method?(:Array)
57
+ range = selector
58
+ replacement = array_literal
59
+ else
60
+ range = receiver
61
+ replacement = selector.begin.join(node.source_range.end)
62
+ end
63
+
64
+ register_offense(range, node, replacement)
65
+ end
66
+
67
+ private
68
+
69
+ def register_offense(range, node, replacement)
70
+ add_offense(range) do |corrector|
71
+ corrector.replace(node, replacement.source)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -146,7 +146,7 @@ module RuboCop
146
146
  end
147
147
 
148
148
  def use_modifier_form_after_multiline_begin_block?(node)
149
- return unless (parent = node.parent)
149
+ return false unless (parent = node.parent)
150
150
 
151
151
  node.multiline? && parent.if_type? && parent.modifier_form?
152
152
  end
@@ -63,7 +63,7 @@ module RuboCop
63
63
  RUBY
64
64
 
65
65
  def offense?(node)
66
- return if node.modifier_form?
66
+ return false if node.modifier_form?
67
67
 
68
68
  redundant_condition?(node) || redundant_condition_inverted?(node)
69
69
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for uses a redundant current directory in path.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # require_relative './path/to/feature'
12
+ #
13
+ # # good
14
+ # require_relative 'path/to/feature'
15
+ #
16
+ class RedundantCurrentDirectoryInPath < Base
17
+ include RangeHelp
18
+ extend AutoCorrector
19
+
20
+ MSG = 'Remove the redundant current directory path.'
21
+ CURRENT_DIRECTORY_PATH = './'
22
+
23
+ def on_send(node)
24
+ return unless node.method?(:require_relative)
25
+ return unless node.first_argument.str_content&.start_with?(CURRENT_DIRECTORY_PATH)
26
+ return unless (index = node.first_argument.source.index(CURRENT_DIRECTORY_PATH))
27
+
28
+ begin_pos = node.first_argument.source_range.begin.begin_pos + index
29
+ range = range_between(begin_pos, begin_pos + 2)
30
+
31
+ add_offense(range) do |corrector|
32
+ corrector.remove(range)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end