rbhint 0.85.1.rc2 → 0.87.1.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -1
  3. data/bin/rubocop-profile +16 -0
  4. data/config/default.yml +118 -10
  5. data/lib/rbhint/version.rb +1 -1
  6. data/lib/rubocop.rb +15 -1
  7. data/lib/rubocop/cli.rb +0 -2
  8. data/lib/rubocop/cli/command/auto_genenerate_config.rb +40 -5
  9. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  10. data/lib/rubocop/cli/command/show_cops.rb +1 -1
  11. data/lib/rubocop/config_loader.rb +24 -66
  12. data/lib/rubocop/config_obsoletion.rb +0 -1
  13. data/lib/rubocop/cop/autocorrect_logic.rb +14 -24
  14. data/lib/rubocop/cop/badge.rb +1 -1
  15. data/lib/rubocop/cop/base.rb +407 -0
  16. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +10 -20
  17. data/lib/rubocop/cop/commissioner.rb +48 -50
  18. data/lib/rubocop/cop/cop.rb +85 -236
  19. data/lib/rubocop/cop/corrector.rb +38 -115
  20. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +26 -0
  21. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +6 -1
  22. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  23. data/lib/rubocop/cop/generator.rb +1 -1
  24. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +11 -14
  25. data/lib/rubocop/cop/layout/case_indentation.rb +18 -19
  26. data/lib/rubocop/cop/layout/class_structure.rb +2 -37
  27. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  28. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -8
  29. data/lib/rubocop/cop/layout/end_alignment.rb +3 -2
  30. data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -0
  31. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -2
  32. data/lib/rubocop/cop/layout/multiline_block_layout.rb +17 -7
  33. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +22 -27
  34. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +27 -68
  35. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +3 -2
  36. data/lib/rubocop/cop/legacy/corrections_proxy.rb +49 -0
  37. data/lib/rubocop/cop/legacy/corrector.rb +29 -0
  38. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -4
  39. data/lib/rubocop/cop/lint/duplicate_elsif_condition.rb +39 -0
  40. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  41. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +3 -2
  42. data/lib/rubocop/cop/lint/interpolation_check.rb +13 -0
  43. data/lib/rubocop/cop/lint/literal_as_condition.rb +11 -1
  44. data/lib/rubocop/cop/lint/nested_method_definition.rb +14 -20
  45. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
  46. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -3
  47. data/lib/rubocop/cop/lint/raise_exception.rb +8 -0
  48. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  49. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -23
  50. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +2 -2
  51. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  52. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +8 -0
  53. data/lib/rubocop/cop/lint/syntax.rb +11 -26
  54. data/lib/rubocop/cop/lint/unused_method_argument.rb +1 -1
  55. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  56. data/lib/rubocop/cop/metrics/block_length.rb +24 -2
  57. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  58. data/lib/rubocop/cop/metrics/class_length.rb +26 -3
  59. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  60. data/lib/rubocop/cop/metrics/method_length.rb +24 -1
  61. data/lib/rubocop/cop/metrics/module_length.rb +26 -3
  62. data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
  63. data/lib/rubocop/cop/metrics/perceived_complexity.rb +3 -3
  64. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +129 -0
  65. data/lib/rubocop/cop/mixin/allowed_methods.rb +19 -0
  66. data/lib/rubocop/cop/mixin/auto_corrector.rb +12 -0
  67. data/lib/rubocop/cop/mixin/code_length.rb +4 -0
  68. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
  69. data/lib/rubocop/cop/mixin/enforce_superclass.rb +3 -1
  70. data/lib/rubocop/cop/mixin/nil_methods.rb +3 -5
  71. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +6 -1
  72. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -3
  73. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -2
  74. data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -13
  75. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +4 -2
  76. data/lib/rubocop/cop/mixin/visibility_help.rb +50 -0
  77. data/lib/rubocop/cop/naming/ascii_identifiers.rb +27 -4
  78. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +2 -2
  79. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  80. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  81. data/lib/rubocop/cop/naming/predicate_name.rb +3 -5
  82. data/lib/rubocop/cop/naming/variable_name.rb +1 -1
  83. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  84. data/lib/rubocop/cop/offense.rb +16 -2
  85. data/lib/rubocop/cop/style/accessor_grouping.rb +147 -0
  86. data/lib/rubocop/cop/style/array_coercion.rb +63 -0
  87. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +3 -2
  88. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +146 -0
  89. data/lib/rubocop/cop/style/case_like_if.rb +217 -0
  90. data/lib/rubocop/cop/style/class_vars.rb +21 -0
  91. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  92. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  93. data/lib/rubocop/cop/style/date_time.rb +1 -1
  94. data/lib/rubocop/cop/style/dir.rb +2 -2
  95. data/lib/rubocop/cop/style/empty_literal.rb +5 -5
  96. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -2
  97. data/lib/rubocop/cop/style/exponential_notation.rb +6 -8
  98. data/lib/rubocop/cop/style/float_division.rb +7 -10
  99. data/lib/rubocop/cop/style/format_string_token.rb +5 -5
  100. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +62 -0
  101. data/lib/rubocop/cop/style/hash_like_case.rb +76 -0
  102. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -11
  103. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -0
  104. data/lib/rubocop/cop/style/missing_else.rb +1 -11
  105. data/lib/rubocop/cop/style/multiline_block_chain.rb +10 -1
  106. data/lib/rubocop/cop/style/mutable_constant.rb +4 -4
  107. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -5
  108. data/lib/rubocop/cop/style/numeric_predicate.rb +3 -4
  109. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -3
  110. data/lib/rubocop/cop/style/proc.rb +1 -1
  111. data/lib/rubocop/cop/style/random_with_offset.rb +4 -10
  112. data/lib/rubocop/cop/style/redundant_assignment.rb +117 -0
  113. data/lib/rubocop/cop/style/redundant_exception.rb +14 -10
  114. data/lib/rubocop/cop/style/redundant_fetch_block.rb +122 -0
  115. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +50 -0
  116. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  117. data/lib/rubocop/cop/style/redundant_parentheses.rb +7 -1
  118. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -1
  119. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -2
  120. data/lib/rubocop/cop/style/redundant_sort.rb +3 -2
  121. data/lib/rubocop/cop/style/rescue_standard_error.rb +1 -1
  122. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  123. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +3 -2
  124. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  125. data/lib/rubocop/cop/style/struct_inheritance.rb +2 -2
  126. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  127. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +9 -32
  128. data/lib/rubocop/cop/style/trivial_accessors.rb +8 -7
  129. data/lib/rubocop/cop/style/yoda_condition.rb +18 -1
  130. data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -2
  131. data/lib/rubocop/cop/team.rb +97 -81
  132. data/lib/rubocop/cop/utils/format_string.rb +1 -2
  133. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  134. data/lib/rubocop/file_finder.rb +4 -4
  135. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  136. data/lib/rubocop/name_similarity.rb +1 -3
  137. data/lib/rubocop/options.rb +15 -8
  138. data/lib/rubocop/path_util.rb +2 -17
  139. data/lib/rubocop/rake_task.rb +6 -9
  140. data/lib/rubocop/result_cache.rb +9 -5
  141. data/lib/rubocop/rspec/cop_helper.rb +4 -4
  142. data/lib/rubocop/rspec/expect_offense.rb +52 -22
  143. data/lib/rubocop/rspec/shared_contexts.rb +8 -8
  144. data/lib/rubocop/runner.rb +33 -32
  145. data/lib/rubocop/target_ruby.rb +1 -1
  146. data/lib/rubocop/version.rb +1 -1
  147. metadata +25 -8
  148. data/lib/rubocop/cop/mixin/classish_length.rb +0 -37
