rubocop 1.22.1 → 1.23.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +43 -7
  4. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  5. data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
  6. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
  7. data/lib/rubocop/cop/gemspec/require_mfa.rb +146 -0
  8. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +30 -23
  9. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
  10. data/lib/rubocop/cop/generator.rb +1 -1
  11. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
  12. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  13. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  14. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  15. data/lib/rubocop/cop/layout/dot_position.rb +9 -7
  16. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  17. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
  18. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  19. data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
  20. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  21. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  22. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  23. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  24. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  25. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  26. data/lib/rubocop/cop/layout/line_length.rb +1 -1
  27. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  28. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -2
  29. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  30. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  31. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  32. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
  33. data/lib/rubocop/cop/layout/space_inside_parens.rb +0 -4
  34. data/lib/rubocop/cop/lint/ambiguous_range.rb +3 -3
  35. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  36. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  37. data/lib/rubocop/cop/lint/number_conversion.rb +5 -2
  38. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
  39. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  40. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  41. data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
  42. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  43. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  44. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  45. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  46. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  47. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  48. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -5
  49. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  50. data/lib/rubocop/cop/naming/file_name.rb +37 -4
  51. data/lib/rubocop/cop/security/json_load.rb +1 -1
  52. data/lib/rubocop/cop/style/commented_keyword.rb +5 -3
  53. data/lib/rubocop/cop/style/documentation.rb +1 -1
  54. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  55. data/lib/rubocop/cop/style/format_string_token.rb +2 -1
  56. data/lib/rubocop/cop/style/line_end_concatenation.rb +1 -1
  57. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  58. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  59. data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
  60. data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
  61. data/lib/rubocop/cop/style/quoted_symbols.rb +11 -1
  62. data/lib/rubocop/cop/style/select_by_regexp.rb +9 -3
  63. data/lib/rubocop/cop/util.rb +11 -1
  64. data/lib/rubocop/formatter/html_formatter.rb +5 -2
  65. data/lib/rubocop/formatter/json_formatter.rb +4 -1
  66. data/lib/rubocop/remote_config.rb +1 -1
  67. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  68. data/lib/rubocop/rspec/support.rb +1 -0
  69. data/lib/rubocop/target_finder.rb +1 -1
  70. data/lib/rubocop/version.rb +1 -1
  71. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  72. data/lib/rubocop.rb +4 -0
  73. metadata +14 -7
@@ -14,6 +14,18 @@ module RuboCop
14
14
  # (i.e. `bundler-console` becomes `Bundler::Console`). As such, the
15
15
  # gemspec is supposed to be named `bundler-console.gemspec`.
16
16
  #
17
+ # When `ExpectMatchingDefinition` (default: `false`) is `true`, the cop requires
18
+ # each file to have a class, module or `Struct` defined in it that matches
19
+ # the filename. This can be further configured using
20
+ # `CheckDefinitionPathHierarchy` (default: `true`) to determine whether the
21
+ # path should match the namespace of the above definition.
22
+ #
23
+ # When `IgnoreExecutableScripts` (default: `true`) is `true`, files that start
24
+ # with a shebang line are not considered by the cop.
25
+ #
26
+ # When `Regex` is set, the cop will flag any filename that does not match
27
+ # the regular expression.
28
+ #
17
29
  # @example
18
30
  # # bad
19
31
  # lib/layoutManager.rb
@@ -28,11 +40,19 @@ module RuboCop
28
40
  include RangeHelp
29
41
 
30
42
  MSG_SNAKE_CASE = 'The name of this source file (`%<basename>s`) should use snake_case.'
31
- MSG_NO_DEFINITION = '%<basename>s should define a class or module called `%<namespace>s`.'
43
+ MSG_NO_DEFINITION = '`%<basename>s` should define a class or module called `%<namespace>s`.'
32
44
  MSG_REGEX = '`%<basename>s` should match `%<regex>s`.'
