rubocop 1.36.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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +78 -12
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/arguments_env.rb +17 -0
  6. data/lib/rubocop/arguments_file.rb +17 -0
  7. data/lib/rubocop/cli/command/execute_runner.rb +7 -7
  8. data/lib/rubocop/cli/command/suggest_extensions.rb +8 -1
  9. data/lib/rubocop/comment_config.rb +41 -1
  10. data/lib/rubocop/config.rb +5 -4
  11. data/lib/rubocop/config_loader.rb +5 -5
  12. data/lib/rubocop/config_loader_resolver.rb +1 -1
  13. data/lib/rubocop/cop/base.rb +2 -9
  14. data/lib/rubocop/cop/commissioner.rb +3 -1
  15. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  16. data/lib/rubocop/cop/generator.rb +1 -2
  17. data/lib/rubocop/cop/internal_affairs/create_empty_file.rb +37 -0
  18. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +111 -0
  19. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  20. data/lib/rubocop/cop/internal_affairs.rb +3 -0
  21. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
  22. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  23. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  24. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
  25. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  26. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
  27. data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
  28. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +30 -3
  29. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
  30. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +6 -2
  31. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -2
  32. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  33. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  34. data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
  35. data/lib/rubocop/cop/lint/duplicate_methods.rb +28 -9
  36. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
  37. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  38. data/lib/rubocop/cop/lint/empty_class.rb +3 -1
  39. data/lib/rubocop/cop/lint/empty_conditional_body.rb +21 -9
  40. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  41. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
  42. data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
  43. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  44. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
  45. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
  46. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  47. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +36 -4
  48. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
  49. data/lib/rubocop/cop/lint/redundant_require_statement.rb +38 -10
  50. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  51. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +18 -8
  52. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  53. data/lib/rubocop/cop/lint/shadowed_exception.rb +0 -10
  54. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -3
  55. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  56. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  57. data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
  58. data/lib/rubocop/cop/lint/void.rb +6 -6
  59. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  60. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  61. data/lib/rubocop/cop/metrics/class_length.rb +9 -4
  62. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  63. data/lib/rubocop/cop/metrics/module_length.rb +9 -4
  64. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -2
  65. data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
  66. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
  67. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +30 -8
  68. data/lib/rubocop/cop/mixin/range_help.rb +23 -0
  69. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
  70. data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
  71. data/lib/rubocop/cop/mixin/surrounding_space.rb +10 -8
  72. data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
  73. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
  74. data/lib/rubocop/cop/registry.rb +32 -14
  75. data/lib/rubocop/cop/style/access_modifier_declarations.rb +5 -7
  76. data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
  77. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  78. data/lib/rubocop/cop/style/block_delimiters.rb +2 -2
  79. data/lib/rubocop/cop/style/character_literal.rb +1 -1
  80. data/lib/rubocop/cop/style/class_equality_comparison.rb +8 -6
  81. data/lib/rubocop/cop/style/collection_compact.rb +12 -3
  82. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  83. data/lib/rubocop/cop/style/endless_method.rb +1 -1
  84. data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
  85. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  86. data/lib/rubocop/cop/style/guard_clause.rb +90 -22
  87. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
  88. data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
  89. data/lib/rubocop/cop/style/hash_except.rb +4 -0
  90. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  91. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +25 -2
  92. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -1
  93. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
  94. data/lib/rubocop/cop/style/module_function.rb +28 -6
  95. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
  96. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  97. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  98. data/lib/rubocop/cop/style/object_then.rb +3 -0
  99. data/lib/rubocop/cop/style/operator_method_call.rb +53 -0
  100. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  101. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  102. data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
  103. data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
  104. data/lib/rubocop/cop/style/redundant_constant_base.rb +72 -0
  105. data/lib/rubocop/cop/style/redundant_each.rb +116 -0
  106. data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
  107. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
  108. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
  109. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  110. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  111. data/lib/rubocop/cop/style/redundant_string_escape.rb +181 -0
  112. data/lib/rubocop/cop/style/require_order.rb +88 -0
  113. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  114. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  115. data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
  116. data/lib/rubocop/cop/style/static_class.rb +32 -1
  117. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  118. data/lib/rubocop/cop/style/symbol_array.rb +2 -0
  119. data/lib/rubocop/cop/style/symbol_proc.rb +3 -5
  120. data/lib/rubocop/cop/style/word_array.rb +2 -0
  121. data/lib/rubocop/cop/team.rb +4 -5
  122. data/lib/rubocop/cop/util.rb +2 -2
  123. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  124. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  125. data/lib/rubocop/cop/variable_force.rb +20 -29
  126. data/lib/rubocop/cops_documentation_generator.rb +2 -1
  127. data/lib/rubocop/ext/processed_source.rb +2 -0
  128. data/lib/rubocop/formatter/disabled_config_formatter.rb +25 -8
  129. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  130. data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
  131. data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
  132. data/lib/rubocop/formatter.rb +3 -1
  133. data/lib/rubocop/optimized_patterns.rb +38 -0
  134. data/lib/rubocop/options.rb +28 -16
  135. data/lib/rubocop/path_util.rb +14 -2
  136. data/lib/rubocop/result_cache.rb +1 -1
  137. data/lib/rubocop/rspec/cop_helper.rb +24 -1
  138. data/lib/rubocop/rspec/shared_contexts.rb +14 -1
  139. data/lib/rubocop/rspec/support.rb +2 -2
  140. data/lib/rubocop/runner.rb +15 -11
  141. data/lib/rubocop/server/cache.rb +5 -1
  142. data/lib/rubocop/server/cli.rb +9 -2
  143. data/lib/rubocop/server/client_command/exec.rb +5 -0
  144. data/lib/rubocop/server/core.rb +19 -2
  145. data/lib/rubocop/server/socket_reader.rb +5 -1
  146. data/lib/rubocop/server.rb +1 -1
  147. data/lib/rubocop/target_ruby.rb +1 -1
  148. data/lib/rubocop/version.rb +8 -3
  149. data/lib/rubocop.rb +18 -6
  150. metadata +18 -5
@@ -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.
@@ -185,7 +185,8 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
185
185
  def to_table(header, content)
186
186
  table = ['|===', "| #{header.join(' | ')}\n\n"].join("\n")
187
187
  marked_contents = content.map do |plain_content|
188
- 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")
189
190
  end
190
191
  table << marked_contents.join("\n\n")
191
192
  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
@@ -65,18 +65,26 @@ 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
 
71
75
  command += ' --auto-gen-only-exclude' if @options[:auto_gen_only_exclude]
72
76
 
73
- if @exclude_limit_option
77
+ if no_exclude_limit?
78
+ command += ' --no-exclude-limit'
79
+ elsif @exclude_limit_option
74
80
  command += format(' --exclude-limit %<limit>d', limit: Integer(@exclude_limit_option))
75
81
  end
76
82
  command += ' --no-offense-counts' unless show_offense_counts?
77
83
 
78
84
  command += ' --no-auto-gen-timestamp' unless show_timestamp?
79
85
 
86
+ command += ' --no-auto-gen-enforced-style' unless auto_gen_enforced_style?
87
+
80
88
  command
81
89
  end
82
90
 
@@ -170,24 +178,29 @@ module RuboCop
170
178
  end
171
179
 
172
180
  def output_cop_config(output_buffer, cfg, cop_name)
173
- # 'Enabled' option will be put into file only if exclude
174
- # limit is exceeded.
175
- cfg_without_enabled = cfg.reject { |key| key == 'Enabled' }
176
-
181
+ filtered_cfg = filtered_config(cfg)
177
182
  output_buffer.puts "#{cop_name}:"
178
- cfg_without_enabled.each do |key, value|
183
+ filtered_cfg.each do |key, value|
179
184
  value = value[0] if value.is_a?(Array)
180
185
  output_buffer.puts " #{key}: #{value}"
181
186
  end
182
187
 
183
- 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) }
184
197
  end
185
198
 
186
199
  def output_offending_files(output_buffer, cfg, cop_name)
187
200
  return unless cfg.empty?
188
201
 
189
202
  offending_files = @files_with_offenses[cop_name].sort
190
- if offending_files.count > @exclude_limit
203
+ if !no_exclude_limit? && offending_files.count > @exclude_limit
191
204
  output_buffer.puts ' Enabled: false'
192
205
  else
193
206
  output_exclude_list(output_buffer, offending_files, cop_name)
@@ -245,6 +258,10 @@ module RuboCop
245
258
  def safe_autocorrect?(config)
246
259
  config.fetch('Safe', true) && config.fetch('SafeAutoCorrect', true)
247
260
  end
261
+
262
+ def no_exclude_limit?
263
+ @options[:no_exclude_limit] == false
264
+ end
248
265
  end
249
266
  end
250
267
  end
