rubocop 1.37.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +6 -0
  4. data/lib/rubocop/cli/command/suggest_extensions.rb +8 -1
  5. data/lib/rubocop/comment_config.rb +36 -1
  6. data/lib/rubocop/cop/commissioner.rb +3 -1
  7. data/lib/rubocop/cop/internal_affairs/create_empty_file.rb +37 -0
  8. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +111 -0
  9. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  10. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  11. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  12. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -0
  13. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +6 -2
  14. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  15. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
  16. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +11 -0
  17. data/lib/rubocop/cop/lint/redundant_require_statement.rb +10 -2
  18. data/lib/rubocop/cop/mixin/surrounding_space.rb +4 -3
  19. data/lib/rubocop/cop/registry.rb +10 -4
  20. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  21. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  22. data/lib/rubocop/cop/style/character_literal.rb +1 -1
  23. data/lib/rubocop/cop/style/collection_compact.rb +6 -2
  24. data/lib/rubocop/cop/style/guard_clause.rb +62 -21
  25. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +25 -2
  26. data/lib/rubocop/cop/style/module_function.rb +28 -6
  27. data/lib/rubocop/cop/style/operator_method_call.rb +2 -1
  28. data/lib/rubocop/cop/style/redundant_each.rb +111 -0
  29. data/lib/rubocop/cop/style/redundant_string_escape.rb +13 -5
  30. data/lib/rubocop/cop/team.rb +3 -4
  31. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  32. data/lib/rubocop/cops_documentation_generator.rb +4 -2
  33. data/lib/rubocop/ext/processed_source.rb +2 -0
  34. data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
  35. data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
  36. data/lib/rubocop/options.rb +6 -2
  37. data/lib/rubocop/rspec/cop_helper.rb +21 -1
  38. data/lib/rubocop/rspec/shared_contexts.rb +13 -12
  39. data/lib/rubocop/runner.rb +15 -11
  40. data/lib/rubocop/server/core.rb +1 -0
  41. data/lib/rubocop/version.rb +1 -1
  42. data/lib/rubocop.rb +1 -0
  43. metadata +8 -5
@@ -10,6 +10,9 @@ module RuboCop
10
10
  # one of `return`, `break`, `next`, `raise`, or `fail` is used
11
11
  # in the body of the conditional expression.
12
12
  #
13
+ # NOTE: Autocorrect works in most cases except with if-else statements
14
+ # that contain logical operators such as `foo || raise('exception')`
15
+ #
13
16
  # @example
14
17
  # # bad
15
18
  # def test
@@ -90,6 +93,7 @@ module RuboCop
90
93
  # end
91
94
  #
92
95
  class GuardClause < Base
96
+ extend AutoCorrector
93
97
  include MinBodyLength
94
98
  include StatementModifier
95
99
 
@@ -101,40 +105,49 @@ module RuboCop
101
105
 
102
106
  return unless body
103
107
 
104
- if body.if_type?
105
- check_ending_if(body)
106
- elsif body.begin_type?
107
- final_expression = body.children.last
108
- check_ending_if(final_expression) if final_expression&.if_type?
109
- end
108
+ check_ending_body(body)
110
109
  end
111
110
  alias on_defs on_def
112
111
 
113
112
  def on_if(node)
114
113
  return if accepted_form?(node)
115
114
 
116
- guard_clause_in_if = node.if_branch&.guard_clause?
117
- guard_clause_in_else = node.else_branch&.guard_clause?
118
- guard_clause = guard_clause_in_if || guard_clause_in_else
119
- return unless guard_clause
115
+ if (guard_clause = node.if_branch&.guard_clause?)
116
+ kw = node.loc.keyword.source
117
+ guard = :if
118
+ elsif (guard_clause = node.else_branch&.guard_clause?)
119
+ kw = node.inverse_keyword
120
+ guard = :else
121
+ else
122
+ return
123
+ end
120
124
 
