rubocop 1.38.0 → 1.40.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +51 -11
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/comment_config.rb +5 -0
  6. data/lib/rubocop/config.rb +5 -4
  7. data/lib/rubocop/config_loader.rb +5 -5
  8. data/lib/rubocop/config_loader_resolver.rb +1 -1
  9. data/lib/rubocop/cop/base.rb +2 -9
  10. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  11. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  12. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  13. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
  14. data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
  15. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
  16. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  17. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  18. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  19. data/lib/rubocop/cop/lint/duplicate_methods.rb +17 -8
  20. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  21. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  22. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  23. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  24. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +13 -3
  25. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +15 -6
  26. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  27. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  28. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  29. data/lib/rubocop/cop/lint/void.rb +6 -6
  30. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  31. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  32. data/lib/rubocop/cop/metrics/class_length.rb +9 -4
  33. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  34. data/lib/rubocop/cop/metrics/module_length.rb +9 -4
  35. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -2
  36. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +24 -5
  37. data/lib/rubocop/cop/mixin/range_help.rb +23 -0
  38. data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
  39. data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
  40. data/lib/rubocop/cop/registry.rb +23 -11
  41. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -25
  42. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  43. data/lib/rubocop/cop/style/class_equality_comparison.rb +7 -5
  44. data/lib/rubocop/cop/style/collection_compact.rb +1 -1
  45. data/lib/rubocop/cop/style/guard_clause.rb +32 -5
  46. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
  47. data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
  48. data/lib/rubocop/cop/style/hash_except.rb +4 -0
  49. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -1
  50. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  51. data/lib/rubocop/cop/style/object_then.rb +3 -0
  52. data/lib/rubocop/cop/style/operator_method_call.rb +13 -0
  53. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  54. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  55. data/lib/rubocop/cop/style/redundant_constant_base.rb +72 -0
  56. data/lib/rubocop/cop/style/redundant_each.rb +13 -8
  57. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
  58. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  59. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  60. data/lib/rubocop/cop/style/require_order.rb +88 -0
  61. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  62. data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
  63. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  64. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  65. data/lib/rubocop/cop/team.rb +1 -1
  66. data/lib/rubocop/cop/util.rb +2 -2
  67. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  68. data/lib/rubocop/cop/variable_force.rb +20 -29
  69. data/lib/rubocop/cops_documentation_generator.rb +3 -4
  70. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  71. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  72. data/lib/rubocop/formatter.rb +3 -1
  73. data/lib/rubocop/optimized_patterns.rb +38 -0
  74. data/lib/rubocop/options.rb +9 -1
  75. data/lib/rubocop/path_util.rb +14 -2
  76. data/lib/rubocop/result_cache.rb +1 -1
  77. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  78. data/lib/rubocop/rspec/support.rb +2 -2
  79. data/lib/rubocop/server/core.rb +16 -1
  80. data/lib/rubocop/target_ruby.rb +1 -1
  81. data/lib/rubocop/version.rb +1 -1
  82. data/lib/rubocop.rb +14 -6
  83. metadata +8 -3
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Sort `require` and `require_relative` in alphabetical order.
7
+ #
8
+ # @safety
9
+ # This cop's autocorrection is unsafe because it will obviously change the execution order.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # require 'b'
14
+ # require 'a'
15
+ #
16
+ # # good
17
+ # require 'a'
18
+ # require 'b'
19
+ #
20
+ # # bad
21
+ # require_relative 'b'
22
+ # require_relative 'a'
23
+ #
24
+ # # good
25
+ # require_relative 'a'
26
+ # require_relative 'b'
27
+ #
28
+ # # good (sorted within each section separated by a blank line)
29
+ # require 'a'
30
+ # require 'd'
31
+ #
32
+ # require 'b'
33
+ # require 'c'
34
+ #
35
+ # # good
36
+ # require 'b'
37
+ # require_relative 'c'
38
+ # require 'a'
39
+ class RequireOrder < Base
40
+ extend AutoCorrector
41
+
42
+ include RangeHelp
43
+
44
+ RESTRICT_ON_SEND = %i[require require_relative].freeze
45
+
46
+ def on_send(node)
47
+ previous_older_sibling = find_previous_older_sibling(node)
48
+ return unless previous_older_sibling
49
+
50
+ add_offense(
51
+ node,
52
+ message: "Sort `#{node.method_name}` in alphabetical order."
53
+ ) do |corrector|
54
+ swap(
55
+ range_with_comments_and_lines(previous_older_sibling),
56
+ range_with_comments_and_lines(node),
57
+ corrector: corrector
58
+ )
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def find_previous_older_sibling(node)
65
+ node.left_siblings.reverse.find do |sibling|
66
+ break unless sibling.send_type?
67
+ break unless sibling.method?(node.method_name)
68
+ break unless in_same_section?(sibling, node)
69
+
70
+ node.first_argument.source < sibling.first_argument.source
71
+ end
72
+ end
73
+
74
+ def in_same_section?(node1, node2)
75
+ !node1.location.expression.with(
76
+ end_pos: node2.location.expression.end_pos
77
+ ).source.include?("\n\n")
78
+ end
79
+
80
+ def swap(range1, range2, corrector:)
81
+ inserted = range2.source
82
+ corrector.insert_before(range1, inserted)
83
+ corrector.remove(range2)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -50,6 +50,11 @@ module RuboCop
50
50
  # foo && foo.bar { |e| e.something }
