rubocop 1.43.0 → 1.45.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +64 -29
  4. data/lib/rubocop/cli.rb +54 -8
  5. data/lib/rubocop/config_loader.rb +12 -15
  6. data/lib/rubocop/config_loader_resolver.rb +3 -4
  7. data/lib/rubocop/cop/base.rb +27 -9
  8. data/lib/rubocop/cop/commissioner.rb +8 -2
  9. data/lib/rubocop/cop/cop.rb +23 -3
  10. data/lib/rubocop/cop/corrector.rb +10 -2
  11. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
  12. data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
  13. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
  14. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  15. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
  16. data/lib/rubocop/cop/layout/class_structure.rb +2 -16
  17. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
  18. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  19. data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
  20. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  21. data/lib/rubocop/cop/layout/space_around_operators.rb +1 -1
  22. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +11 -13
  23. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +4 -4
  24. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +5 -4
  25. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
  26. data/lib/rubocop/cop/lint/debugger.rb +8 -27
  27. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
  28. data/lib/rubocop/cop/lint/else_layout.rb +2 -6
  29. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +14 -7
  30. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
  31. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  32. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  33. data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -5
  34. data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
  35. data/lib/rubocop/cop/lint/useless_access_modifier.rb +7 -4
  36. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
  37. data/lib/rubocop/cop/lint/useless_rescue.rb +15 -1
  38. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +9 -1
  39. data/lib/rubocop/cop/lint/void.rb +19 -10
  40. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  41. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  42. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  43. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +2 -5
  44. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  45. data/lib/rubocop/cop/mixin/allowed_methods.rb +3 -1
  46. data/lib/rubocop/cop/mixin/comments_help.rb +5 -3
  47. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +51 -25
  48. data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
  49. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -3
  50. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  51. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -0
  52. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
  53. data/lib/rubocop/cop/registry.rb +12 -7
  54. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -11
  55. data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -0
  56. data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
  57. data/lib/rubocop/cop/style/class_and_module_children.rb +3 -10
  58. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  59. data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
  60. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
  61. data/lib/rubocop/cop/style/documentation.rb +1 -1
  62. data/lib/rubocop/cop/style/documentation_method.rb +6 -0
  63. data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
  64. data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
  65. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -5
  66. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
  67. data/lib/rubocop/cop/style/min_max_comparison.rb +11 -1
  68. data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
  69. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  70. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +18 -3
  71. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
  72. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +11 -3
  73. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
  74. data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
  75. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
  76. data/lib/rubocop/cop/style/redundant_condition.rb +16 -1
  77. data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
  78. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -10
  79. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +58 -0
  80. data/lib/rubocop/cop/style/require_order.rb +2 -9
  81. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  82. data/lib/rubocop/cop/style/semicolon.rb +24 -2
  83. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  84. data/lib/rubocop/cop/style/word_array.rb +1 -1
  85. data/lib/rubocop/cop/style/yoda_condition.rb +12 -5
  86. data/lib/rubocop/cop/style/yoda_expression.rb +11 -2
  87. data/lib/rubocop/cop/team.rb +19 -14
  88. data/lib/rubocop/cop/variable_force/scope.rb +3 -3
  89. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
  90. data/lib/rubocop/cop/variable_force.rb +1 -1
  91. data/lib/rubocop/formatter.rb +0 -1
  92. data/lib/rubocop/options.rb +22 -1
  93. data/lib/rubocop/rspec/expect_offense.rb +6 -4
  94. data/lib/rubocop/runner.rb +40 -4
  95. data/lib/rubocop/server/cache.rb +10 -3
  96. data/lib/rubocop/server/cli.rb +37 -18
  97. data/lib/rubocop/server/client_command/exec.rb +1 -1
  98. data/lib/rubocop/server/client_command/start.rb +6 -1
  99. data/lib/rubocop/server/core.rb +23 -8
  100. data/lib/rubocop/version.rb +1 -1
  101. data/lib/rubocop.rb +4 -0
  102. metadata +11 -27
@@ -33,12 +33,14 @@ module RuboCop
33
33
  # "bar" != foo
34
34
  # 42 >= foo
35
35
  # 10 < bar
36
+ # 99 == CONST
36
37
  #
37
38
  # # good
38
39
  # foo == 99
39
40
  # foo == "bar"
40
41
  # foo <= 42
41
42
  # bar > 10
43
+ # CONST == 99
42
44
  # "#{interpolation}" == foo
43
45
  # /#{interpolation}/ == foo
44
46
  #
@@ -92,9 +94,10 @@ module RuboCop
92
94
  def on_send(node)
93
95
  return unless yoda_compatible_condition?(node)
94
96
  return if (equality_only? && non_equality_operator?(node)) ||
95
- file_constant_equal_program_name?(node)
97
+ file_constant_equal_program_name?(node) ||
98
+ valid_yoda?(node)
96
99
 
97
- valid_yoda?(node) || add_offense(node) do |corrector|
100
+ add_offense(node) do |corrector|
98
101
  corrector.replace(actual_code_range(node), corrected_code(node))
99
102
  end
100
103
  end
@@ -119,11 +122,11 @@ module RuboCop
119
122
  lhs = node.receiver
120
123
  rhs = node.first_argument
121
124
 
122
- return true if (lhs.literal? && rhs.literal?) ||
123
- (!lhs.literal? && !rhs.literal?) ||
125
+ return true if (constant_portion?(lhs) && constant_portion?(rhs)) ||
126
+ (!constant_portion?(lhs) && !constant_portion?(rhs)) ||
124
127
  interpolation?(lhs)
125
128
 
126
- enforce_yoda? ? lhs.literal? : rhs.literal?
129
+ enforce_yoda? ? constant_portion?(lhs) : constant_portion?(rhs)
127
130
  end
128
131
 
129
132
  def message(node)
@@ -137,6 +140,10 @@ module RuboCop
137
140
  "#{rhs.source} #{reverse_comparison(node.method_name)} #{lhs.source}"
138
141
  end
139
142
 
143
+ def constant_portion?(node)
144
+ node.literal? || node.const_type?
145
+ end
146
+
140
147
  def actual_code_range(node)
141
148
  range_between(node.loc.expression.begin_pos, node.loc.expression.end_pos)
142
149
  end
@@ -24,12 +24,14 @@ module RuboCop
24
24
  # 1 + x
25
25
  # 10 * y
26
26
  # 1 & z
27
+ # 1 + CONST
27
28
  #
28
29
  # # good
29
30
  # 60 * 24
30
31
  # x + 1
31
32
  # y * 10
32
33
  # z & 1
34
+ # CONST + 1
33
35
  #
34
36
  # # good
35
37
  # 1 | x
@@ -50,8 +52,7 @@ module RuboCop
50
52
 
51
53
  lhs = node.receiver
52
54
  rhs = node.first_argument
53
- return if !lhs.numeric_type? || rhs.numeric_type?
54
-
55
+ return unless yoda_expression_constant?(lhs, rhs)
55
56
  return if offended_ancestor?(node)
56
57
 
57
58
  message = format(MSG, source: rhs.source)
@@ -64,6 +65,14 @@ module RuboCop
64
65
 
65
66
  private
66
67
 
68
+ def yoda_expression_constant?(lhs, rhs)
69
+ constant_portion?(lhs) && !constant_portion?(rhs)
70
+ end
71
+
72
+ def constant_portion?(node)
73
+ node.numeric_type? || node.const_type?
74
+ end
75
+
67
76
  def supported_operators
68
77
  Array(cop_config['SupportedOperators'])
69
78
  end
@@ -77,7 +77,7 @@ module RuboCop
77
77
  end
78
78
 
79
79
  # @return [Commissioner::InvestigationReport]
80
- def investigate(processed_source)
80
+ def investigate(processed_source, offset: 0, original: processed_source)
81
81
  be_ready
82
82
 
83
83
  # The autocorrection process may have to be repeated multiple times
@@ -87,14 +87,15 @@ module RuboCop
87
87
  on_duty = roundup_relevant_cops(processed_source.file_path)
88
88
 
89
89
  autocorrect_cops, other_cops = on_duty.partition(&:autocorrect?)
90
+ report = investigate_partial(autocorrect_cops, processed_source,
91
+ offset: offset, original: original)
90
92
 
91
- report = investigate_partial(autocorrect_cops, processed_source)
92
-
93
- unless autocorrect(processed_source, report)
93
+ unless autocorrect(processed_source, report, offset: offset, original: original)
94
94
  # If we corrected some errors, another round of inspection will be
95
95
  # done, and any other offenses will be caught then, so only need
96
96
  # to check other_cops if no correction was done
97
- report = report.merge(investigate_partial(other_cops, processed_source))
97
+ report = report.merge(investigate_partial(other_cops, processed_source,
98
+ offset: offset, original: original))
98
99
  end
99
100
 
100
101
  process_errors(processed_source.path, report.errors)
@@ -116,12 +117,12 @@ module RuboCop
116
117
 
117
118
  private
118
119
 
119
- def autocorrect(processed_source, report)
120
+ def autocorrect(processed_source, report, original:, offset:)
120
121
  @updated_source_file = false
121
122
  return unless autocorrect?
122
123
  return if report.processed_source.parser_error
123
124
 
124
- new_source = autocorrect_report(report)
125
+ new_source = autocorrect_report(report, original: original, offset: offset)
125
126
 
126
127
  return unless new_source
127
128
 
@@ -149,9 +150,9 @@ module RuboCop
149
150
  end
150
151
 
151
152
  # @return [Commissioner::InvestigationReport]
152
- def investigate_partial(cops, processed_source)
153
+ def investigate_partial(cops, processed_source, offset:, original:)
153
154
  commissioner = Commissioner.new(cops, self.class.forces_for(cops), @options)
154
- commissioner.investigate(processed_source)
155
+ commissioner.investigate(processed_source, offset: offset, original: original)
155
156
  end
156
157
 
157
158
  # @return [Array<cop>]
@@ -175,18 +176,22 @@ module RuboCop
175
176
  cop.class.support_target_rails_version?(cop.target_rails_version)
176
177
  end
177
178
 
178
- def autocorrect_report(report)
179
- corrector = collate_corrections(report)
179
+ def autocorrect_report(report, offset:, original:)
180
+ corrector = collate_corrections(report, offset: offset, original: original)
180
181
 
181
182
  corrector.rewrite unless corrector.empty?
182
183
  end
183
184
 
184
- def collate_corrections(report)
185
- corrector = Corrector.new(report.processed_source)
185
+ def collate_corrections(report, offset:, original:)
186
+ corrector = Corrector.new(original)
186
187
 
187
188
  each_corrector(report) do |to_merge|
188
189
  suppress_clobbering do
189
- corrector.merge!(to_merge)
190
+ if offset.positive?
191
+ corrector.import!(to_merge, offset: offset)
192
+ else
193
+ corrector.merge!(to_merge)
194
+ end
190
195
  end
191
196
  end
192
197
 
@@ -45,9 +45,9 @@ module RuboCop
45
45
  node
46
46
  else
47
47
  child_index = case node.type
48
- when :module, :sclass then 1
49
- when :def, :class, :block then 2
50
- when :defs then 3
48
+ when :module, :sclass then 1
49
+ when :def, :class, :block, :numblock then 2
50
+ when :defs then 3
51
51
  end
52
52
 
53
53
  node.children[child_index]
@@ -97,8 +97,10 @@ module RuboCop
97
97
  scope_stack.reverse_each do |scope|
98
98
  variable = scope.variables[name]
99
99
  return variable if variable
100
+
100
101
  # Only block scope allows referencing outer scope variables.
101
- return nil unless scope.node.block_type?
102
+ node = scope.node
103
+ return nil unless node.block_type? || node.numblock_type?
102
104
  end
103
105
 
104
106
  nil
@@ -50,7 +50,7 @@ module RuboCop
50
50
 
51
51
  ZERO_ARITY_SUPER_TYPE = :zsuper
52
52
 
53
- TWISTED_SCOPE_TYPES = %i[block class sclass defs module].freeze
53
+ TWISTED_SCOPE_TYPES = %i[block numblock class sclass defs module].freeze
54
54
  SCOPE_TYPES = (TWISTED_SCOPE_TYPES + [:def]).freeze
55
55
 
56
56
  SEND_TYPE = :send
@@ -2,7 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  # The bootstrap module for formatter.
5
- # @api private
6
5
  module Formatter
7
6
  require_relative 'formatter/text_util'
8
7
 
@@ -61,6 +61,9 @@ module RuboCop
61
61
  add_config_generation_options(opts)
62
62
  add_additional_modes(opts)
63
63
  add_general_options(opts)
64
+
65
+ # `stackprof` is not supported on JRuby and Windows.
66
+ add_profile_options(opts) if RUBY_ENGINE == 'ruby' && !Platform.windows?
64
67
  end
65
68
  end
66
69
 
@@ -206,6 +209,7 @@ module RuboCop
206
209
  option(opts, '--start-server')
207
210
  option(opts, '--stop-server')
208
211
  option(opts, '--server-status')
212
+ option(opts, '--no-detach')
209
213
  end
210
214
  end
211
215
 
@@ -233,6 +237,16 @@ module RuboCop
233
237
  end
234
238
  end
235
239
 
240
+ def add_profile_options(opts)
241
+ section(opts, 'Profiling Options') do
242
+ option(opts, '--profile') do
243
+ @options[:profile] = true
244
+ @options[:cache] = 'false' unless @options.key?(:cache)
245
+ end
246
+ option(opts, '--memory')
247
+ end
248
+ end
249
+
236
250
  def handle_deprecated_option(old_option, new_option)
237
251
  warn rainbow.wrap("#{old_option} is deprecated; use #{new_option} instead.").yellow
238
252
  @options[long_opt_symbol([new_option])] = @options.delete(long_opt_symbol([old_option]))
@@ -424,6 +438,8 @@ module RuboCop
424
438
  def invalid_arguments_for_parallel
425
439
  [('--auto-gen-config' if @options.key?(:auto_gen_config)),
426
440
  ('-F/--fail-fast' if @options.key?(:fail_fast)),
441
+ ('--profile' if @options[:profile]),
442
+ ('--memory' if @options[:memory]),
427
443
  ('--cache false' if @options > { cache: 'false' })].compact
428
444
  end
429
445
 
@@ -465,6 +481,7 @@ module RuboCop
465
481
 
466
482
  # This module contains help texts for command line options.
467
483
  # @api private
484
+ # rubocop:disable Metrics/ModuleLength
468
485
  module OptionsHelp
469
486
  MAX_EXCL = RuboCop::Options::DEFAULT_MAXIMUM_EXCLUSION_ITEMS.to_s
470
487
  FORMATTER_OPTION_LIST = RuboCop::Formatter::FormatterSet::BUILTIN_FORMATTERS_FOR_KEYS.keys
@@ -599,9 +616,13 @@ module RuboCop
599
616
  start_server: 'Start server process.',
600
617
  stop_server: 'Stop server process.',
601
618
  server_status: 'Show server status.',
619
+ no_detach: 'Run the server process in the foreground.',
602
620
  raise_cop_error: ['Raise cop-related errors with cause and location.',
603
621
  'This is used to prevent cops from failing silently.',
604
- 'Default is false.']
622
+ 'Default is false.'],
623
+ profile: 'Profile rubocop',
624
+ memory: 'Profile rubocop memory usage'
605
625
  }.freeze
606
626
  end
627
+ # rubocop:enable Metrics/ModuleLength
607
628
  end
@@ -6,7 +6,7 @@ module RuboCop
6
6
  #
7
7
  # This mixin makes it easier to specify strict offense expectations
8
8
  # in a declarative and visual fashion. Just type out the code that
9
- # should generate a offense, annotate code by writing '^'s
9
+ # should generate an offense, annotate code by writing '^'s
10
10
  # underneath each character that should be highlighted, and follow
11
11
  # the carets with a string (separated by a space) that is the
12
12
  # message of the offense. You can include multiple offenses in
@@ -126,7 +126,7 @@ module RuboCop
126
126
  @offenses
127
127
  end
128
128
 
129
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
129
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
130
130
  def expect_correction(correction, loop: true, source: nil)
131
131
  if source
132
132
  expected_annotations = parse_annotations(source, raise_error: false)
@@ -138,6 +138,8 @@ module RuboCop
138
138
 
139
139
  source = @processed_source.raw_source
140
140
 
141
+ raise 'Use `expect_no_corrections` if the code will not change' if correction == source
142
+
141
143
  iteration = 0
142
144
  new_source = loop do
143
145
  iteration += 1
@@ -157,11 +159,11 @@ module RuboCop
157
159
  _investigate(cop, @processed_source)
158
160
  end
159
161
 
160
- raise 'Use `expect_no_corrections` if the code will not change' if new_source == source
162
+ raise 'Expected correction but no corrections were made' if new_source == source
161
163
 
162
164
  expect(new_source).to eq(correction)
163
165
  end
164
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
166
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
165
167
 
166
168
  def expect_no_corrections
167
169
  raise '`expect_no_corrections` must follow `expect_offense`' unless @processed_source
@@ -24,6 +24,27 @@ module RuboCop
24
24
  end
25
25
  end
26
26
 
27
+ class << self
28
+ # @return [Array<#call>]
29
+ def ruby_extractors
30
+ @ruby_extractors ||= [default_ruby_extractor]
31
+ end
32
+
33
+ private
34
+
35
+ # @return [#call]
36
+ def default_ruby_extractor
37
+ lambda do |processed_source|
38
+ [
39
+ {
40
+ offset: 0,
41
+ processed_source: processed_source
42
+ }
43
+ ]
44
+ end
45
+ end
46
+ end
47
+
27
48
  # @api private
28
49
  MAX_ITERATIONS = 200
29
50
 
@@ -319,10 +340,25 @@ module RuboCop
319
340
  end
320
341
 
321
342
  def inspect_file(processed_source, team = mobilize_team(processed_source))
322
- report = team.investigate(processed_source)
323
- @errors.concat(team.errors)
324
- @warnings.concat(team.warnings)
325
- [report.offenses, team.updated_source_file?]
343
+ extracted_ruby_sources = extract_ruby_sources(processed_source)
344
+ offenses = extracted_ruby_sources.flat_map do |extracted_ruby_source|
345
+ report = team.investigate(
346
+ extracted_ruby_source[:processed_source],
347
+ offset: extracted_ruby_source[:offset],
348
+ original: processed_source
349
+ )
350
+ @errors.concat(team.errors)
351
+ @warnings.concat(team.warnings)
352
+ report.offenses
353
+ end
354
+ [offenses, team.updated_source_file?]
355
+ end
356
+
357
+ def extract_ruby_sources(processed_source)
358
+ self.class.ruby_extractors.find do |ruby_extractor|
359
+ result = ruby_extractor.call(processed_source)
360
+ break result if result
361
+ end
326
362
  end
327
363
 
328
364
  def mobilize_team(processed_source)
@@ -57,18 +57,24 @@ module RuboCop
57
57
  File.expand_path(File.join(cache_root_dir, 'server'))
58
58
  end
59
59
 
60
+ # rubocop:disable Metrics/MethodLength
60
61
  def cache_root_dir_from_config
61
62
  CacheConfig.root_dir do
62
63
  # `RuboCop::ConfigStore` has heavy dependencies, this is a lightweight implementation
63
64
  # so that only the necessary `CacheRootDirectory` can be obtained.
64
- require 'yaml'
65
65
  config_path = ConfigFinder.find_config_path(Dir.pwd)
66
+ file_contents = File.read(config_path)
67
+
68
+ # Returns early if `CacheRootDirectory` is not used before requiring `erb` or `yaml`.
69
+ next unless file_contents.include?('CacheRootDirectory')
66
70
 
67
71
  require 'erb'
68
- file_contents = File.read(config_path)
69
72
  yaml_code = ERB.new(file_contents).result
70
73
 
71
- config_yaml = YAML.safe_load(yaml_code, permitted_classes: [Regexp, Symbol])
74
+ require 'yaml'
75
+ config_yaml = YAML.safe_load(
76
+ yaml_code, permitted_classes: [Regexp, Symbol], aliases: true
77
+ )
72
78
 
73
79
  # For compatibility with Ruby 3.0 or lower.
74
80
  if Gem::Version.new(Psych::VERSION) < Gem::Version.new('4.0.0')
@@ -78,6 +84,7 @@ module RuboCop
78
84
  config_yaml&.dig('AllCops', 'CacheRootDirectory')
79
85
  end
80
86
  end
87
+ # rubocop:enable Metrics/MethodLength
81
88
 
82
89
  def port_path
83
90
  dir.join('port')
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rainbow'
4
3
  require_relative '../arguments_env'
5
4
  require_relative '../arguments_file'
6
5
 
@@ -23,15 +22,21 @@ module RuboCop
23
22
  STATUS_ERROR = 2
24
23
 
25
24
  SERVER_OPTIONS = %w[
26
- --server --no-server --server-status --restart-server --start-server --stop-server
25
+ --server
26
+ --no-server
27
+ --server-status
28
+ --restart-server
29
+ --start-server
30
+ --stop-server
31
+ --no-detach
27
32
  ].freeze
28
33
  EXCLUSIVE_OPTIONS = (SERVER_OPTIONS - %w[--server --no-server]).freeze
34
+ NO_DETACH_OPTIONS = %w[--server --start-server --restart-server].freeze
29
35
 
30
36
  def initialize
31
37
  @exit = false
32
38
  end
33
39
 
34
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
35
40
  def run(argv = ARGV)
36
41
  unless Server.support_server?
37
42
  return error('RuboCop server is not supported by this Ruby.') if use_server_option?(argv)
@@ -40,16 +45,34 @@ module RuboCop
40
45
  end
41
46
 
42
47
  Cache.cache_root_path = fetch_cache_root_path_from(argv)
43
- deleted_server_arguments = delete_server_argument_from(argv)
44
48
 
45
- if deleted_server_arguments.size >= 2
46
- return error("#{deleted_server_arguments.join(', ')} cannot be specified together.")
49
+ process_arguments(argv)
50
+ end
51
+
52
+ def exit?
53
+ @exit
54
+ end
55
+
56
+ private
57
+
58
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
59
+ def process_arguments(argv)
60
+ server_arguments = delete_server_argument_from(argv)
61
+
62
+ detach = !server_arguments.delete('--no-detach')
63
+
64
+ if server_arguments.size >= 2
65
+ return error("#{server_arguments.join(', ')} cannot be specified together.")
47
66
  end
48
67
 
49
- server_command = deleted_server_arguments.first
68
+ server_command = server_arguments.first
69
+
70
+ unless detach || NO_DETACH_OPTIONS.include?(server_command)
71
+ return error("#{server_command} cannot be combined with --no-detach.")
72
+ end
50
73
 
51
74
  if EXCLUSIVE_OPTIONS.include?(server_command) && argv.count > allowed_option_count
52
- return error("#{server_command} cannot be combined with other options.")
75
+ return error("#{server_command} cannot be combined with #{argv[0]}.")
53
76
  end
54
77
 
55
78
  if server_command.nil?
@@ -57,23 +80,17 @@ module RuboCop
57
80
  ArgumentsFile.read_as_arguments.delete('--server')
58
81
  end
59
82
 
60
- run_command(server_command)
83
+ run_command(server_command, detach: detach)
61
84
 
62
85
  STATUS_SUCCESS
63
86
  end
64
87
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
65
88
 
66
- def exit?
67
- @exit
68
- end
69
-
70
- private
71
-
72
89
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength:
73
- def run_command(server_command)
90
+ def run_command(server_command, detach:)
74
91
  case server_command
75
92
  when '--server'
76
- Server::ClientCommand::Start.new.run unless Server.running?
93
+ Server::ClientCommand::Start.new(detach: detach).run unless Server.running?
77
94
  when '--no-server'
78
95
  Server::ClientCommand::Stop.new.run if Server.running?
79
96
  when '--restart-server'
@@ -81,7 +98,7 @@ module RuboCop
81
98
  Server::ClientCommand::Restart.new.run
82
99
  when '--start-server'
83
100
  @exit = true
84
- Server::ClientCommand::Start.new.run
101
+ Server::ClientCommand::Start.new(detach: detach).run
85
102
  when '--stop-server'
86
103
  @exit = true
87
104
  Server::ClientCommand::Stop.new.run
@@ -118,6 +135,8 @@ module RuboCop
118
135
  end
119
136
 
120
137
  def error(message)
138
+ require 'rainbow'
139
+
121
140
  @exit = true
122
141
  warn Rainbow(message).red
123
142
 
@@ -41,7 +41,7 @@ module RuboCop
41
41
  end
42
42
 
43
43
  def incompatible_version?
44
- RuboCop::Version::STRING != Cache.version_path.read
44
+ Cache.version_path.read != RuboCop::Version::STRING
45
45
  end
46
46
 
47
47
  def stderr
@@ -15,6 +15,11 @@ module RuboCop
15
15
  # This class is a client command to start server process.
16
16
  # @api private
17
17
  class Start < Base
18
+ def initialize(detach: true)
19
+ @detach = detach
20
+ super()
21
+ end
22
+
18
23
  def run
19
24
  if Server.running?
20
25
  warn "RuboCop server (#{Cache.pid_path.read}) is already running."
@@ -34,7 +39,7 @@ module RuboCop
34
39
  host = ENV.fetch('RUBOCOP_SERVER_HOST', '127.0.0.1')
35
40
  port = ENV.fetch('RUBOCOP_SERVER_PORT', 0)
36
41
 