121
- kw = if guard_clause_in_if
122
- node.loc.keyword.source
123
- else
124
- node.inverse_keyword
125
- end
125
+ guard = nil if and_or_guard_clause?(guard_clause)
126
126
 
127
- register_offense(node, guard_clause_source(guard_clause), kw)
127
+ register_offense(node, guard_clause_source(guard_clause), kw, guard)
128
128
  end
129
129
 
130
130
  private
131
131
 
132
+ def check_ending_body(body)
133
+ return if body.nil?
134
+
135
+ if body.if_type?
136
+ check_ending_if(body)
137
+ elsif body.begin_type?
138
+ final_expression = body.children.last
139
+ check_ending_if(final_expression) if final_expression&.if_type?
140
+ end
141
+ end
142
+
132
143
  def check_ending_if(node)
133
144
  return if accepted_form?(node, ending: true) || !min_body_length?(node)
134
145
  return if allowed_consecutive_conditionals? &&
135
146
  consecutive_conditionals?(node.parent, node)
136
147
 
137
148
  register_offense(node, 'return', node.inverse_keyword)
149
+
150
+ check_ending_body(node.if_branch)
138
151
  end
139
152
 
140
153
  def consecutive_conditionals?(parent, node)
@@ -145,28 +158,56 @@ module RuboCop
145
158
  end
146
159
  end
147
160
 
148
- def register_offense(node, scope_exiting_keyword, conditional_keyword)
161
+ def register_offense(node, scope_exiting_keyword, conditional_keyword, guard = nil)
149
162
  condition, = node.node_parts
150
163
  example = [scope_exiting_keyword, conditional_keyword, condition.source].join(' ')
151
164
  if too_long_for_single_line?(node, example)
152
165
  return if trivial?(node)
153
166
 
154
167
  example = "#{conditional_keyword} #{condition.source}; #{scope_exiting_keyword}; end"
168
+ replacement = <<~RUBY.chomp
169
+ #{conditional_keyword} #{condition.source}
170
+ #{scope_exiting_keyword}
171
+ end
172
+ RUBY
155
173
  end
156
174
 
157
- add_offense(node.loc.keyword, message: format(MSG, example: example))
175
+ add_offense(node.loc.keyword, message: format(MSG, example: example)) do |corrector|
176
+ next if node.else? && guard.nil?
177
+
178
+ autocorrect(corrector, node, condition, replacement || example, guard)
179
+ end
158
180
  end
159
181
 
160
- def guard_clause_source(guard_clause)
161
- parent = guard_clause.parent
182
+ def autocorrect(corrector, node, condition, replacement, guard)
183
+ corrector.replace(node.loc.keyword.join(condition.loc.expression), replacement)
184
+ corrector.remove(node.loc.end)
185
+ return unless node.else?
186
+
187
+ corrector.remove(node.loc.else)
188
+ corrector.remove(branch_to_remove(node, guard))
189
+ end
190
+
191
+ def branch_to_remove(node, guard)
192
+ case guard
193
+ when :if then node.if_branch
194
+ when :else then node.else_branch
195
+ end
196
+ end
162
197
 
163
- if parent.and_type? || parent.or_type?
198
+ def guard_clause_source(guard_clause)
199
+ if and_or_guard_clause?(guard_clause)
164
200
  guard_clause.parent.source
165
201
  else
166
202
  guard_clause.source
167
203
  end
168
204
  end
169
205
 
206
+ def and_or_guard_clause?(guard_clause)
207
+ parent = guard_clause.parent
208
+ parent.and_type? || parent.or_type?
209
+ end
210
+
170
211
  def too_long_for_single_line?(node, example)
171
212
  max = max_line_length
172
213
  max && node.source_range.column + example.length > max
@@ -5,10 +5,27 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for redundant `if` with boolean literal branches.
7
7
  # It checks only conditions to return boolean value (`true` or `false`) for safe detection.