51
51
  # foo && foo.bar(param) { |e| e.something }
52
52
  #
53
+ # foo ? foo.bar : nil
54
+ # foo.nil? ? nil : foo.bar
55
+ # !foo.nil? ? foo.bar : nil
56
+ # !foo ? nil : foo.bar
57
+ #
53
58
  # # good
54
59
  # foo&.bar
55
60
  # foo&.bar&.baz
@@ -105,6 +110,17 @@ module RuboCop
105
110
  }
106
111
  PATTERN
107
112
 
113
+ # @!method ternary_safe_navigation_candidate(node)
114
+ def_node_matcher :ternary_safe_navigation_candidate, <<~PATTERN
115
+ {
116
+ (if (send $_ {:nil? :!}) nil $_)
117
+
118
+ (if (send (send $_ :nil?) :!) $_ nil)
119
+
120
+ (if $_ $_ nil)
121
+ }
122
+ PATTERN
123
+
108
124
  # @!method not_nil_check?(node)
109
125
  def_node_matcher :not_nil_check?, '(send (send $_ :nil?) :!)'
110
126
 
@@ -118,9 +134,11 @@ module RuboCop
118
134
  check_node(node)
119
135
  end
120
136
 
137
+ private
138
+
121
139
  def check_node(node)
122
140
  checked_variable, receiver, method_chain, method = extract_parts(node)
123
- return unless receiver == checked_variable
141
+ return if receiver != checked_variable || receiver.nil?
124
142
  return if use_var_only_in_unless_modifier?(node, checked_variable)
125
143
  return if chain_length(method_chain, method) > max_chain_length
126
144
  return if unsafe_method_used?(method_chain, method)
@@ -133,10 +151,8 @@ module RuboCop
133
151
  node.if_type? && node.unless? && !method_called?(variable)
134
152
  end
135
153
 
136
- private
137
-
138
154
  def autocorrect(corrector, node)
139
- body = node.node_parts[1]
155
+ body = extract_body(node)
140
156
  method_call = method_call(node)
141
157
 
142
158
  corrector.remove(begin_range(node, body))
@@ -147,6 +163,14 @@ module RuboCop
147
163
  add_safe_nav_to_all_methods_in_chain(corrector, method_call, body)
148
164
  end
149
165
 
166
+ def extract_body(node)
167
+ if node.if_type? && node.ternary?
168
+ node.branches.find { |branch| !branch.nil_type? }
169
+ else
170
+ node.node_parts[1]
171
+ end
172
+ end
173
+
150
174
  def handle_comments(corrector, node, method_call)
151
175
  comments = comments(node)
152
176
  return if comments.empty?
@@ -174,7 +198,7 @@ module RuboCop
174
198
  end
175
199
 
176
200
  def allowed_if_condition?(node)
177
- node.else? || node.elsif? || node.ternary?
201
+ node.else? || node.elsif?
178
202
  end
179
203
 