37
- Server::Core.new.start(host, port)
42
+ Server::Core.new.start(host, port, detach: @detach)
38
43
  end
39
44
  end
40
45
  end
@@ -27,31 +27,46 @@ module RuboCop
27
27
  self.class.token
28
28
  end
29
29
 
30
- def start(host, port)
30
+ def start(host, port, detach: true)
31
31
  $PROGRAM_NAME = "rubocop --server #{Cache.project_dir}"
32
32
 
33
- require 'rubocop'
33
+ require_relative '../../rubocop'
34
34
  start_server(host, port)
35
35
 
36
- demonize if server_mode?
36
+ return unless server_mode?
37
+
38
+ detach ? detach_server : run_server
37
39
  end
38
40
 
39
41
  private
40
42
 
41
- def demonize
42
- Cache.write_port_and_token_files(port: @server.addr[1], token: token)
43
+ def detach_server
44
+ write_port_and_token_files
43
45
 
44
46
  pid = fork do
45
47
  Process.daemon(true)
46
48
  $stderr.reopen(Cache.stderr_path, 'w')
47
- Cache.write_pid_file do
48
- read_socket(@server.accept) until @server.closed?
49
- end
49
+ process_input
50
50
  end
51
51
 
52
52
  Process.waitpid(pid)
53
53
  end
54
54
 
55
+ def write_port_and_token_files
56
+ Cache.write_port_and_token_files(port: @server.addr[1], token: token)
57
+ end
58
+
59
+ def process_input
60
+ Cache.write_pid_file do
61
+ read_socket(@server.accept) until @server.closed?
62
+ end
63
+ end
64
+
65
+ def run_server
66
+ write_port_and_token_files
67
+ process_input
68
+ end
69
+
55
70
  def server_mode?
56
71
  true
57
72
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.43.0'
6
+ STRING = '1.45.1'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
data/lib/rubocop.rb CHANGED
@@ -166,6 +166,7 @@ require_relative 'rubocop/cop/bundler/ordered_gems'
166
166
 
167
167
  require_relative 'rubocop/cop/gemspec/dependency_version'
168
168
  require_relative 'rubocop/cop/gemspec/deprecated_attribute_assignment'
169
+ require_relative 'rubocop/cop/gemspec/development_dependencies'
169
170
  require_relative 'rubocop/cop/gemspec/duplicated_assignment'
170
171
  require_relative 'rubocop/cop/gemspec/ordered_dependencies'
171
172
  require_relative 'rubocop/cop/gemspec/require_mfa'
@@ -471,6 +472,7 @@ require_relative 'rubocop/cop/style/combinable_loops'
471
472
  require_relative 'rubocop/cop/style/command_literal'
472
473
  require_relative 'rubocop/cop/style/comment_annotation'
473
474
  require_relative 'rubocop/cop/style/commented_keyword'
475
+ require_relative 'rubocop/cop/style/comparable_clamp'
474
476
  require_relative 'rubocop/cop/style/concat_array_literals'
475
477
  require_relative 'rubocop/cop/style/conditional_assignment'
476
478
  require_relative 'rubocop/cop/style/constant_visibility'
@@ -532,6 +534,7 @@ require_relative 'rubocop/cop/style/in_pattern_then'
532
534
  require_relative 'rubocop/cop/style/infinite_loop'
533
535
  require_relative 'rubocop/cop/style/inverse_methods'
534
536
  require_relative 'rubocop/cop/style/inline_comment'
537
+ require_relative 'rubocop/cop/style/invertible_unless_condition'
535
538
  require_relative 'rubocop/cop/style/ip_addresses'
536
539
  require_relative 'rubocop/cop/style/keyword_parameters_order'
537
540
  require_relative 'rubocop/cop/style/lambda'
@@ -553,6 +556,7 @@ require_relative 'rubocop/cop/style/redundant_double_splat_hash_braces'
553
556
  require_relative 'rubocop/cop/style/redundant_each'
554
557
  require_relative 'rubocop/cop/style/redundant_fetch_block'
555
558
  require_relative 'rubocop/cop/style/redundant_file_extension_in_require'
559
+ require_relative 'rubocop/cop/style/redundant_heredoc_delimiter_quotes'
556
560
  require_relative 'rubocop/cop/style/redundant_initialize'
557
561
  require_relative 'rubocop/cop/style/redundant_self_assignment'
558
562
  require_relative 'rubocop/cop/style/redundant_self_assignment_branch'