@@ -41,8 +41,7 @@ module RuboCop
41
41
  #
42
42
  # @see https://ruby-doc.org/core-2.6.3/Kernel.html#method-i-format
43
43
  class FormatSequence
44
- attr_reader :begin_pos, :end_pos
45
- attr_reader :flags, :width, :precision, :name, :type
44
+ attr_reader :begin_pos, :end_pos, :flags, :width, :precision, :name, :type
46
45
 
47
46
  def initialize(match)
48
47
  @source = match[0]
@@ -42,10 +42,10 @@ module RuboCop
42
42
  def reference!(node)
43
43
  reference = Reference.new(node, @scope)
44
44
  @references << reference
45
- consumed_branches = Set.new
45
+ consumed_branches = nil
46
46
 
47
47
  @assignments.reverse_each do |assignment|
48
- next if consumed_branches.include?(assignment.branch)
48
+ next if consumed_branches&.include?(assignment.branch)
49
49
 
50
50
  assignment.reference!(node) unless assignment.run_exclusively_with?(reference)
51
51
 
@@ -58,7 +58,9 @@ module RuboCop
58
58
 
59
59
  break if !assignment.branch || assignment.branch == reference.branch
60
60
 
61
- consumed_branches << assignment.branch unless assignment.branch.may_run_incompletely?
61
+ unless assignment.branch.may_run_incompletely?
62
+ (consumed_branches ||= Set.new) << assignment.branch
63
+ end
62
64
  end