180
204
  def method_call(node)
@@ -192,7 +216,12 @@ module RuboCop
192
216
  end
193
217
 
194
218
  def extract_parts_from_if(node)
195
- variable, receiver = modifier_if_safe_navigation_candidate(node)
219
+ variable, receiver =
220
+ if node.ternary?
221
+ ternary_safe_navigation_candidate(node)
222
+ else
223
+ modifier_if_safe_navigation_candidate(node)
224
+ end
196
225
 
197
226
  checked_variable, matching_receiver, method = extract_common_parts(receiver, variable)
198
227
 
@@ -49,7 +49,8 @@ module RuboCop
49
49
  MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
50
50
  RESTRICT_ON_SEND = %i[select find_all reject].freeze
51
51
  REPLACEMENTS = { select: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
52
- REGEXP_METHODS = %i[match? =~].to_set.freeze
52
+ OPPOSITE_REPLACEMENTS = { select: 'grep_v', find_all: 'grep_v', reject: 'grep' }.freeze
53
+ REGEXP_METHODS = %i[match? =~ !~].to_set.freeze
53
54
 
54
55
  # @!method regexp_match?(node)
55
56
  def_node_matcher :regexp_match?, <<~PATTERN
@@ -90,8 +91,10 @@ module RuboCop
90
91
  return unless (regexp_method_send_node = extract_send_node(block_node))
91
92
  return if match_predicate_without_receiver?(regexp_method_send_node)
92
93
 
94
+ opposite = regexp_method_send_node.send_type? && regexp_method_send_node.method?(:!~)
93
95
  regexp = find_regexp(regexp_method_send_node, block_node)
94
- register_offense(node, block_node, regexp)
96
+
97
+ register_offense(node, block_node, regexp, opposite)
95
98
  end
96
99
 
97
100
  private
@@ -102,8 +105,9 @@ module RuboCop
102
105
  node.hash_type? || creates_hash?(node) || env_const?(node)
103
106
  end
104
107
 
105
- def register_offense(node, block_node, regexp)
106
- replacement = REPLACEMENTS[node.method_name.to_sym]
108
+ def register_offense(node, block_node, regexp, opposite)
109
+ method_name = node.method_name.to_sym
110
+ replacement = opposite ? OPPOSITE_REPLACEMENTS[method_name] : REPLACEMENTS[method_name]
107
111
  message = format(MSG, replacement: replacement, original_method: node.method_name)
108
112
 
109
113
  add_offense(block_node, message: message) do |corrector|
@@ -95,11 +95,7 @@ module RuboCop
95
95
  end
96
96
 
97
97
  def offense?(node)
98
- # If it's a string within an interpolation, then it's not an offense
99
- # for this cop.
100
- return false if inside_interpolation?(node)
101
-
102
- wrong_quotes?(node)
98
+ wrong_quotes?(node) && !inside_interpolation?(node)
103
99
  end
104
100
 
105
101
  def consistent_multiline?
@@ -7,7 +7,7 @@ module RuboCop
7
7
  #
8
8
  # If you prefer a style that allows block for method with arguments,
9
9
  # please set `true` to `AllowMethodsWithArguments`.
10
- # respond_to , and `define_method?` methods are allowed by default.
10
+ # `define_method?` methods are allowed by default.
11
11
  # These are customizable with `AllowedMethods` option.
12
12
  #
13
13
  # @safety
@@ -72,12 +72,10 @@ module RuboCop
72
72
  # # some comment
73
73
  # end
74
74
  #
75
- # @example AllowedMethods: [respond_to, define_method] (default)
75
+ # @example AllowedMethods: [define_method] (default)
76
76
  # # good
77
- # respond_to { |foo| foo.bar }
78
77
  # define_method(:foo) { |foo| foo.bar }
79
78
  #
80
- #
81
79
  # @example AllowedPatterns: [] (default)
82
80
  # # bad
83
81
  # something.map { |s| s.upcase }
@@ -38,7 +38,7 @@ module RuboCop
38
38
  new(cops, config, options)
39
39
  end
40
40
 
41
- # @return [Array<Cop::Cop>]
41
+ # @return [Array<Cop::Base>]
42
42
  def self.mobilize_cops(cop_classes, config, options = {})
43
43
  cop_classes = Registry.new(cop_classes.to_a, options) unless cop_classes.is_a?(Registry)
44
44
 
@@ -122,7 +122,7 @@ module RuboCop
122
122
  string.inspect
123
123
  else
124
124
  # In a single-quoted strings, double quotes don't need to be escaped
125
- "'#{string.gsub('\"', '"').gsub('\\') { '\\\\' }}'"
125
+ "'#{string.gsub('\\') { '\\\\' }.gsub('\"', '"')}'"
126
126
  end
127
127
  end
128
128
 
@@ -159,7 +159,7 @@ module RuboCop
159
159
  private
160
160
 
161
161
  def compatible_external_encoding_for?(src)
162
- src = src.dup if RUBY_VERSION < '2.3' || RUBY_ENGINE == 'jruby'
162
+ src = src.dup if RUBY_ENGINE == 'jruby'
163
163
  src.force_encoding(Encoding.default_external).valid_encoding?
164
164
  end
165
165
  end
@@ -83,7 +83,7 @@ module RuboCop
83
83
  end
84
84
 
85
85
  def multiple_assignment_node
86
- grandparent_node = node.parent ? node.parent.parent : nil
86
+ grandparent_node = node.parent&.parent
87
87
  return nil unless grandparent_node
88
88
  return nil unless grandparent_node.type == MULTIPLE_ASSIGNMENT_TYPE
89
89
  return nil unless node.parent.type == MULTIPLE_LEFT_HAND_SIDE_TYPE
@@ -108,34 +108,26 @@ module RuboCop
108
108
  :skip_children
109
109
  end
110
110
 
111
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
111
+ # rubocop:disable Layout/ClassStructure
112
+ NODE_HANDLER_METHOD_NAMES = [
113
+ [VARIABLE_ASSIGNMENT_TYPE, :process_variable_assignment],
114
+ [REGEXP_NAMED_CAPTURE_TYPE, :process_regexp_named_captures],
115
+ [MULTIPLE_ASSIGNMENT_TYPE, :process_variable_multiple_assignment],
116
+ [VARIABLE_REFERENCE_TYPE, :process_variable_referencing],
117
+ [RESCUE_TYPE, :process_rescue],
118
+ [ZERO_ARITY_SUPER_TYPE, :process_zero_arity_super],
119
+ [SEND_TYPE, :process_send],
120
+ *ARGUMENT_DECLARATION_TYPES.product([:process_variable_declaration]),
121
+ *OPERATOR_ASSIGNMENT_TYPES.product([:process_variable_operator_assignment]),
122
+ *LOOP_TYPES.product([:process_loop]),
123
+ *SCOPE_TYPES.product([:process_scope])
124
+ ].to_h.freeze
125
+ private_constant :NODE_HANDLER_METHOD_NAMES
126
+ # rubocop:enable Layout/ClassStructure
127
+
112
128
  def node_handler_method_name(node)
113
- case node.type
114
- when VARIABLE_ASSIGNMENT_TYPE
115
- :process_variable_assignment
116
- when REGEXP_NAMED_CAPTURE_TYPE
117
- :process_regexp_named_captures
118
- when MULTIPLE_ASSIGNMENT_TYPE
119
- :process_variable_multiple_assignment
120
- when VARIABLE_REFERENCE_TYPE
121
- :process_variable_referencing
122
- when RESCUE_TYPE
123
- :process_rescue
124
- when ZERO_ARITY_SUPER_TYPE
125
- :process_zero_arity_super
126
- when SEND_TYPE
127
- :process_send
128
- when *ARGUMENT_DECLARATION_TYPES
129
- :process_variable_declaration
130
- when *OPERATOR_ASSIGNMENT_TYPES
131
- :process_variable_operator_assignment
132
- when *LOOP_TYPES
133
- :process_loop
134
- when *SCOPE_TYPES
135
- :process_scope
136
- end
129
+ NODE_HANDLER_METHOD_NAMES[node.type]
137
130
  end
138
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
139
131
 
140
132
  def process_variable_declaration(node)
141
133
  variable_name = node.children.first
@@ -358,13 +350,12 @@ module RuboCop
358
350
  end
359
351
  end
360
352
 
361
- # Use Node#equal? for accurate check.
362
353
  def scanned_node?(node)
363
- scanned_nodes.any? { |scanned_node| scanned_node.equal?(node) }
354
+ scanned_nodes.include?(node)
364
355
  end
365
356
 
366
357
  def scanned_nodes
367
- @scanned_nodes ||= []
358
+ @scanned_nodes ||= Set.new.compare_by_identity
368
359
  end
369
360
 
370
361
  # Hooks invoked by VariableTable.
@@ -183,11 +183,10 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
183
183
  # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
184
184
 
185
185
  def to_table(header, content)
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")
186
+ table = ['|===', "| #{header.join(' | ')}\n\n"].join("\n")
189
187
  marked_contents = content.map do |plain_content|
190
- plain_content.map { |c| #{c}" }.join("\n")
188
+ # Escape `|` with backslash to prevent the regexp `|` is not used as a table separator.
189
+ plain_content.map { |c| "| #{c.gsub(/\|/, '\|')}" }.join("\n")
191
190
  end
192
191
  table << marked_contents.join("\n\n")
193
192
  table << "\n|===\n"
@@ -65,6 +65,10 @@ module RuboCop
65
65
  @options.fetch(:offense_counts, true)
66
66
  end
67
67
 
68
+ def auto_gen_enforced_style?
69
+ @options.fetch(:auto_gen_enforced_style, true)
70
+ end
71
+
68
72
  def command
69
73
  command = 'rubocop --auto-gen-config'
70
74
 
@@ -79,6 +83,8 @@ module RuboCop
79
83
 
80
84
  command += ' --no-auto-gen-timestamp' unless show_timestamp?
81
85
 
86
+ command += ' --no-auto-gen-enforced-style' unless auto_gen_enforced_style?
87
+
82
88
  command
83
89
  end
84
90
 
@@ -172,17 +178,22 @@ module RuboCop
172
178
  end
173
179
 
174
180
  def output_cop_config(output_buffer, cfg, cop_name)
175
- # 'Enabled' option will be put into file only if exclude
176
- # limit is exceeded.
177
- cfg_without_enabled = cfg.reject { |key| key == 'Enabled' }
178
-
181
+ filtered_cfg = filtered_config(cfg)
179
182
  output_buffer.puts "#{cop_name}:"
180
- cfg_without_enabled.each do |key, value|
183
+ filtered_cfg.each do |key, value|
181
184
  value = value[0] if value.is_a?(Array)
182
185
  output_buffer.puts " #{key}: #{value}"
183
186
  end
184
187
 
185
- output_offending_files(output_buffer, cfg_without_enabled, cop_name)
188
+ output_offending_files(output_buffer, filtered_cfg, cop_name)
189
+ end
190
+
191
+ def filtered_config(cfg)
192
+ # 'Enabled' option will be put into file only if exclude
193
+ # limit is exceeded.
194
+ rejected_keys = ['Enabled']
195
+ rejected_keys << 'EnforcedStyle' unless auto_gen_enforced_style?
196
+ cfg.reject { |key| rejected_keys.include?(key) }
186
197
  end
187
198
 
188
199
  def output_offending_files(output_buffer, cfg, cop_name)
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
3
4
  require 'cgi'
4
5
  require 'erb'
5
6
  require 'ostruct'
6
- require 'base64'
7
7
 
8
8
  module RuboCop
9
9
  module Formatter
@@ -6,6 +6,7 @@ module RuboCop
6
6
 
7
7
  require_relative 'formatter/base_formatter'
8
8
  require_relative 'formatter/simple_text_formatter'
9
+
9
10
  # relies on simple text
10
11
  require_relative 'formatter/clang_style_formatter'
11
12
  require_relative 'formatter/disabled_config_formatter'
@@ -18,11 +19,12 @@ module RuboCop
18
19
  require_relative 'formatter/junit_formatter'
19
20
  require_relative 'formatter/markdown_formatter'
20
21
  require_relative 'formatter/offense_count_formatter'
22
+ require_relative 'formatter/pacman_formatter'
21
23
  require_relative 'formatter/progress_formatter'
22
24
  require_relative 'formatter/quiet_formatter'
23
25
  require_relative 'formatter/tap_formatter'
24
26
  require_relative 'formatter/worst_offenders_formatter'
25
- require_relative 'formatter/pacman_formatter'
27
+
26
28
  # relies on progress formatter
27
29
  require_relative 'formatter/auto_gen_config_formatter'
28
30
 
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # @api private
5
+ module OptimizedPatterns
6
+ # A wrapper around patterns array to perform optimized search.
7
+ # @api private
8
+ class PatternsSet
9
+ def initialize(patterns)
10
+ @strings = Set.new
11
+ @patterns = []
12
+ partition_patterns(patterns)
13
+ end
14
+
15
+ def match?(path)
16
+ @strings.include?(path) || @patterns.any? { |pattern| PathUtil.match_path?(pattern, path) }
17
+ end
18
+
19
+ private
20
+
21
+ def partition_patterns(patterns)
22
+ patterns.each do |pattern|
23
+ if pattern.is_a?(String) && !pattern.match?(/[*{\[?]/)
24
+ @strings << pattern
25
+ else
26
+ @patterns << pattern
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ @cache = {}.compare_by_identity
33
+
34
+ def self.from(patterns)
35
+ @cache[patterns] ||= PatternsSet.new(patterns)
36
+ end
37
+ end
38
+ end
@@ -167,6 +167,7 @@ module RuboCop
167
167
  option(opts, '--[no-]offense-counts')
168
168
  option(opts, '--[no-]auto-gen-only-exclude')
169
169
  option(opts, '--[no-]auto-gen-timestamp')
170
+ option(opts, '--[no-]auto-gen-enforced-style')
170
171
  end
171
172
  end
172
173
 
@@ -464,7 +465,7 @@ module RuboCop
464
465
 
465
466
  # This module contains help texts for command line options.
466
467
  # @api private
467
- module OptionsHelp
468
+ module OptionsHelp # rubocop:disable Metrics/ModuleLength
468
469
  MAX_EXCL = RuboCop::Options::DEFAULT_MAXIMUM_EXCLUSION_ITEMS.to_s
469
470
  FORMATTER_OPTION_LIST = RuboCop::Formatter::FormatterSet::BUILTIN_FORMATTERS_FOR_KEYS.keys
470
471
 
@@ -486,6 +487,13 @@ module RuboCop
486
487
  auto_gen_timestamp:
487
488
  ['Include the date and time when the --auto-gen-config',
488
489
  'was run in the file it generates. Default is true.'],
490
+ auto_gen_enforced_style:
491
+ ['Add a setting to the TODO configuration file to enforce',
492
+ 'the style used, rather than a per-file exclusion',
493
+ 'if one style is used in all files for cop with',
494
+ 'EnforcedStyle as a configurable option',
495
+ 'when the --auto-gen-config was run',
496
+ 'in the file it generates. Default is true.'],
489
497
  auto_gen_only_exclude:
490
498
  ['Generate only Exclude parameters and not Max',
491
499
  'when running --auto-gen-config, except if the',
@@ -33,11 +33,18 @@ module RuboCop
33
33
  end
34
34
  end
35
35
 
36
+ # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
36
37
  def match_path?(pattern, path)
37
38
  case pattern
38
39
  when String
39
- File.fnmatch?(pattern, path, File::FNM_PATHNAME | File::FNM_EXTGLOB) ||
40
- hidden_file_in_not_hidden_dir?(pattern, path)
40
+ matches =
41
+ if pattern == path
42
+ true
43
+ elsif pattern.match?(/[*{\[?]/)
44
+ File.fnmatch?(pattern, path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
45
+ end
46
+
47
+ matches || hidden_file_in_not_hidden_dir?(pattern, path)
41
48
  when Regexp
42
49
  begin
43
50
  pattern.match?(path)
@@ -48,6 +55,7 @@ module RuboCop
48
55
  end
49
56
  end
50
57
  end
58
+ # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
51
59
 
52
60
  # Returns true for an absolute Unix or Windows path.
53
61
  def absolute?(path)
@@ -67,8 +75,12 @@ module RuboCop
67
75
  maybe_hidden_file?(path) && File.basename(path).start_with?('.')
68
76
  end
69
77
 
78
+ HIDDEN_FILE_PATTERN = "#{File::SEPARATOR}."
79
+
70
80
  # Loose check to reduce memory allocations
71
81
  def maybe_hidden_file?(path)
82
+ return false unless path.include?(HIDDEN_FILE_PATTERN)
83
+
72
84
  separator_index = path.rindex(File::SEPARATOR)
73
85
  return false unless separator_index
74
86
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'digest/sha1'
4
- require 'find'
5
4
  require 'etc'
5
+ require 'find'
6
6
  require 'zlib'
7
7
  require_relative 'cache_config'
8
8
 
@@ -44,7 +44,10 @@ module CopHelper
44
44
 
45
45
  def registry
46
46
  @registry ||= begin
47
- cops = configuration.keys.map { |cop| RuboCop::Cop::Registry.global.find_by_cop_name(cop) }
47
+ keys = configuration.keys
48
+ cops =
49
+ keys.map { |directive| RuboCop::Cop::Registry.global.find_cops_by_directive(directive) }
50
+ .flatten
48
51
  cops << cop_class if defined?(cop_class) && !cops.include?(cop_class)
49
52
  cops.compact!
50
53
  RuboCop::Cop::Registry.new(cops)
@@ -3,10 +3,10 @@
3
3
  # Require this file to load code that supports testing using RSpec.
4
4
 
5
5
  require_relative 'cop_helper'
6
- require_relative 'host_environment_simulation_helper'
7
- require_relative 'shared_contexts'
8
6
  require_relative 'expect_offense'
7
+ require_relative 'host_environment_simulation_helper'
9
8
  require_relative 'parallel_formatter'
9
+ require_relative 'shared_contexts'
10
10
 
11
11
  RSpec.configure do |config|
12
12
  config.include CopHelper
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'socket'
4
3
  require 'securerandom'
4
+ require 'socket'
5
5
 
6
6
  #
7
7
  # This code is based on https://github.com/fohte/rubocop-daemon.
@@ -17,6 +17,8 @@ module RuboCop
17
17
  # The core of server process. It starts TCP server and perform socket communication.
18
18
  # @api private
19
19
  class Core
20
+ JSON_FORMATS = %w[json j].freeze
21
+
20
22
  def self.token
21
23
  @token ||= SecureRandom.hex(4)
22
24
  end
@@ -57,6 +59,10 @@ module RuboCop
57
59
  def start_server(host, port)
58
60
  @server = TCPServer.open(host, port)
59
61
 
62
+ # JSON format does not expected output message when IDE integration with server mode.
63
+ # See: https://github.com/rubocop/rubocop/issues/11164
64
+ return if use_json_format?
65
+
60
66
  output_stream = ARGV.include?('--stderr') ? $stderr : $stdout
61
67
  output_stream.puts "RuboCop server starting on #{@server.addr[3]}:#{@server.addr[1]}."
62
68
  end
@@ -76,6 +82,15 @@ module RuboCop
76
82
  ensure
77
83
  socket.close
78
84
  end
85
+
86
+ def use_json_format?
87
+ return true if ARGV.include?('--format=json') || ARGV.include?('--format=j')
88
+ return false unless (index = ARGV.index('--format'))
89
+
90
+ format = ARGV[index + 1]
91
+
92
+ JSON_FORMATS.include?(format)
93
+ end
79
94
  end
80
95
  end
81
96
  end
@@ -84,7 +84,7 @@ module RuboCop
84
84
  # @api private
85
85
  class ToolVersionsFile < RubyVersionFile
86
86
  TOOL_VERSIONS_FILENAME = '.tool-versions'
87
- TOOL_VERSIONS_PATTERN = /\Aruby (?:ruby-)?(?<version>\d+\.\d+)/.freeze
87
+ TOOL_VERSIONS_PATTERN = /^(?:ruby )(?<version>\d+\.\d+)/.freeze
88
88
 
89
89
  def name
90
90
  "`#{TOOL_VERSIONS_FILENAME}`"
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.38.0'
6
+ STRING = '1.40.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \