rubocop 1.22.1 → 1.23.0

Sign up to get free protection for your applications and to get access to all the features.
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'