63
65
  end
64
66
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
@@ -20,12 +20,12 @@ module RuboCop
20
20
  end
21
21
  end
22
22
 
23
- def find_files_upwards(filename, start_dir)
24
- files = []
23
+ def find_last_file_upwards(filename, start_dir)
24
+ last_file = nil
25
25
  traverse_files_upwards(filename, start_dir) do |file|
26
- files << file
26
+ last_file = file
27
27
  end
28
- files
28
+ last_file
29
29
  end
30
30
 
31
31
  private
@@ -115,7 +115,7 @@ module RuboCop
115
115
  output_buffer.puts "# Offense count: #{offense_count}" if @show_offense_counts
116
116
 
117
117
  cop_class = Cop::Cop.registry.find_by_cop_name(cop_name)
118
- output_buffer.puts '# Cop supports --auto-correct.' if cop_class&.new&.support_autocorrect?
118
+ output_buffer.puts '# Cop supports --auto-correct.' if cop_class&.support_autocorrect?
119
119
 
120
120
  default_cfg = default_config(cop_name)
121
121
  return unless default_cfg
@@ -22,9 +22,7 @@ module RuboCop
22
22
  names.delete(target_name)
23
23
 
24
24
  spell_checker = DidYouMean::SpellChecker.new(dictionary: names)
25
- similar_names = spell_checker.correct(target_name)
26
-
27
- similar_names
25
+ spell_checker.correct(target_name)
28
26
  end
29
27
  end
30
28
  end
@@ -163,7 +163,7 @@ module RuboCop
163
163
  end
164
164
  end
165
165
 
166
- # rubocop:disable Metrics/MethodLength
166
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
167
167
  def add_boolean_flags(opts)
168
168
  option(opts, '-F', '--fail-fast')
169
169
  option(opts, '-C', '--cache FLAG')
@@ -171,7 +171,16 @@ module RuboCop
171
171
  option(opts, '-D', '--[no-]display-cop-names')
172
172
  option(opts, '-E', '--extra-details')
173
173
  option(opts, '-S', '--display-style-guide')
174
- option(opts, '-a', '--auto-correct')
174
+ option(opts, '-a', '--auto-correct') do
175
+ @options[:safe_auto_correct] = true
176
+ end
177
+ option(opts, '--safe-auto-correct') do
178
+ warn '--safe-auto-correct is deprecated; use --auto-correct'
179
+ @options[:safe_auto_correct] = @options[:auto_correct] = true
180
+ end
181
+ option(opts, '-A', '--auto-correct-all') do
182
+ @options[:auto_correct] = true
183
+ end
175
184
  option(opts, '--disable-pending-cops')
176
185
  option(opts, '--enable-pending-cops')
177
186
  option(opts, '--ignore-disable-comments')
@@ -184,7 +193,7 @@ module RuboCop
184
193
  option(opts, '-V', '--verbose-version')
185
194
  option(opts, '-P', '--parallel')
186
195
  end
187
- # rubocop:enable Metrics/MethodLength
196
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
188
197
 
189
198
  def add_aliases(opts)
190
199
  option(opts, '-l', '--lint') do
@@ -196,9 +205,6 @@ module RuboCop
196
205
  @options[:only] << 'Layout'
197
206
  @options[:auto_correct] = true
198
207
  end
199
- option(opts, '--safe-auto-correct') do
200
- @options[:auto_correct] = true
201
- end
202
208
  end
203
209
 
204
210
  def add_list_options(opts)
@@ -465,8 +471,9 @@ module RuboCop
465
471
  lint: 'Run only lint cops.',
466
472
  safe: 'Run only safe cops.',
467
473
  list_target_files: 'List all files RuboCop will inspect.',
468
- auto_correct: 'Auto-correct offenses.',
469
- safe_auto_correct: 'Run auto-correct only when it\'s safe.',
474
+ auto_correct: 'Auto-correct offenses (only when it\'s safe).',
475
+ safe_auto_correct: '(same, deprecated)',
476
+ auto_correct_all: 'Auto-correct offenses (safe and unsafe)',
470
477
  fix_layout: 'Run only layout cops, with auto-correct on.',
471
478
  color: 'Force color output on or off.',
472
479
  version: 'Display version.',
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module PathUtil
6
6
  module_function
7
7
 
8
- def relative_path(path, base_dir = PathUtil.pwd)
8
+ def relative_path(path, base_dir = Dir.pwd)
9
9
  # Optimization for the common case where path begins with the base
10
10
  # dir. Just cut off the first part.
11
11
  if path.start_with?(base_dir)
@@ -24,7 +24,7 @@ module RuboCop
24
24
 
25
25
  def smart_path(path)
26
26
  # Ideally, we calculate this relative to the project root.
27
- base_dir = PathUtil.pwd
27
+ base_dir = Dir.pwd
28
28
 
29
29
  if path.start_with? base_dir
30
30
  relative_path(path, base_dir)
@@ -54,21 +54,6 @@ module RuboCop
54
54
  %r{\A([A-Z]:)?/}i.match?(path)
55
55
  end
56
56
 
57
- def self.pwd
58
- @pwd ||= Dir.pwd
59
- end
60
-
61
- def self.reset_pwd
62
- @pwd = nil
63
- end
64
-
65
- def self.chdir(dir, &block)
66
- reset_pwd
67
- Dir.chdir(dir, &block)
68
- ensure
69
- reset_pwd
70
- end
71
-
72
57
  def hidden_file_in_not_hidden_dir?(pattern, path)
73
58
  File.fnmatch?(
74
59
  pattern, path,
@@ -8,14 +8,11 @@ module RuboCop
8
8
  #
9
9
  # require 'rubocop/rake_task'
10
10
  # RuboCop::RakeTask.new
11
- class RakeTask < Rake::TaskLib
12
- attr_accessor :name
13
- attr_accessor :verbose
14
- attr_accessor :fail_on_error
15
- attr_accessor :patterns
16
- attr_accessor :formatters
17
- attr_accessor :requires
18
- attr_accessor :options
11
+ #
12
+ # Use global Rake namespace here to avoid namespace issues with custom
13
+ # rubocop-rake tasks
14
+ class RakeTask < ::Rake::TaskLib
15
+ attr_accessor :name, :verbose, :fail_on_error, :patterns, :formatters, :requires, :options
19
16
 
20
17
  def initialize(name = :rubocop, *args, &task_block)
21
18
  setup_ivars(name)
@@ -69,7 +66,7 @@ module RuboCop
69
66
  task(:auto_correct, *args) do |_, task_args|
70
67
  RakeFileUtils.verbose(verbose) do
71
68
  yield(*[self, task_args].slice(0, task_block.arity)) if block_given?
72
- options = full_options.unshift('--auto-correct')
69
+ options = full_options.unshift('--auto-correct-all')
73
70
  options.delete('--parallel')
74
71
  run_cli(verbose, options)
75
72
  end
@@ -158,6 +158,7 @@ module RuboCop
158
158
  end
159
159
 
160
160
  # The checksum of the rubocop program running the inspection.
161
+ # rubocop:disable Metrics/AbcSize
161
162
  def rubocop_checksum
162
163
  ResultCache.source_checksum ||=
163
164
  begin
@@ -168,13 +169,16 @@ module RuboCop
168
169
  # exe directory. A change to any of them could affect the cop output
169
170
  # so we include them in the cache hash.
170
171
  source_files = $LOADED_FEATURES + Find.find(exe_root).to_a
171
- sources = source_files
172
- .select { |path| File.file?(path) }
173
- .sort
174
- .map { |path| IO.read(path, encoding: Encoding::UTF_8) }
175
- Digest::SHA1.hexdigest(sources.join)
172
+
173
+ digest = Digest::SHA1.new
174
+ source_files
175
+ .select { |path| File.file?(path) }
176
+ .sort!
177
+ .each { |path| digest << File.mtime(path).to_s }
178
+ digest.hexdigest
176
179
  end
177
180
  end
181
+ # rubocop:enable Metrics/AbcSize
178
182
 
179
183
  # Return a hash of the options given at invocation, minus the ones that have
180
184
  # no effect on which offenses and disabled line ranges are found, and thus
@@ -43,14 +43,14 @@ module CopHelper
43
43
  processed_source = parse_source(source, file)
44
44
  _investigate(cop, processed_source)
45
45
 
46
- corrector =
47
- RuboCop::Cop::Corrector.new(processed_source.buffer, cop.corrections)
48
- corrector.rewrite
46
+ @last_corrector.rewrite
49
47
  end
50
48
 
51
49
  def _investigate(cop, processed_source)
52
50
  team = RuboCop::Cop::Team.new([cop], nil, raise_error: true)
53
- team.inspect_file(processed_source)
51
+ report = team.investigate(processed_source)
52
+ @last_corrector = report.correctors.first || RuboCop::Cop::Corrector.new(processed_source)
53
+ report.offenses
54
54
  end
55
55
  end
56
56
 
@@ -73,25 +73,37 @@ module RuboCop
73
73
  # expect_no_corrections
74
74
  #
75
75
  # If your code has variables of different lengths, you can use `%{foo}`,
76
- # `^{foo}`, and `_{foo}` to format your template:
76
+ # `^{foo}`, and `_{foo}` to format your template; you can also abbreviate
77
+ # offense messages with `[...]`:
77
78
  #
78
79
  # %w[raise fail].each do |keyword|
79
80
  # expect_offense(<<~RUBY, keyword: keyword)
80
81
  # %{keyword}(RuntimeError, msg)
81
- # ^{keyword}^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
82
+ # ^{keyword}^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument [...]
82
83
  # RUBY
83
84
  #
84
85
  # %w[has_one has_many].each do |type|
85
86
  # expect_offense(<<~RUBY, type: type)
86
87
  # class Book
87
88
  # %{type} :chapter, foreign_key: 'book_id'
88
- # _{type} ^^^^^^^^^^^^^^^^^^^^^^ Specifying the default value is redundant.
89
+ # _{type} ^^^^^^^^^^^^^^^^^^^^^^ Specifying the default [...]
89
90
  # end
90
91
  # RUBY
91
92
  # end
93
+ #
94
+ # If you need to specify an offense on a blank line, use the empty `^{}` marker:
95
+ #
96
+ # @example `^{}` empty line offense
97
+ #
98
+ # expect_offense(<<~RUBY)
99
+ #
100
+ # ^{} Missing frozen string literal comment.
101
+ # puts 1
102
+ # RUBY
92
103
  module ExpectOffense
93
104
  def format_offense(source, **replacements)
94
105
  replacements.each do |keyword, value|
106
+ value = value.to_s
95
107
  source = source.gsub("%{#{keyword}}", value)
96
108
  .gsub("^{#{keyword}}", '^' * value.size)
97
109
  .gsub("_{#{keyword}}", ' ' * value.size)
@@ -100,7 +112,7 @@ module RuboCop
100
112
  end
101
113
 
102
114
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
103
- def expect_offense(source, file = nil, **replacements)
115
+ def expect_offense(source, file = nil, severity: nil, **replacements)
104
116
  source = format_offense(source, **replacements)
105
117
  RuboCop::Formatter::DisabledConfigFormatter
106
118
  .config_to_allow_offenses = {}
@@ -118,11 +130,12 @@ module RuboCop
118
130
 
119
131
  raise 'Error parsing example code' unless @processed_source.valid_syntax?
120
132
 
121
- _investigate(cop, @processed_source)
133
+ offenses = _investigate(cop, @processed_source)
122
134
  actual_annotations =
123
- expected_annotations.with_offense_annotations(cop.offenses)
135
+ expected_annotations.with_offense_annotations(offenses)
124
136
 
125
- expect(actual_annotations.to_s).to eq(expected_annotations.to_s)
137
+ expect(actual_annotations).to eq(expected_annotations)
138
+ expect(offenses.map(&:severity).uniq).to eq([severity]) if severity
126
139
  end
127
140
 
128
141
  def expect_correction(correction, loop: true)
@@ -132,12 +145,10 @@ module RuboCop
132
145
  new_source = loop do
133
146
  iteration += 1
134
147
 
135
- corrector =
136
- RuboCop::Cop::Corrector.new(@processed_source.buffer, cop.corrections)
137
- corrected_source = corrector.rewrite
148
+ corrected_source = @last_corrector.rewrite
138
149
 
139
150
  break corrected_source unless loop
140
- break corrected_source if cop.corrections.empty?
151
+ break corrected_source if @last_corrector.empty?
141
152
  break corrected_source if corrected_source == @processed_source.buffer.source
142
153
 
143
154
  if iteration > RuboCop::Runner::MAX_ITERATIONS
@@ -145,9 +156,6 @@ module RuboCop
145
156
  end
146
157
 
147
158
  # Prepare for next loop
148
- cop.instance_variable_set(:@corrections, [])
149
- # Cache invalidation. This is bad!
150
- cop.instance_variable_set(:@token_table, nil)
151
159
  @processed_source = parse_source(corrected_source,
152
160
  @processed_source.path)
153
161
  _investigate(cop, @processed_source)
@@ -160,30 +168,29 @@ module RuboCop
160
168
  def expect_no_corrections
161
169
  raise '`expect_no_corrections` must follow `expect_offense`' unless @processed_source
162
170
 
163
- return if cop.corrections.empty?
171
+ return if @last_corrector.empty?
164
172
 
165
173
  # In order to print a nice diff, e.g. what source got corrected to,
166
174
  # we need to run the actual corrections
167
175
 
168
- corrector =
169
- RuboCop::Cop::Corrector.new(@processed_source.buffer, cop.corrections)
170
- new_source = corrector.rewrite
176
+ new_source = @last_corrector.rewrite
171
177
 
172
178
  expect(new_source).to eq(@processed_source.buffer.source)
173
179
  end
174
180
 
175
181
  def expect_no_offenses(source, file = nil)
176
- inspect_source(source, file)
182
+ offenses = inspect_source(source, file)
177
183
 
178
184
  expected_annotations = AnnotatedSource.parse(source)
179
185
  actual_annotations =
180
- expected_annotations.with_offense_annotations(cop.offenses)
186
+ expected_annotations.with_offense_annotations(offenses)
181
187
  expect(actual_annotations.to_s).to eq(source)
182
188
  end
183
189
 
184
190
  # Parsed representation of code annotated with the `^^^ Message` style
185
191
  class AnnotatedSource
186
- ANNOTATION_PATTERN = /\A\s*\^+ /.freeze
192
+ ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) /.freeze
193
+ ABBREV = "[...]\n"
187
194
 