8
- # The conditions to be checked are comparison methods, predicate methods, and double negative.
8
+ # The conditions to be checked are comparison methods, predicate methods, and
9
+ # double negation (!!).
9
10
  # `nonzero?` method is allowed by default.
10
11
  # These are customizable with `AllowedMethods` option.
11
12
  #
13
+ # This cop targets only `if`s with a single `elsif` or `else` branch. The following
14
+ # code will be allowed, because it has two `elsif` branches:
15
+ #
16
+ # [source,ruby]
17
+ # ----
18
+ # if foo
19
+ # true
20
+ # elsif bar > baz
21
+ # true
22
+ # elsif qux > quux # Single `elsif` is warned, but two or more `elsif`s are not.
23
+ # true
24
+ # else
25
+ # false
26
+ # end
27
+ # ----
28
+ #
12
29
  # @safety
13
30
  # Autocorrection is unsafe because there is no guarantee that all predicate methods
14
31
  # will return a boolean value. Those methods can be allowed with `AllowedMethods` config.
@@ -57,7 +74,7 @@ module RuboCop
57
74
  def_node_matcher :double_negative?, '(send (send _ :!) :!)'
58
75
 
59
76
  def on_if(node)
60
- return unless if_with_boolean_literal_branches?(node)
77
+ return if !if_with_boolean_literal_branches?(node) || multiple_elsif?(node)
61
78
 
62
79
  condition = node.condition
63
80
  range, keyword = offense_range_with_keyword(node, condition)
@@ -76,6 +93,12 @@ module RuboCop
76
93
 
77
94
  private
78
95
 
96
+ def multiple_elsif?(node)
97
+ return false unless (parent = node.parent)
98
+
99
+ parent.if_type? && parent.elsif?
100
+ end
101
+
79
102
  def offense_range_with_keyword(node, condition)
80
103
  if node.ternary?
81
104
  range = condition.source_range.end.join(node.source_range.end)
@@ -3,13 +3,15 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for use of `extend self` or `module_function` in a
7
- # module.
6
+ # Checks for use of `extend self` or `module_function` in a module.
8
7
  #
9
- # Supported styles are: module_function, extend_self, forbidden. `forbidden`
10
- # style prohibits the usage of both styles.
8
+ # Supported styles are: `module_function` (default), `extend_self` and `forbidden`.
11
9
  #
12
- # NOTE: the cop won't be activated when the module contains any private methods.
10
+ # A couple of things to keep in mind:
11
+ #
12
+ # - `forbidden` style prohibits the usage of both styles
13
+ # - in default mode (`module_function`), the cop won't be activated when the module
14
+ # contains any private methods
13
15
  #
14
16
  # @safety
15
17
  # Autocorrection is unsafe (and is disabled by default) because `extend self`
@@ -28,7 +30,6 @@ module RuboCop
28
30
  # # ...
29
31
  # end
30
32
  #
31
- # @example EnforcedStyle: module_function (default)
32
33
  # # good
33
34
  # module Test
34
35
  # extend self
@@ -37,6 +38,13 @@ module RuboCop
37
38
  # # ...
38
39
  # end
39
40
  #
41
+ # # good
42
+ # module Test
43
+ # class << self
44
+ # # ...
45
+ # end
46
+ # end
47
+ #
40
48
  # @example EnforcedStyle: extend_self
41
49
  # # bad
42
50
  # module Test
@@ -50,6 +58,13 @@ module RuboCop
50
58
  # # ...
51
59
  # end
52
60
  #
61
+ # # good
62
+ # module Test
63
+ # class << self
64
+ # # ...
65
+ # end
66
+ # end
67
+ #
53
68
  # @example EnforcedStyle: forbidden
54
69
  # # bad
55
70
  # module Test
@@ -70,6 +85,13 @@ module RuboCop
70
85
  # private
71
86
  # # ...
72
87
  # end
88
+ #
89
+ # # good
90
+ # module Test
91
+ # class << self
92
+ # # ...
93
+ # end
94
+ # end
73
95
  class ModuleFunction < Base