@@ -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
@@ -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
@@ -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
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
- require 'shellwords'
4
+ require_relative 'arguments_env'
5
+ require_relative 'arguments_file'
5
6
 
6
7
  module RuboCop
7
8
  class IncorrectCopNameError < StandardError; end
@@ -24,7 +25,10 @@ module RuboCop
24
25
  end
25
26
 
26
27
  def parse(command_line_args)
28
+ args_from_file = ArgumentsFile.read_as_arguments
29
+ args_from_env = ArgumentsEnv.read_as_arguments
27
30
  args = args_from_file.concat(args_from_env).concat(command_line_args)
31
+
28
32
  define_options.parse!(args)
29
33
 
30
34
  @validator.validate_compatibility
@@ -45,18 +49,6 @@ module RuboCop
45
49
 
46
50
  private
47
51
 
48
- def args_from_file
49
- if File.exist?('.rubocop') && !File.directory?('.rubocop')
50
- File.read('.rubocop').shellsplit
51
- else
52
- []
53
- end
54
- end
55
-
56
- def args_from_env
57
- Shellwords.split(ENV.fetch('RUBOCOP_OPTS', ''))
58
- end
59
-
60
52
  def define_options
61
53
  OptionParser.new do |opts|
62
54
  opts.banner = rainbow.wrap('Usage: rubocop [options] [file1, file2, ...]').bright
@@ -73,7 +65,7 @@ module RuboCop
73
65
  end
74
66
 
75
67
  def add_check_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
76
- section(opts, 'Basic Options') do
68
+ section(opts, 'Basic Options') do # rubocop:disable Metrics/BlockLength
77
69
  option(opts, '-l', '--lint') do
78
70
  @options[:only] ||= []
79
71
  @options[:only] << 'Lint'
@@ -98,6 +90,7 @@ module RuboCop
98
90
  option(opts, '--force-default-config')
99
91
  option(opts, '-s', '--stdin FILE')
100
92
  option(opts, '-P', '--[no-]parallel')
93
+ option(opts, '--raise-cop-error')
101
94
  add_severity_option(opts)
102
95
  end
103
96
  end
@@ -169,10 +162,12 @@ module RuboCop
169
162
  end
170
163
 
171
164
  option(opts, '--exclude-limit COUNT') { @validator.validate_exclude_limit_option }
165
+ option(opts, '--no-exclude-limit')
172
166
 
173
167
  option(opts, '--[no-]offense-counts')
174
168
  option(opts, '--[no-]auto-gen-only-exclude')
175
169
  option(opts, '--[no-]auto-gen-timestamp')
170
+ option(opts, '--[no-]auto-gen-enforced-style')
176
171
  end
177
172
  end
178
173
 
@@ -400,6 +395,12 @@ module RuboCop
400
395
  end
401
396
 
402
397
  def validate_autocorrect
398
+ if @options.key?(:safe_autocorrect) && @options.key?(:autocorrect_all)
399
+ message = Rainbow(<<~MESSAGE).red
400
+ Error: Both safe and unsafe autocorrect options are specified, use only one.
401
+ MESSAGE
402
+ raise OptionArgumentError, message
403
+ end
403
404
  return if @options.key?(:autocorrect)
404
405
  return unless @options.key?(:disable_uncorrectable)
405
406
 
@@ -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',
@@ -497,6 +505,7 @@ module RuboCop
497
505
  disable_uncorrectable: ['Used with --autocorrect to annotate any',
498
506
  'offenses that do not support autocorrect',
499
507
  'with `rubocop:todo` comments.'],
508
+ no_exclude_limit: ['Do not set the limit for how many files to exclude.'],
500
509
  force_exclusion: ['Any files excluded by `Exclude` in configuration',
501
510
  'files will be excluded, even if given explicitly',
502
511
  'as arguments.'],
@@ -589,7 +598,10 @@ module RuboCop
589
598
  restart_server: 'Restart server process.',
590
599
  start_server: 'Start server process.',
591
600
  stop_server: 'Stop server process.',
592
- server_status: 'Show server status.'
601
+ server_status: 'Show server status.',
602
+ raise_cop_error: ['Raise cop-related errors with cause and location.',
603
+ 'This is used to prevent cops from failing silently.',
604
+ 'Default is false.']
593
605
  }.freeze
594
606
  end
595
607
  end
@@ -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
 