188
195
  # @param annotated_source [String] string passed to the matchers
189
196
  #
@@ -217,6 +224,27 @@ module RuboCop
217
224
  @annotations = annotations.sort.freeze
218
225
  end
219
226
 
227
+ def ==(other)
228
+ other.is_a?(self.class) &&
229
+ other.lines == lines &&
230
+ match_annotations?(other)
231
+ end
232
+
233
+ # Dirty hack: expectations with [...] are rewritten when they match
234
+ # This way the diff is clean.
235
+ def match_annotations?(other)
236
+ annotations.zip(other.annotations) do |(_actual_line, actual_annotation),
237
+ (_expected_line, expected_annotation)|
238
+ if expected_annotation.end_with?(ABBREV)
239
+ if actual_annotation.start_with?(expected_annotation[0...-ABBREV.length])
240
+ expected_annotation.replace(actual_annotation)
241
+ end
242
+ end
243
+ end
244
+
245
+ annotations == other.annotations
246
+ end
247
+
220
248
  # Construct annotated source string (like what we parse)
221
249
  #
222
250
  # Reconstruct a deterministic annotated source string. This is
@@ -249,6 +277,7 @@ module RuboCop
249
277
 
250
278
  reconstructed.join
251
279
  end
280
+ alias inspect to_s
252
281
 