74
96
  include ConfigurableEnforcedStyle
75
97
  extend AutoCorrector
@@ -25,9 +25,10 @@ module RuboCop
25
25
 
26
26
  def on_send(node)
27
27
  return unless (dot = node.loc.dot)
28
+ return if node.receiver.const_type?
28
29
 
29
30
  _lhs, _op, rhs = *node
30
- return if rhs.children.first
31
+ return if rhs.nil? || rhs.children.first
31
32
 
32
33
  add_offense(dot) do |corrector|
33
34
  corrector.replace(dot, ' ')
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for redundant `each`.
7
+ #
8
+ # @safety
9
+ # This cop is unsafe, as it can produce false positives if the receiver
10
+ # is not an `Enumerable`.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # array.each.each { |v| do_something(v) }
16
+ #
17
+ # # good
18
+ # array.each { |v| do_something(v) }
19
+ #
20
+ # # bad
21
+ # array.each.each_with_index { |v, i| do_something(v, i) }
22
+ #
23
+ # # good
24
+ # array.each.with_index { |v, i| do_something(v, i) }
25
+ # array.each_with_index { |v, i| do_something(v, i) }
26
+ #
27
+ # # bad
28
+ # array.each.each_with_object { |v, o| do_something(v, o) }
29
+ #
30
+ # # good
31
+ # array.each.with_object { |v, o| do_something(v, o) }
32
+ # array.each_with_object { |v, o| do_something(v, o) }
33
+ #
34
+ class RedundantEach < Base
35
+ extend AutoCorrector
36
+
37
+ MSG = 'Remove redundant `each`.'
38
+ MSG_WITH_INDEX = 'Use `with_index` to remove redundant `each`.'
39
+ MSG_WITH_OBJECT = 'Use `with_object` to remove redundant `each`.'
40
+
41
+ RESTRICT_ON_SEND = %i[each each_with_index each_with_object].freeze
42
+
43
+ def on_send(node)
44
+ return unless (redundant_node = redundant_each_method(node))
45
+
46
+ range = range(node)
47
+
48
+ add_offense(range, message: message(node)) do |corrector|
49
+ case node.method_name
50
+ when :each
51
+ remove_redundant_each(corrector, range, redundant_node)
52
+ when :each_with_index
53
+ corrector.replace(node.loc.selector, 'with_index')
54
+ when :each_with_object
55
+ corrector.replace(node.loc.selector, 'with_object')
56
+ end
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
63
+ def redundant_each_method(node)
64
+ if node.method?(:each) && !node.parent.block_type?
65
+ ancestor_node = node.each_ancestor(:send).detect do |ancestor|
66
+ RESTRICT_ON_SEND.include?(ancestor.method_name) || ancestor.method?(:reverse_each)
67
+ end
68
+ end
69
+
70
+ ancestor_node || node.each_descendant(:send).detect do |descendant|
71
+ next if descendant.parent.block_type?
72
+
73
+ detected = descendant.method_name.to_s.start_with?('each_') unless node.method?(:each)
74
+
75
+ detected || descendant.method?(:reverse_each)
76
+ end
77
+ end
78
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
79
+
80
+ def range(node)
81
+ if node.method?(:each)
82
+ node.loc.dot.join(node.loc.selector)
83
+ else
84
+ node.loc.selector
85
+ end
86
+ end
87
+
88
+ def message(node)
89
+ case node.method_name
90
+ when :each
91
+ MSG
92
+ when :each_with_index
93
+ MSG_WITH_INDEX
94
+ when :each_with_object
95
+ MSG_WITH_OBJECT
96
+ end
97
+ end
98
+
99
+ def remove_redundant_each(corrector, range, redundant_node)
100
+ corrector.remove(range)
101
+
102
+ if redundant_node.method?(:each_with_index)
103
+ corrector.replace(redundant_node.loc.selector, 'each.with_index')
104
+ elsif redundant_node.method?(:each_with_object)
105
+ corrector.replace(redundant_node.loc.selector, 'each.with_object')
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -42,10 +42,9 @@ module RuboCop
42
42
  MSG = 'Redundant escape of %<char>s inside string literal.'