33
45
 
34
46
  SNAKE_CASE = /^[\d[[:lower:]]_.?!]+$/.freeze
35
47
 
48
+ # @!method struct_definition(node)
49
+ def_node_matcher :struct_definition, <<~PATTERN
50
+ {
51
+ (casgn $_ $_ (send (const {nil? cbase} :Struct) :new ...))
52
+ (casgn $_ $_ (block (send (const {nil? cbase} :Struct) :new ...) ...))
53
+ }
54
+ PATTERN
55
+
36
56
  def on_new_investigation
37
57
  file_path = processed_source.file_path
38
58
  return if config.file_to_exclude?(file_path) || config.allowed_camel_case_file?(file_path)
@@ -103,6 +123,10 @@ module RuboCop
103
123
  cop_config['CheckDefinitionPathHierarchy']
104
124
  end
105
125
 
126
+ def definition_path_hierarchy_roots
127
+ cop_config['CheckDefinitionPathHierarchyRoots'] || []
128
+ end
129
+
106
130
  def regex
107
131
  cop_config['Regex']
108
132
  end
@@ -126,7 +150,7 @@ module RuboCop
126
150
  name = namespace.pop
127
151
 
128
152
  on_node(%i[class module casgn], node) do |child|
129
- next unless (const = child.defined_module)
153
+ next unless (const = find_definition(child))
130
154
 
131
155
  const_namespace, const_name = *const
132
156
  next if name != const_name && !match_acronym?(name, const_name)
@@ -138,6 +162,15 @@ module RuboCop
138
162
  nil
139
163
  end
140
164
 
165
+ def find_definition(node)
166
+ node.defined_module || defined_struct(node)
167
+ end
168
+
169
+ def defined_struct(node)
170
+ namespace, name = *struct_definition(node)
171
+ s(:const, namespace, name) if name
172
+ end
173
+
141
174
  def match_namespace(node, namespace, expected)
142
175
  match_partial = partial_matcher!(expected)
143
176
 
@@ -177,13 +210,13 @@ module RuboCop
177
210
  allowed_acronyms.any? { |acronym| expected.gsub(acronym.capitalize, acronym) == name }
178
211
  end
179
212
 
180
- def to_namespace(path)
213
+ def to_namespace(path) # rubocop:disable Metrics/AbcSize
181
214
  components = Pathname(path).each_filename.to_a
182
215
  # To convert a pathname to a Ruby namespace, we need a starting point
183
216
  # But RC can be run from any working directory, and can check any path
184
217
  # We can't assume that the working directory, or any other, is the
185
218
  # "starting point" to build a namespace.
186
- start = %w[lib spec test src]
219
+ start = definition_path_hierarchy_roots
187
220
  start_index = nil
188
221
 
189
222
  # To find the closest namespace root take the path components, and
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # security issues.
8
8
  #
9
9
  # @safety
10
- # Autocorrect is disabled by default because it's potentially dangerous.
10
+ # This cop's autocorrection is unsafe because it's potentially dangerous.
11
11
  # If using a stream, like `JSON.load(open('file'))`, it will need to call
12
12
  # `#read` manually, like `JSON.parse(open('file').read)`.
13
13
  # If reading single values (rather than proper JSON objects), like
@@ -52,9 +52,11 @@ module RuboCop
52
52
  ALLOWED_COMMENTS = %w[:nodoc: :yields: rubocop:disable rubocop:todo].freeze
53
53
  ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }.freeze
54
54
 
55
+ REGEXP = /(?<keyword>\S+).*#/.freeze
56
+
55
57
  def on_new_investigation
56
58
  processed_source.comments.each do |comment|