253
282
  # Return the plain source code without annotations
254
283
  #
@@ -267,6 +296,7 @@ module RuboCop
267
296
  offenses.map do |offense|
268
297
  indent = ' ' * offense.column
269
298
  carets = '^' * offense.column_length
299
+ carets = '^{}' if offense.column_length.zero?
270
300
 
271
301
  [offense.line, "#{indent}#{carets} #{offense.message}\n"]
272
302
  end
@@ -274,7 +304,7 @@ module RuboCop
274
304
  self.class.new(lines, offense_annotations)
275
305
  end
276
306
 
277
- private
307
+ protected
278
308
 
279
309
  attr_reader :lines, :annotations
280
310
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'tmpdir'
4
- require 'fileutils'
5
4
 
6
5
  RSpec.shared_context 'isolated environment', :isolated_environment do
7
6
  around do |example|
@@ -25,7 +24,7 @@ RSpec.shared_context 'isolated environment', :isolated_environment do
25
24
  working_dir = File.join(tmpdir, 'work')
26
25
  Dir.mkdir(working_dir)
27
26
 
28
- RuboCop::PathUtil.chdir(working_dir) do
27
+ Dir.chdir(working_dir) do
29
28
  example.run
30
29
  end
31
30
  ensure
@@ -45,11 +44,11 @@ RSpec.shared_context 'config', :config do # rubocop:disable Metrics/BlockLength
45
44
  let(:source) { 'code = {some: :ruby}' }
46
45
 
47
46
  let(:cop_class) do
48
- if described_class.is_a?(Class) && described_class < RuboCop::Cop::Cop
49
- described_class
50
- else
51
- RuboCop::Cop::Cop
47
+ unless described_class.is_a?(Class) && described_class < RuboCop::Cop::Base
48
+ raise 'Specify which cop class to use (e.g `let(:cop_class) { RuboCop::Cop::Base }`, ' \
49
+ 'or RuboCop::Cop::Cop for legacy)'
52
50
  end
51
+ described_class
53
52
  end
54
53
 
55
54
  let(:cop_config) { {} }
@@ -95,8 +94,9 @@ RSpec.shared_context 'config', :config do # rubocop:disable Metrics/BlockLength
95
94
  end
96
95
 
97
96
  let(:cop) do
98
- cop_class.new(config, cop_options)
99
- .tap { |cop| cop.processed_source = processed_source }
97
+ cop_class.new(config, cop_options).tap do |cop|
98
+ cop.send :begin_investigation, processed_source
99
+ end
100
100
  end
101
101
  end
102
102