43
43
 
44
44
  def on_str(node)
45
- return if node.parent&.regexp_type? || node.parent&.xstr_type?
45
+ return if node.parent&.regexp_type? || node.parent&.xstr_type? || node.character_literal?
46
46
 
47
47
  str_contents_range = str_contents_range(node)
48
- return unless str_contents_range.source.include?('\\')
49
48
 
50
49
  each_match_range(str_contents_range, /(\\.)/) do |range|
51
50
  next if allowed_escape?(node, range.resize(3))
@@ -91,9 +90,7 @@ module RuboCop
91
90
 
92
91
  return true if escaped[0] == ' ' && percent_array_literal?(node)
93
92
 
94
- # Allow #{foo}, #$foo, #@foo, and #@@foo for escaping local, global, instance and class
95
- # variable interpolations inside
96
- return true if /\A#[{$@]/.match?(escaped)
93
+ return true if disabling_interpolation?(range)
97
94
  return true if delimiter?(node, escaped[0])
98
95
 
99
96
  false
@@ -167,6 +164,17 @@ module RuboCop
167
164
  def literal_in_interpolated_or_multiline_string?(node)
168
165
  node.str_type? && !begin_loc_present?(node) && node.parent&.dstr_type?
169
166
  end
167
+
168
+ def disabling_interpolation?(range)
169
+ # Allow \#{foo}, \#$foo, \#@foo, and \#@@foo
170
+ # for escaping local, global, instance and class variable interpolations
171
+ return true if range.source.match?(/\A\\#[{$@]/)
172
+
173
+ # Also allow #\{foo}, #\$foo, #\@foo and #\@@foo
174
+ return true if range.adjust(begin_pos: -2).source.match?(/\A[^\\]#\\[{$@]/)
175
+
176
+ false
177
+ end
170
178
  end
171
179
  end
172
180
  end
@@ -40,10 +40,9 @@ module RuboCop
40
40
 
41
41
  # @return [Array<Cop::Cop>]
42
42
  def self.mobilize_cops(cop_classes, config, options = {})
43
- cop_classes = Registry.new(cop_classes.to_a) unless cop_classes.is_a?(Registry)
44
- only = options.fetch(:only, [])
45
- safe = options.fetch(:safe, false)
46
- cop_classes.enabled(config, only, only_safe: safe).map do |cop_class|
43
+ cop_classes = Registry.new(cop_classes.to_a, options) unless cop_classes.is_a?(Registry)
44
+
45
+ cop_classes.enabled(config).map do |cop_class|
47
46
  cop_class.new(config, options)
48
47
  end
49
48
  end
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  def accessible_variables
112
- scope_stack.reverse_each.each_with_object([]) do |scope, variables|
112
+ scope_stack.reverse_each.with_object([]) do |scope, variables|
113
113
  variables.concat(scope.variables.values)
114
114
  break variables unless scope.node.block_type?
115
115
  end
@@ -183,9 +183,11 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
183
183
  # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
184
184
 
185
185
  def to_table(header, content)
186
- table = ['|===', "| #{header.join(' | ')}\n\n"].join("\n")
186
+ # Specify `[separator=¦]` to prevent the regexp `|` is not used as a table separator.
187
+ # See: https://docs.asciidoctor.org/asciidoc/latest/tables/data-format/#escape-the-cell-separator
188
+ table = ['[separator=¦]', '|===', "| #{header.join(' | ')}\n\n"].join("\n")
187
189
  marked_contents = content.map do |plain_content|
188
- plain_content.map { |c| "| #{c}" }.join("\n")
190
+ plain_content.map { |c| "¦ #{c}" }.join("\n")
189
191
  end
190
192
  table << marked_contents.join("\n\n")
191
193
  table << "\n|===\n"
@@ -4,6 +4,8 @@ module RuboCop
4
4
  module Ext
5
5
  # Extensions to AST::ProcessedSource for our cached comment_config
6
6
  module ProcessedSource
7
+ attr_accessor :registry, :config
8
+
7
9
  def comment_config
8
10
  @comment_config ||= CommentConfig.new(self)
9
11
  end
@@ -12,13 +12,14 @@ module RuboCop
12
12
  # 26 LineLength
13
13
  # 3 OneLineConditional
14
14
  # --
15
- # 29 Total
15
+ # 29 Total in 5 files
16
16
  class OffenseCountFormatter < BaseFormatter
17
17
  attr_reader :offense_counts
18
18
 
19
19
  def started(target_files)
20
20
  super
21
21
  @offense_counts = Hash.new(0)
22
+ @offending_files_count = 0
22
23
  @style_guide_links = {}
23
24
 
24
25
  return unless output.tty?
@@ -43,26 +44,28 @@ module RuboCop
43
44
  if options[:display_style_guide]
44
45
  offenses.each { |o| @style_guide_links[o.cop_name] ||= o.message[/ \(http\S+\)\Z/] }
45
46
  end
47
+ @offending_files_count += 1 unless offenses.empty?
46
48
  @progressbar.increment if instance_variable_defined?(:@progressbar)
47
49
  end
48
50
 
49
51
  def finished(_inspected_files)
50
- report_summary(@offense_counts)
52
+ report_summary(@offense_counts, @offending_files_count)
51
53
  end
52
54
 
53
55
  # rubocop:disable Metrics/AbcSize
54
- def report_summary(offense_counts)
56
+ def report_summary(offense_counts, offending_files_count)
55
57
  per_cop_counts = ordered_offense_counts(offense_counts)
56
58
  total_count = total_offense_count(offense_counts)
57
59
 
58
60
  output.puts
59
61
 
62
+ column_width = total_count.to_s.length + 2
60
63
  per_cop_counts.each do |cop_name, count|
61
- output.puts "#{count.to_s.ljust(total_count.to_s.length + 2)}#{cop_name}" \
64
+ output.puts "#{count.to_s.ljust(column_width)}#{cop_name}" \
62
65
  "#{@style_guide_links[cop_name]}\n"
63
66
  end
64
67
  output.puts '--'
65
- output.puts "#{total_count} Total"
68
+ output.puts "#{total_count} Total in #{offending_files_count} files"
66
69
 
67
70
  output.puts
68
71
  end
@@ -12,7 +12,7 @@ module RuboCop
12
12
  # 26 this/file/is/really/bad.rb
13
13
  # 3 just/ok.rb
14
14
  # --
15
- # 29 Total
15
+ # 29 Total in 2 files
16
16
  class WorstOffendersFormatter < BaseFormatter
17
17
  attr_reader :offense_counts
18
18
 
@@ -36,14 +36,17 @@ module RuboCop
36
36
  def report_summary(offense_counts)
37
37
  per_file_counts = ordered_offense_counts(offense_counts)
38
38
  total_count = total_offense_count(offense_counts)
39
+ file_count = per_file_counts.size
39
40
 
40
41
  output.puts
41
42
 
43
+ column_width = total_count.to_s.length + 2
42
44
  per_file_counts.each do |file_name, count|
43
- output.puts "#{count.to_s.ljust(total_count.to_s.length + 2)}#{file_name}\n"
45
+ output.puts "#{count.to_s.ljust(column_width)}#{file_name}\n"
44
46
  end
47
+
45
48
  output.puts '--'
46
- output.puts "#{total_count} Total"
49
+ output.puts "#{total_count} Total in #{file_count} files"
47
50
 
48
51
  output.puts
49
52
  end
@@ -65,7 +65,7 @@ module RuboCop
65
65
  end
66
66
 
67
67
  def add_check_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
68
- section(opts, 'Basic Options') do
68
+ section(opts, 'Basic Options') do # rubocop:disable Metrics/BlockLength
69
69
  option(opts, '-l', '--lint') do
70
70
  @options[:only] ||= []
71
71
  @options[:only] << 'Lint'
@@ -90,6 +90,7 @@ module RuboCop
90
90
  option(opts, '--force-default-config')
91
91
  option(opts, '-s', '--stdin FILE')
92
92
  option(opts, '-P', '--[no-]parallel')
93
+ option(opts, '--raise-cop-error')
93
94
  add_severity_option(opts)
94
95
  end
95
96
  end
@@ -589,7 +590,10 @@ module RuboCop
589
590
  restart_server: 'Restart server process.',
590
591
  start_server: 'Start server process.',
591
592
  stop_server: 'Stop server process.',
592
- server_status: 'Show server status.'
593
+ server_status: 'Show server status.',
594
+ raise_cop_error: ['Raise cop-related errors with cause and location.',
595
+ 'This is used to prevent cops from failing silently.',
596
+ 'Default is false.']
593
597
  }.freeze
594
598
  end
595
599
  end
@@ -28,7 +28,27 @@ module CopHelper
28
28
  file = file.path
29
29
  end
30
30
 
31
- RuboCop::ProcessedSource.new(source, ruby_version, file)
31
+ processed_source = RuboCop::ProcessedSource.new(source, ruby_version, file)
32
+ processed_source.config = configuration
33
+ processed_source.registry = registry
34
+ processed_source
35
+ end
36
+
37
+ def configuration
38
+ @configuration ||= if defined?(config)
39
+ config
40
+ else
41
+ RuboCop::Config.new({}, "#{Dir.pwd}/.rubocop.yml")
42
+ end
43
+ end
44
+
45
+ def registry
46
+ @registry ||= begin
47
+ cops = configuration.keys.map { |cop| RuboCop::Cop::Registry.global.find_by_cop_name(cop) }
48
+ cops << cop_class if defined?(cop_class) && !cops.include?(cop_class)
49
+ cops.compact!
50
+ RuboCop::Cop::Registry.new(cops)
51
+ end
32
52
  end
33
53
 
34
54
  def autocorrect_source_file(source)
@@ -3,14 +3,6 @@
3
3
  require 'tmpdir'
4
4
 
5
5
  RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLength
6
- before do
7
- if RuboCop.const_defined?(:Server)
8
- # Bust server cache to behave as an isolated environment
9
- RuboCop::Server::Cache.cache_root_path = nil
10
- RuboCop::Server::Cache.instance_variable_set(:@project_dir_cache_key, nil)
11
- end
12
- end
13
-
14
6
  around do |example|
15
7
  Dir.mktmpdir do |tmpdir|
16
8
  original_home = Dir.home
@@ -40,14 +32,23 @@ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLe
40
32
  ENV['HOME'] = original_home
41
33
  ENV['XDG_CONFIG_HOME'] = original_xdg_config_home
42
34
 
43
- if RuboCop.const_defined?(:Server)
44
- RuboCop::Server::Cache.cache_root_path = nil
45
- RuboCop::Server::Cache.instance_variable_set(:@project_dir_cache_key, nil)
46
- end
47
35
  RuboCop::FileFinder.root_level = nil
48
36
  end
49
37
  end
50
38
  end
39
+
40
+ if RuboCop.const_defined?(:Server)
41
+ around do |example|
42
+ RuboCop::Server::Cache.cache_root_path = nil
43
+ RuboCop::Server::Cache.instance_variable_set(:@project_dir_cache_key, nil)
44
+ begin
45
+ example.run
46
+ ensure
47
+ RuboCop::Server::Cache.cache_root_path = nil
48
+ RuboCop::Server::Cache.instance_variable_set(:@project_dir_cache_key, nil)
49
+ end
50
+ end
51
+ end
51
52
  end
52
53
 
53
54
  RSpec.shared_context 'maintain registry' do