@@ -28,7 +28,30 @@ 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
+ keys = configuration.keys
48
+ cops =
49
+ keys.map { |directive| RuboCop::Cop::Registry.global.find_cops_by_directive(directive) }
50
+ .flatten
51
+ cops << cop_class if defined?(cop_class) && !cops.include?(cop_class)
52
+ cops.compact!
53
+ RuboCop::Cop::Registry.new(cops)
54
+ end
32
55
  end
33
56
 
34
57
  def autocorrect_source_file(source)
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'tmpdir'
4
4
 
5
- RSpec.shared_context 'isolated environment' do
5
+ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLength
6
6
  around do |example|
7
7
  Dir.mktmpdir do |tmpdir|
8
8
  original_home = Dir.home
@@ -36,6 +36,19 @@ RSpec.shared_context 'isolated environment' do
36
36
  end
37
37
  end
38
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
39
52
  end
40
53
 
41
54
  RSpec.shared_context 'maintain registry' do
@@ -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
@@ -423,17 +423,21 @@ module RuboCop
423
423
  end
424
424
 
425
425
  def get_processed_source(file)
426
- ruby_version = @config_store.for_file(file).target_ruby_version
427
-
428
- if @options[:stdin]
429
- ProcessedSource.new(@options[:stdin], ruby_version, file)
430
- else
431
- begin
432
- ProcessedSource.from_file(file, ruby_version)
433
- rescue Errno::ENOENT
434
- raise RuboCop::Error, "No such file or directory: #{file}"
435
- end
436
- end
426
+ config = @config_store.for_file(file)
427
+ ruby_version = config.target_ruby_version
428
+
429
+ processed_source = if @options[:stdin]
430
+ ProcessedSource.new(@options[:stdin], ruby_version, file)
431
+ else
432
+ begin
433
+ ProcessedSource.from_file(file, ruby_version)
434
+ rescue Errno::ENOENT
435
+ raise RuboCop::Error, "No such file or directory: #{file}"
436
+ end
437
+ end
438
+ processed_source.config = config
439
+ processed_source.registry = mobilized_cop_classes(config)
440
+ processed_source
437
441
  end
438
442
 
439
443
  # A Cop::Team instance is stateful and may change when inspecting.
@@ -103,9 +103,13 @@ module RuboCop
103
103
  dir.join('version')
104
104
  end
105
105
 
106
+ def stderr_path
107
+ dir.join('stderr')
108
+ end
109
+
106
110
  def pid_running?
107
111
  Process.kill(0, pid_path.read.to_i) == 1
108
- rescue Errno::ESRCH
112
+ rescue Errno::ESRCH, Errno::ENOENT
109
113
  false
110
114
  end
111
115
 
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rainbow'
4
+ require_relative '../arguments_env'
5
+ require_relative '../arguments_file'
4
6
 
5
7
  #
6
8
  # This code is based on https://github.com/fohte/rubocop-daemon.
@@ -29,7 +31,7 @@ module RuboCop
29
31
  @exit = false
30
32
  end
31
33
 
32
- # rubocop:disable Metrics/MethodLength
34
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
33
35
  def run(argv = ARGV)
34
36
  unless Server.support_server?
35
37
  return error('RuboCop server is not supported by this Ruby.') if use_server_option?(argv)
@@ -50,11 +52,16 @@ module RuboCop
50
52
  return error("#{server_command} cannot be combined with other options.")
51
53
  end
52
54
 
55
+ if server_command.nil?
56
+ server_command = ArgumentsEnv.read_as_arguments.delete('--server') ||
57
+ ArgumentsFile.read_as_arguments.delete('--server')
58
+ end
59
+
53
60
  run_command(server_command)
54
61
 
55
62
  STATUS_SUCCESS
56
63
  end
57
- # rubocop:enable Metrics/MethodLength
64
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
58
65
 
59
66
  def exit?
60
67
  @exit
@@ -23,6 +23,7 @@ module RuboCop
23
23
  args: ARGV.dup,
24
24
  body: $stdin.tty? ? '' : $stdin.read
25
25
  )
26
+ warn stderr unless stderr.empty?
26
27
  status
27
28
  end
28
29
 
@@ -43,6 +44,10 @@ module RuboCop
43
44
  RuboCop::Version::STRING != Cache.version_path.read
44
45
  end
45
46
 
47
+ def stderr
48
+ Cache.stderr_path.read
49
+ end
50
+
46
51
  def status
47
52
  unless Cache.status_path.file?
48
53
  raise "RuboCop server: Could not find status file at: #{Cache.status_path}"