57
- next unless offensive?(comment) && (match = line(comment).match(/(?<keyword>\S+).*#/))
59
+ next unless offensive?(comment) && (match = source_line(comment).match(REGEXP))
58
60
 
59
61
  register_offense(comment, match[:keyword])
60
62
  end
@@ -76,12 +78,12 @@ module RuboCop
76
78
  end
77
79
 
78
80
  def offensive?(comment)
79
- line = line(comment)
81
+ line = source_line(comment)
80
82
  KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
81
83
  ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
82
84
  end
83
85
 
84
- def line(comment)
86
+ def source_line(comment)
85
87
  comment.location.expression.source_line
86
88
  end
87
89
  end
@@ -176,7 +176,7 @@ module RuboCop
176
176
  end
177
177
 
178
178
  def qualify_const(node)
179
- return if node.nil?
179
+ return if node.nil? || node.cbase_type?
180
180
 
181
181
  [qualify_const(node.namespace), node.short_name].compact
182
182
  end
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # to go on its own line (expanded style).
10
10
  #
11
11
  # NOTE: A method definition is not considered empty if it contains
12
- # comments.
12
+ # comments.
13
13
  #
14
14
  # @example EnforcedStyle: compact (default)
15
15
  # # bad
@@ -102,7 +102,8 @@ module RuboCop
102
102
  end
103
103
 
104
104
  def use_ignored_method?(node)
105
- (parent = node.parent) && parent.send_type? && ignored_method?(parent.method_name)
105
+ send_parent = node.each_ancestor(:send).first
106
+ send_parent && ignored_method?(send_parent.method_name)
106
107
  end
107
108
 
108
109
  def unannotated_format?(node, detected_style)
@@ -59,7 +59,7 @@ module RuboCop
59
59
 
60
60
  return unless eligible_token_set?(predecessor, operator, successor)
61
61
 
62
- return if operator.line == successor.line
62
+ return if same_line?(operator, successor)
63
63
 
64
64
  next_successor = token_after_last_string(successor, index)
65
65
 
@@ -54,7 +54,7 @@ module RuboCop
54
54
  return true if in_pattern_node.pattern.first_line != in_pattern_node.pattern.last_line
55
55
  return false unless in_pattern_node.body
56
56
 
57
- in_pattern_node.loc.line == in_pattern_node.body.loc.line
57
+ same_line?(in_pattern_node, in_pattern_node.body)
58
58
  end
59
59
  end
60
60
  end
@@ -54,7 +54,7 @@ module RuboCop
54
54
  end
55
55
  return false unless when_node.body
56
56
 
57
- when_node.loc.line == when_node.body.loc.line
57
+ same_line?(when_node, when_node.body)
58
58
  end
59
59
 
60
60
  def accept_node_type?(node)
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop flags uses of OpenStruct, as it is now officially discouraged
7
+ # to be used for performance, version compatibility, and potential security issues.
8
+ #
9
+ # @safety
10
+ #
11
+ # Note that this cop may flag false positives; for instance, the following legal
12
+ # use of a hand-rolled `OpenStruct` type would be considered an offense:
13
+ #
14
+ # ```
15
+ # module MyNamespace
16
+ # class OpenStruct # not the OpenStruct we're looking for
17
+ # end
18
+ #
19
+ # def new_struct
20
+ # OpenStruct.new # resolves to MyNamespace::OpenStruct
21
+ # end
22
+ # end
23
+ # ```
24
+ #
25
+ # @example
26
+ #
27
+ # # bad
28
+ # point = OpenStruct.new(x: 0, y: 1)
29
+ #
30
+ # # good
31
+ # Point = Struct.new(:x, :y)
32
+ # point = Point.new(0, 1)
33
+ #
34
+ # # also good
35
+ # point = { x: 0, y: 1 }
36
+ #
37
+ # # bad
38
+ # test_double = OpenStruct.new(a: 'b')
39
+ #
40
+ # # good (assumes test using rspec-mocks)
41
+ # test_double = double
42
+ # allow(test_double).to receive(:a).and_return('b')
43
+ #
44
+ class OpenStructUse < Base
45
+ MSG = 'Avoid using `OpenStruct`; use `Struct`, `Hash`, a class or test doubles instead.'
46
+
47
+ # @!method uses_open_struct?(node)
48
+ def_node_matcher :uses_open_struct?, <<-PATTERN
49
+ (const {nil? (cbase)} :OpenStruct)
50
+ PATTERN
51
+
52
+ def on_const(node)
53
+ return unless uses_open_struct?(node)
54
+ return if custom_class_or_module_definition?(node)
55
+
56
+ add_offense(node)
57
+ end
58
+
59
+ private
60
+
61
+ def custom_class_or_module_definition?(node)
62
+ parent = node.parent
63
+
64
+ (parent.class_type? || parent.module_type?) && node.left_siblings.empty?
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -56,6 +56,7 @@ module RuboCop
56
56
  class ParenthesesAroundCondition < Base
57
57
  include SafeAssignment
58
58
  include Parentheses
59
+ include RangeHelp
59
60
  extend AutoCorrector
60
61
 
61
62
  def on_if(node)
@@ -73,13 +74,14 @@ module RuboCop
73
74
 
74
75
  # @!method control_op_condition(node)
75
76
  def_node_matcher :control_op_condition, <<~PATTERN
76
- (begin $_ ...)
77
+ (begin $_ $...)
77
78
  PATTERN
78
79
 
79
80
  def process_control_op(node)
80
81
  cond = node.condition
81
82
 
82
- control_op_condition(cond) do |first_child|
83
+ control_op_condition(cond) do |first_child, rest_children|
84
+ return if semicolon_separated_expressions?(first_child, rest_children)
83
85
  return if modifier_op?(first_child)
84
86
  return if parens_allowed?(cond)
85
87
 
@@ -90,6 +92,14 @@ module RuboCop
90
92
  end
91
93
  end
92
94
 
95
+ def semicolon_separated_expressions?(first_exp, rest_exps)
96
+ return false unless (second_exp = rest_exps.first)
97
+
98
+ range = range_between(first_exp.source_range.end_pos, second_exp.source_range.begin_pos)
99
+
100
+ range.source.include?(';')
101
+ end
102
+
93
103
  def modifier_op?(node)
94
104
  return false if node.if_type? && node.ternary?
95
105
  return true if node.rescue_type?
@@ -46,7 +46,7 @@ module RuboCop
46
46
 
47
47
  message = style == :single_quotes ? MSG_SINGLE : MSG_DOUBLE
48
48
 
49
- if wrong_quotes?(node)
49
+ if wrong_quotes?(node) || invalid_double_quotes?(node.source)
50
50
  add_offense(node, message: message) do |corrector|
51
51
  opposite_style_detected
52
52
  autocorrect(corrector, node)
@@ -58,6 +58,16 @@ module RuboCop
58
58
 
59
59
  private
60
60
 
61
+ def invalid_double_quotes?(source)
62
+ return false unless style == :double_quotes
63
+
64
+ # The string needs single quotes if:
65
+ # 1. It contains a double quote
66
+ # 2. It contains text that would become an escape sequence with double quotes
67
+ # 3. It contains text that would become an interpolation with double quotes
68
+ !/" | (?<!\\)\\[aAbcdefkMnprsStuUxzZ0-7] | \#[@{$]/x.match?(source)
69
+ end
70
+
61
71
  def autocorrect(corrector, node)
62
72
  str = if hash_colon_key?(node)
63
73
  # strip quotes
@@ -83,8 +83,9 @@ module RuboCop
83
83
  return if block_node.body.begin_type?
84
84
  return if receiver_allowed?(block_node.receiver)
85
85
  return unless (regexp_method_send_node = extract_send_node(block_node))
86
+ return if match_predicate_without_receiver?(regexp_method_send_node)
86
87
 
87
- regexp = find_regexp(regexp_method_send_node)
88
+ regexp = find_regexp(regexp_method_send_node, block_node)
88
89
  register_offense(node, block_node, regexp)
89
90
  end
90
91
 
@@ -118,15 +119,20 @@ module RuboCop
118
119
  regexp_method_send_node
119
120
  end
120
121
 
121
- def find_regexp(node)
122
+ def find_regexp(node, block)
122
123
  return node.child_nodes.first if node.match_with_lvasgn_type?
123
124
 
124
- if node.receiver.lvar_type?
125
+ if node.receiver.lvar_type? &&
126
+ (block.numblock_type? || node.receiver.source == block.arguments.first.source)
125
127
  node.first_argument
126
128
  elsif node.first_argument.lvar_type?
127
129
  node.receiver
128
130
  end
129
131
  end
132
+
133
+ def match_predicate_without_receiver?(node)
134
+ node.send_type? && node.method?(:match?) && node.receiver.nil?
135
+ end
130
136
  end
131
137
  end
132
138
  end
@@ -126,8 +126,18 @@ module RuboCop
126
126
  StringInterpreter.interpret(string)
127
127
  end
128
128
 
129
+ def line(node_or_range)
130
+ if node_or_range.respond_to?(:line)
131
+ node_or_range.line
132
+ elsif node_or_range.respond_to?(:loc)
133
+ node_or_range.loc.line
134
+ end
135
+ end
136
+
129
137
  def same_line?(node1, node2)
130
- node1.respond_to?(:loc) && node2.respond_to?(:loc) && node1.loc.line == node2.loc.line
138
+ line1 = line(node1)
139
+ line2 = line(node2)
140
+ line1 && line2 && line1 == line2
131
141
  end
132
142
 
133
143
  def indent(node, offset: 0)
@@ -23,12 +23,15 @@ module RuboCop
23
23
  end
24
24
  end
25
25
 
26
+ Summary = Struct.new(:offense_count, :inspected_files, :target_files, keyword_init: true)
27
+ FileOffenses = Struct.new(:path, :offenses, keyword_init: true)
28
+
26
29
  attr_reader :files, :summary
27
30
 
28
31
  def initialize(output, options = {})
29
32
  super
30
33
  @files = []
31
- @summary = OpenStruct.new(offense_count: 0)
34
+ @summary = Summary.new(offense_count: 0)
32
35
  end
33
36
 
34
37
  def started(target_files)
@@ -36,7 +39,7 @@ module RuboCop
36
39
  end
37
40
 
38
41
  def file_finished(file, offenses)
39
- files << OpenStruct.new(path: file, offenses: offenses)
42
+ files << FileOffenses.new(path: file, offenses: offenses)
40
43
  summary.offense_count += offenses.count
41
44
  end
42
45
 
@@ -59,12 +59,15 @@ module RuboCop
59
59
  end
60
60
 
61
61
  # TODO: Consider better solution for Offense#real_column.
62
+ # The minimum value of `start_column: real_column` is 1.
63
+ # So, the minimum value of `last_column` should be 1.
64
+ # And non-zero value of `last_column` should be used as is.
62
65
  def hash_for_location(offense)
63
66
  {
64
67
  start_line: offense.line,
65
68
  start_column: offense.real_column,
66
69
  last_line: offense.last_line,
67
- last_column: offense.last_column,
70
+ last_column: offense.last_column.zero? ? 1 : offense.last_column,
68
71
  length: offense.location.length,
69
72
  # `line` and `column` exist for compatibility.
70
73
  # Use `start_line` and `start_column` instead.
@@ -33,7 +33,7 @@ module RuboCop
33
33
 
34
34
  def inherit_from_remote(file, path)
35
35
  new_uri = @uri.dup
36
- new_uri.path.gsub!(%r{/[^/]*$}, "/#{file}")
36
+ new_uri.path.gsub!(%r{/[^/]*$}, "/#{file.delete_prefix('./')}")
37
37
  RemoteConfig.new(new_uri.to_s, File.dirname(path))
38
38
  end
39
39
 
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec::Support.require_rspec_core 'formatters/base_text_formatter'
4
+ RSpec::Support.require_rspec_core 'formatters/console_codes'
5
+
6
+ module RuboCop
7
+ module RSpec
8
+ # RSpec formatter for use with running `rake spec` in parallel. This formatter
9
+ # removes much of the noise from RSpec so that only the important information
10
+ # will be surfaced by test-queue.
11
+ # It also adds metadata to the output in order to more easily find the text
12
+ # needed for outputting after the parallel run completes.
13
+ class ParallelFormatter < ::RSpec::Core::Formatters::BaseTextFormatter
14
+ ::RSpec::Core::Formatters.register self, :dump_pending, :dump_failures, :dump_summary
15
+
16
+ # Don't show pending tests
17
+ def dump_pending(*); end
18
+
19
+ # The BEGIN/END comments are used by `spec_runner.rake` to determine what
20
+ # output goes where in the final parallelized output, and should not be
21
+ # removed!
22
+ def dump_failures(notification)
23
+ return if notification.failure_notifications.empty?
24
+
25
+ output.puts '# FAILURES BEGIN'
26
+ notification.failure_notifications.each do |failure|
27
+ output.puts failure.fully_formatted('*', colorizer)
28
+ end
29
+ output.puts
30
+ output.puts '# FAILURES END'
31
+ end
32
+
33
+ def dump_summary(summary)
34
+ output_summary(summary)
35
+ output_rerun_commands(summary)
36
+ end
37
+
38
+ private
39
+
40
+ def colorizer
41
+ @colorizer ||= ::RSpec::Core::Formatters::ConsoleCodes
42
+ end
43
+
44
+ # The BEGIN/END comments are used by `spec_runner.rake` to determine what
45
+ # output goes where in the final parallelized output, and should not be
46
+ # removed!
47
+ def output_summary(summary)
48
+ output.puts '# SUMMARY BEGIN'
49
+ output.puts colorize_summary(summary)
50
+ output.puts '# SUMMARY END'
51
+ end
52
+
53
+ def colorize_summary(summary)
54
+ totals = totals(summary)
55
+
56
+ if summary.failure_count.positive? || summary.errors_outside_of_examples_count.positive?
57
+ colorizer.wrap(totals, ::RSpec.configuration.failure_color)
58
+ else
59
+ colorizer.wrap(totals, ::RSpec.configuration.success_color)
60
+ end
61
+ end
62
+
63
+ # The BEGIN/END comments are used by `spec_runner.rake` to determine what
64
+ # output goes where in the final parallelized output, and should not be
65
+ # removed!
66
+ def output_rerun_commands(summary)
67
+ output.puts '# RERUN BEGIN'
68
+ output.puts summary.colorized_rerun_commands.lines[3..-1].join
69
+ output.puts '# RERUN END'
70
+ end
71
+
72
+ def totals(summary)
73
+ output = pluralize(summary.example_count, 'example')
74
+ output += ", #{summary.pending_count} pending" if summary.pending_count.positive?
75
+ output += ", #{pluralize(summary.failure_count, 'failure')}"
76
+
77
+ if summary.errors_outside_of_examples_count.positive?
78
+ error_count = pluralize(summary.errors_outside_of_examples_count, 'error')
79
+ output += ", #{error_count} occurred outside of examples"
80
+ end
81
+
82
+ output
83
+ end
84
+
85
+ def pluralize(*args)
86
+ ::RSpec::Core::Formatters::Helpers.pluralize(*args)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -6,6 +6,7 @@ require_relative 'cop_helper'
6
6
  require_relative 'host_environment_simulation_helper'
7
7
  require_relative 'shared_contexts'
8
8
  require_relative 'expect_offense'
9
+ require_relative 'parallel_formatter'
9
10
 
10
11
  RSpec.configure do |config|
11
12
  config.include CopHelper
@@ -95,7 +95,7 @@ module RuboCop
95
95
 
96
96
  def wanted_dir_patterns(base_dir, exclude_pattern, flags)
97
97
  base_dir = base_dir.gsub('/{}/', '/\{}/')
98
- dirs = Dir.glob(File.join(base_dir.gsub('/**/', '/\**/'), '*/'), flags)
98
+ dirs = Dir.glob(File.join(base_dir.gsub('/*/', '/\*/').gsub('/**/', '/\**/'), '*/'), flags)
99
99
  .reject do |dir|
100
100
  next true if dir.end_with?('/./', '/../')
101
101
  next true if File.fnmatch?(exclude_pattern, dir, flags)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.22.1'
6
+ STRING = '1.23.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
@@ -23,7 +23,7 @@ module RuboCop
23
23
  when Psych::Nodes::Mapping
24
24
  tree.children.each_slice(2).with_object([]) do |(key, value), keys|
25
25
  exist = keys.find { |key2| key2.value == key.value }
26
- on_duplicated.call(exist, key) if exist
26
+ yield(exist, key) if exist
27
27
  keys << key
28
28
  traverse(value, &on_duplicated)
29
29
  end
data/lib/rubocop.rb CHANGED
@@ -83,6 +83,7 @@ require_relative 'rubocop/cop/mixin/enforce_superclass'
83
83
  require_relative 'rubocop/cop/mixin/first_element_line_break'
84
84
  require_relative 'rubocop/cop/mixin/frozen_string_literal'
85
85
  require_relative 'rubocop/cop/mixin/gem_declaration'
86
+ require_relative 'rubocop/cop/mixin/gemspec_help'
86
87
  require_relative 'rubocop/cop/mixin/hash_alignment_styles'
87
88
  require_relative 'rubocop/cop/mixin/hash_transform_method'
88
89
  require_relative 'rubocop/cop/mixin/ignored_pattern'
@@ -160,6 +161,7 @@ require_relative 'rubocop/cop/bundler/ordered_gems'
160
161
  require_relative 'rubocop/cop/gemspec/date_assignment'
161
162
  require_relative 'rubocop/cop/gemspec/duplicated_assignment'
162
163
  require_relative 'rubocop/cop/gemspec/ordered_dependencies'
164
+ require_relative 'rubocop/cop/gemspec/require_mfa'
163
165
  require_relative 'rubocop/cop/gemspec/required_ruby_version'
164
166
  require_relative 'rubocop/cop/gemspec/ruby_version_globals_usage'
165
167
 
@@ -382,6 +384,7 @@ require_relative 'rubocop/cop/lint/useless_access_modifier'
382
384
  require_relative 'rubocop/cop/lint/useless_assignment'
383
385
  require_relative 'rubocop/cop/lint/useless_else_without_rescue'
384
386
  require_relative 'rubocop/cop/lint/useless_method_definition'
387
+ require_relative 'rubocop/cop/lint/useless_ruby2_keywords'
385
388
  require_relative 'rubocop/cop/lint/useless_setter_call'
386
389
  require_relative 'rubocop/cop/lint/useless_times'
387
390
  require_relative 'rubocop/cop/lint/void'
@@ -514,6 +517,7 @@ require_relative 'rubocop/cop/style/method_call_without_args_parentheses'
514
517
  require_relative 'rubocop/cop/style/method_call_with_args_parentheses'
515
518
  require_relative 'rubocop/cop/style/multiline_in_pattern_then'
516
519
  require_relative 'rubocop/cop/style/numbered_parameters'
520
+ require_relative 'rubocop/cop/style/open_struct_use'
517
521
  require_relative 'rubocop/cop/style/redundant_assignment'
518
522
  require_relative 'rubocop/cop/style/redundant_fetch_block'
519
523
  require_relative 'rubocop/cop/style/redundant_file_extension_in_require'