rubocop-minitest 0.7.0 → 0.10.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +0 -3
  3. data/.rubocop.yml +2 -1
  4. data/.rubocop_todo.yml +0 -7
  5. data/CHANGELOG.md +58 -0
  6. data/Gemfile +1 -1
  7. data/README.md +2 -2
  8. data/Rakefile +29 -0
  9. data/config/default.yml +96 -16
  10. data/docs/antora.yml +7 -0
  11. data/docs/modules/ROOT/nav.adoc +6 -0
  12. data/docs/modules/ROOT/pages/cops.adoc +37 -0
  13. data/docs/modules/ROOT/pages/cops_minitest.adoc +1014 -0
  14. data/docs/modules/ROOT/pages/index.adoc +5 -0
  15. data/docs/modules/ROOT/pages/installation.adoc +15 -0
  16. data/docs/modules/ROOT/pages/usage.adoc +32 -0
  17. data/{manual → legacy-docs}/cops.md +0 -0
  18. data/{manual → legacy-docs}/cops_minitest.md +7 -5
  19. data/{manual → legacy-docs}/index.md +0 -0
  20. data/{manual → legacy-docs}/installation.md +0 -0
  21. data/{manual → legacy-docs}/usage.md +0 -0
  22. data/lib/rubocop/cop/generator.rb +56 -0
  23. data/lib/rubocop/cop/minitest/assert_empty_literal.rb +15 -0
  24. data/lib/rubocop/cop/minitest/assert_equal.rb +2 -31
  25. data/lib/rubocop/cop/minitest/assert_in_delta.rb +27 -0
  26. data/lib/rubocop/cop/minitest/assert_kind_of.rb +25 -0
  27. data/lib/rubocop/cop/minitest/assert_output.rb +49 -0
  28. data/lib/rubocop/cop/minitest/assert_path_exists.rb +58 -0
  29. data/lib/rubocop/cop/minitest/assert_silent.rb +45 -0
  30. data/lib/rubocop/cop/minitest/assertion_in_lifecycle_hook.rb +43 -0
  31. data/lib/rubocop/cop/minitest/global_expectations.rb +49 -28
  32. data/lib/rubocop/cop/minitest/literal_as_actual_argument.rb +52 -0
  33. data/lib/rubocop/cop/minitest/multiple_assertions.rb +63 -0
  34. data/lib/rubocop/cop/minitest/refute_in_delta.rb +27 -0
  35. data/lib/rubocop/cop/minitest/refute_kind_of.rb +25 -0
  36. data/lib/rubocop/cop/minitest/refute_path_exists.rb +58 -0
  37. data/lib/rubocop/cop/minitest/test_method_name.rb +70 -0
  38. data/lib/rubocop/cop/minitest/unspecified_exception.rb +36 -0
  39. data/lib/rubocop/cop/minitest_cops.rb +15 -0
  40. data/lib/rubocop/cop/mixin/argument_range_helper.rb +10 -0
  41. data/lib/rubocop/cop/mixin/in_delta_mixin.rb +50 -0
  42. data/lib/rubocop/cop/mixin/minitest_cop_rule.rb +1 -3
  43. data/lib/rubocop/cop/mixin/minitest_exploration_helpers.rb +84 -0
  44. data/lib/rubocop/minitest/version.rb +1 -1
  45. data/mkdocs.yml +2 -2
  46. data/relnotes/v0.10.0.md +21 -0
  47. data/relnotes/v0.10.1.md +5 -0
  48. data/relnotes/v0.8.0.md +12 -0
  49. data/relnotes/v0.8.1.md +5 -0
  50. data/relnotes/v0.9.0.md +10 -0
  51. data/rubocop-minitest.gemspec +4 -4
  52. data/tasks/cops_documentation.rake +83 -54
  53. data/tasks/cut_release.rake +16 -0
  54. metadata +40 -12
@@ -1,22 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'mixin/argument_range_helper'
4
+ require_relative 'mixin/in_delta_mixin'
4
5
  require_relative 'mixin/minitest_cop_rule'
6
+ require_relative 'mixin/minitest_exploration_helpers'
5
7
  require_relative 'minitest/assert_empty'
6
8
  require_relative 'minitest/assert_empty_literal'
7
9
  require_relative 'minitest/assert_equal'
10
+ require_relative 'minitest/assert_in_delta'
11
+ require_relative 'minitest/assertion_in_lifecycle_hook'
12
+ require_relative 'minitest/assert_kind_of'
8
13
  require_relative 'minitest/assert_nil'
9
14
  require_relative 'minitest/assert_includes'
10
15
  require_relative 'minitest/assert_instance_of'
11
16
  require_relative 'minitest/assert_match'
17
+ require_relative 'minitest/assert_output'
18
+ require_relative 'minitest/assert_path_exists'
12
19
  require_relative 'minitest/assert_respond_to'
20
+ require_relative 'minitest/assert_silent'
13
21
  require_relative 'minitest/assert_truthy'
14
22
  require_relative 'minitest/global_expectations'
23
+ require_relative 'minitest/literal_as_actual_argument'
24
+ require_relative 'minitest/multiple_assertions'
15
25
  require_relative 'minitest/refute_empty'
16
26
  require_relative 'minitest/refute_false'
17
27
  require_relative 'minitest/refute_equal'
28
+ require_relative 'minitest/refute_in_delta'
29
+ require_relative 'minitest/refute_kind_of'
18
30
  require_relative 'minitest/refute_nil'
19
31
  require_relative 'minitest/refute_includes'
20
32
  require_relative 'minitest/refute_match'
21
33
  require_relative 'minitest/refute_instance_of'
34
+ require_relative 'minitest/refute_path_exists'
22
35
  require_relative 'minitest/refute_respond_to'
36
+ require_relative 'minitest/test_method_name'
37
+ require_relative 'minitest/unspecified_exception'
@@ -26,6 +26,16 @@ module RuboCop
26
26
  second_argument.source_range.end_pos
27
27
  )
28
28
  end
29
+
30
+ def all_arguments_range(node)
31
+ first_argument = node.first_argument
32
+ last_argument = node.arguments.last
33
+
34
+ range_between(
35
+ first_argument.source_range.begin_pos,
36
+ last_argument.source_range.end_pos
37
+ )
38
+ end
29
39
  end
30
40
  end
31
41
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for `AssertInDelta` and `RefuteInDelta` cops.
6
+ module InDeltaMixin
7
+ MSG = 'Prefer using `%<good_method>s` over `%<bad_method>s`.'
8
+
9
+ def on_send(node)
10
+ equal_floats_call(node) do |expected, actual, message|
11
+ message = message.first
12
+
13
+ if expected.float_type? || actual.float_type?
14
+ message = format(MSG,
15
+ good_method: build_good_method(expected, actual, message),
16
+ bad_method: node.source)
17
+
18
+ add_offense(node, message: message)
19
+ end
20
+ end
21
+ end
22
+
23
+ def autocorrect(node)
24
+ equal_floats_call(node) do |expected, actual, message|
25
+ message = message.first
26
+ replacement = build_good_method(expected, actual, message)
27
+
28
+ lambda do |corrector|
29
+ corrector.replace(node, replacement)
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def build_good_method(expected, actual, message)
37
+ if message
38
+ "#{assertion_method}_in_delta(#{expected.source}, #{actual.source}, 0.001, #{message.source})"
39
+ else
40
+ "#{assertion_method}_in_delta(#{expected.source}, #{actual.source})"
41
+ end
42
+ end
43
+
44
+ def assertion_method
45
+ class_name = self.class.name.split('::').last
46
+ class_name[/\A[[:upper:]][[:lower:]]+/].downcase
47
+ end
48
+ end
49
+ end
50
+ end
@@ -22,9 +22,7 @@ module RuboCop
22
22
  # @param inverse [Boolean] An optional param. Order of arguments replaced by auto-correction.
23
23
  #
24
24
  def define_rule(assertion_method, target_method:, preferred_method: nil, inverse: false)
25
- if preferred_method.nil?
26
- preferred_method = "#{assertion_method}_#{target_method.to_s.delete('?')}"
27
- end
25
+ preferred_method = "#{assertion_method}_#{target_method.to_s.delete('?')}" if preferred_method.nil?
28
26
 
29
27
  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
30
28
  include ArgumentRangeHelper
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ # Helper methods for different explorations against test files and test cases.
8
+ module MinitestExplorationHelpers
9
+ extend NodePattern::Macros
10
+
11
+ ASSERTION_PREFIXES = %w[assert refute].freeze
12
+
13
+ LIFECYCLE_HOOK_METHODS = %i[
14
+ before_setup
15
+ setup
16
+ after_setup
17
+ before_teardown
18
+ teardown
19
+ after_teardown
20
+ ].to_set.freeze
21
+
22
+ private
23
+
24
+ def test_class?(class_node)
25
+ class_node.parent_class && class_node.identifier.source.end_with?('Test')
26
+ end
27
+
28
+ def test_case?(node)
29
+ return false unless node&.def_type? && test_case_name?(node.method_name)
30
+
31
+ class_ancestor = node.each_ancestor(:class).first
32
+ test_class?(class_ancestor)
33
+ end
34
+
35
+ def test_cases(class_node)
36
+ class_def_nodes(class_node)
37
+ .select { |def_node| test_case_name?(def_node.method_name) }
38
+ end
39
+
40
+ def lifecycle_hooks(class_node)
41
+ class_def_nodes(class_node)
42
+ .select { |def_node| lifecycle_hook_method?(def_node) }
43
+ end
44
+
45
+ def class_def_nodes(class_node)
46
+ class_def = class_node.body
47
+ return [] unless class_def
48
+
49
+ if class_def.def_type?
50
+ [class_def]
51
+ else
52
+ class_def.each_child_node(:def).to_a
53
+ end
54
+ end
55
+
56
+ def test_case_name?(name)
57
+ name.to_s.start_with?('test_')
58
+ end
59
+
60
+ def assertions(def_node)
61
+ method_def = def_node.body
62
+ return [] unless method_def
63
+
64
+ send_nodes =
65
+ if method_def.send_type?
66
+ [method_def]
67
+ else
68
+ method_def.each_child_node(:send)
69
+ end
70
+
71
+ send_nodes.select { |send_node| assertion?(send_node) }
72
+ end
73
+
74
+ def assertion?(node)
75
+ node.send_type? &&
76
+ ASSERTION_PREFIXES.any? { |prefix| node.method_name.to_s.start_with?(prefix) }
77
+ end
78
+
79
+ def lifecycle_hook_method?(node)
80
+ node.def_type? && LIFECYCLE_HOOK_METHODS.include?(node.method_name)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Minitest
5
- VERSION = '0.7.0'
5
+ VERSION = '0.10.1'
6
6
  end
7
7
  end
data/mkdocs.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  site_name: "A RuboCop extension focused on enforcing Minitest best practices and coding conventions."
2
2
  repo_url: https://github.com/rubocop-hq/rubocop-minitest
3
- edit_uri: edit/master/manual/
3
+ edit_uri: edit/master/legacy-docs/
4
4
  copyright: "Copyright &copy; 2019 Bozhidar Batsov, Jonas Arvidsson, Koichi ITO, and RuboCop contributors"
5
- docs_dir: manual
5
+ docs_dir: legacy-docs
6
6
  pages:
7
7
  - Home: index.md
8
8
  - Installation: installation.md
@@ -0,0 +1,21 @@
1
+ ### New features
2
+
3
+ * [#92](https://github.com/rubocop-hq/rubocop-minitest/pull/92): Add new `Minitest/LiteralAsActualArgument` cop. ([@fatkodima][], [@tsmmark][])
4
+ * [#95](https://github.com/rubocop-hq/rubocop-minitest/pull/95): Add new `Minitest/AssertionInLifecycleHook` cop. ([@fatkodima][])
5
+ * [#91](https://github.com/rubocop-hq/rubocop-minitest/pull/91): Add new `Minitest/AssertInDelta` and `Minitest/RefuteInDelta` cops. ([@fatkodima][])
6
+ * [#89](https://github.com/rubocop-hq/rubocop-minitest/pull/89): Add new `Minitest/TestMethodName` cop. ([@fatkodima][])
7
+ * [#83](https://github.com/rubocop-hq/rubocop-minitest/pull/83): New cops `AssertPathExists` and `RefutePathExists` check for use of `assert_path_exists`/`refute_path_exists` instead of `assert(File.exist?(path))`/`refute(File.exist?(path))`. ([@fatkodima][])
8
+ * [#88](https://github.com/rubocop-hq/rubocop-minitest/pull/88): Add new `Minitest/MultipleAssertions` cop. ([@fatkodima][])
9
+ * [#87](https://github.com/rubocop-hq/rubocop-minitest/pull/87): Add new `Minitest/AssertSilent` cop. ([@fatkodima][])
10
+ * [#96](https://github.com/rubocop-hq/rubocop-minitest/pull/96): Add new `Minitest/UnspecifiedException` cop. ([@fatkodima][])
11
+ * [#98](https://github.com/rubocop-hq/rubocop-minitest/pull/98): Add new `Minitest/AssertOutput` cop. ([@fatkodima][])
12
+ * [#84](https://github.com/rubocop-hq/rubocop-minitest/pull/84): New cops `AssertKindOf` and `RefuteKindOf` check for use of `assert_kind_of`/`refute_kind_of` instead of `assert(foo.kind_of?(Class))`/`refute(foo.kind_of?(Class))`. ([@fatkodima][])
13
+ * [#85](https://github.com/rubocop-hq/rubocop-minitest/pull/85): Add autocorrect to `Rails/AssertEmptyLiteral` cop. ([@fatkodima][])
14
+
15
+ ### Changes
16
+
17
+ * [#104](https://github.com/rubocop-hq/rubocop-minitest/pull/104): Require RuboCop 0.87 or higher. ([@koic][])
18
+
19
+ [@fatkodima]: https://github.com/fatkodima
20
+ [@tsmmark]: https://github.com/tsmmark
21
+ [@koic]: https://github.com/koic
@@ -0,0 +1,5 @@
1
+ ### Bug fixes
2
+
3
+ * [#106](https://github.com/rubocop-hq/rubocop-minitest/issues/106): Fix an error for `Minitest/AssertOutput` when using gvar at top level. ([@koic][])
4
+
5
+ [@koic]: https://github.com/koic
@@ -0,0 +1,12 @@
1
+ ### New features
2
+
3
+ * [#66](https://github.com/rubocop-hq/rubocop-minitest/issues/66): Support all expectations of `Minitest::Expectations` for `Minitest/GlobalExpectations` cop. ([@koic][])
4
+
5
+ ### Bug fixes
6
+
7
+ * [#60](https://github.com/rubocop-hq/rubocop-minitest/issues/60): Fix `Minitest/GlobalExpectations` autocorrection for chained methods. ([@tejasbubane][])
8
+ * [#69](https://github.com/rubocop-hq/rubocop-minitest/pull/69): Fix a false negative for `Minitest/GlobalExpectations` cop when using a variable or a hash index for receiver. ([@koic][])
9
+ * [#71](https://github.com/rubocop-hq/rubocop-minitest/pull/71): Fix a false negative for `Minitest/AssertEqual` when an argument is enclosed in redundant parentheses. ([@koic][])
10
+
11
+ [@koic]: https://github.com/koic
12
+ [@tejasbubane]: https://github.com/tejasbubane
@@ -0,0 +1,5 @@
1
+ ### Bug fixes
2
+
3
+ * [#72](https://github.com/rubocop-hq/rubocop-minitest/pull/72): Fix some false negatives for `Minitest/GlobalExpectations`. ([@andrykonchin][])
4
+
5
+ [@andrykonchin]: https://github.com/andrykonchin
@@ -0,0 +1,10 @@
1
+ ### Bug fixes
2
+
3
+ * [#75](https://github.com/rubocop-hq/rubocop-minitest/issues/75): Fix a false negative for `Minitest/GlobalExpectations` when using global expectation methods with no arguments. ([@koic][])
4
+
5
+ ### Changes
6
+
7
+ * [#73](https://github.com/rubocop-hq/rubocop-minitest/issues/73): The Minitest department works on file names end with `_test.rb` by default. ([@koic][])
8
+ * [#77](https://github.com/rubocop-hq/rubocop-minitest/pull/77): **(BREAKING)** Drop support for Ruby 2.3. ([@koic][])
9
+
10
+ [@koic]: https://github.com/koic
@@ -16,12 +16,12 @@ Gem::Specification.new do |spec|
16
16
  DESCRIPTION
17
17
  spec.license = 'MIT'
18
18
 
19
- spec.required_ruby_version = '>= 2.3.0'
19
+ spec.required_ruby_version = '>= 2.4.0'
20
20
  spec.metadata = {
21
- 'homepage_uri' => 'https://docs.rubocop.org/projects/minitest/',
21
+ 'homepage_uri' => 'https://docs.rubocop.org/rubocop-minitest/',
22
22
  'changelog_uri' => 'https://github.com/rubocop-hq/rubocop-minitest/blob/master/CHANGELOG.md',
23
23
  'source_code_uri' => 'https://github.com/rubocop-hq/rubocop-minitest',
24
- 'documentation_uri' => 'https://docs.rubocop.org/projects/minitest/',
24
+ 'documentation_uri' => 'https://docs.rubocop.org/rubocop-minitest/',
25
25
  'bug_tracker_uri' => 'https://github.com/rubocop-hq/rubocop-minitest/issues'
26
26
  }
27
27
 
@@ -34,6 +34,6 @@ Gem::Specification.new do |spec|
34
34
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
35
  spec.require_paths = ['lib']
36
36
 
37
- spec.add_runtime_dependency 'rubocop', '>= 0.74'
37
+ spec.add_runtime_dependency 'rubocop', '>= 0.87'
38
38
  spec.add_development_dependency 'minitest', '~> 5.11'
39
39
  end
@@ -17,7 +17,8 @@ task generate_cops_documentation: :yard_for_generate_documentation do
17
17
 
18
18
  def cops_body(config, cop, description, examples_objects, pars)
19
19
  content = h2(cop.cop_name)
20
- content << properties(config, cop)
20
+ content << required_ruby_version(cop)
21
+ content << properties(cop.new(config))
21
22
  content << "#{description}\n"
22
23
  content << examples(examples_objects) if examples_objects.count.positive?
23
24
  content << configurations(pars)
@@ -27,60 +28,66 @@ task generate_cops_documentation: :yard_for_generate_documentation do
27
28
 
28
29
  def examples(examples_object)
29
30
  examples_object.each_with_object(h3('Examples').dup) do |example, content|
31
+ content << "\n" unless content.end_with?("\n\n")
30
32
  content << h4(example.name) unless example.name == ''
31
33
  content << code_example(example)
32
34
  end
33
35
  end
34
36
 
37
+ def required_ruby_version(cop)
38
+ return '' unless cop.respond_to?(:required_minimum_ruby_version)
39
+
40
+ "NOTE: Required Ruby version: #{cop.required_minimum_ruby_version}\n\n"
41
+ end
42
+
35
43
  # rubocop:disable Metrics/MethodLength
36
- def properties(config, cop)
44
+ def properties(cop_instance)
37
45
  header = [
38
46
  'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
39
47
  'VersionChanged'
40
48
  ]
41
- config = config.for_cop(cop)
42
- safe_auto_correct = config.fetch('SafeAutoCorrect', true)
43
- autocorrect = if cop.new.support_autocorrect?
44
- "Yes #{'(Unsafe)' unless safe_auto_correct}"
49
+ autocorrect = if cop_instance.support_autocorrect?
50
+ "Yes#{' (Unsafe)' unless cop_instance.safe_autocorrect?}"
45
51
  else
46
52
  'No'
47
53
  end
54
+ cop_config = cop_instance.cop_config
48
55
  content = [[
49
- config.fetch('Enabled') ? 'Enabled' : 'Disabled',
50
- config.fetch('Safe', true) ? 'Yes' : 'No',
56
+ cop_status(cop_config.fetch('Enabled')),
57
+ cop_config.fetch('Safe', true) ? 'Yes' : 'No',
51
58
  autocorrect,
52
- config.fetch('VersionAdded', '-'),
53
- config.fetch('VersionChanged', '-')
59
+ cop_config.fetch('VersionAdded', '-'),
60
+ cop_config.fetch('VersionChanged', '-')
54
61
  ]]
55
- to_table(header, content) + "\n"
62
+ "#{to_table(header, content)}\n"
56
63
  end
57
64
  # rubocop:enable Metrics/MethodLength
58
65
 
59
66
  def h2(title)
60
67
  content = +"\n"
61
- content << "## #{title}\n"
68
+ content << "== #{title}\n"
62
69
  content << "\n"
63
70
  content
64
71
  end
65
72
 
66
73
  def h3(title)
67
74
  content = +"\n"
68
- content << "### #{title}\n"
75
+ content << "=== #{title}\n"
69
76
  content << "\n"
70
77
  content
71
78
  end
72
79
 
73
80
  def h4(title)
74
- content = +"#### #{title}\n"
81
+ content = +"==== #{title}\n"
75
82
  content << "\n"
76
83
  content
77
84
  end
78
85
 
79
86
  def code_example(ruby_code)
80
- content = +"```ruby\n"
81
- content << ruby_code.text
82
- .gsub('@good', '# good').gsub('@bad', '# bad').strip
83
- content << "\n```\n"
87
+ content = +"[source,ruby]\n----\n"
88
+ content << ruby_code.text.gsub('@good', '# good')
89
+ .gsub('@bad', '# bad').strip
90
+ content << "\n----\n"
84
91
  content
85
92
  end
86
93
 
@@ -88,7 +95,10 @@ task generate_cops_documentation: :yard_for_generate_documentation do
88
95
  return '' if pars.empty?
89
96
 
90
97
  header = ['Name', 'Default value', 'Configurable values']
91
- configs = pars.each_key.reject { |key| key.start_with?('Supported') }
98
+ configs = pars
99
+ .each_key
100
+ .reject { |key| key.start_with?('Supported') }
101
+ .reject { |key| key.start_with?('AllowMultipleStyles') }
92
102
  content = configs.map do |name|
93
103
  configurable = configurable_values(pars, name)
94
104
  default = format_table_value(pars[name])
@@ -106,8 +116,6 @@ task generate_cops_documentation: :yard_for_generate_documentation do
106
116
  format_table_value(pars[supported_style_name])
107
117
  when 'IndentationWidth'
108
118
  'Integer'
109
- when 'Database'
110
- format_table_value(pars['SupportedDatabases'])
111
119
  else
112
120
  case pars[name]
113
121
  when String
@@ -129,11 +137,14 @@ task generate_cops_documentation: :yard_for_generate_documentation do
129
137
 
130
138
  def to_table(header, content)
131
139
  table = [
132
- header.join(' | '),
133
- Array.new(header.size, '---').join(' | ')
134
- ]
135
- table.concat(content.map { |c| c.join(' | ') })
136
- table.join("\n") + "\n"
140
+ '|===',
141
+ "| #{header.join(' | ')}\n\n"
142
+ ].join("\n")
143
+ marked_contents = content.map do |plain_content|
144
+ plain_content.map { |c| "| #{c}" }.join("\n")
145
+ end
146
+ table << marked_contents.join("\n\n")
147
+ table << "\n|===\n"
137
148
  end
138
149
 
139
150
  def format_table_value(val)
@@ -146,11 +157,20 @@ task generate_cops_documentation: :yard_for_generate_documentation do
146
157
  val.map { |config| format_table_value(config) }.join(', ')
147
158
  end
148
159
  else
149
- "`#{val.nil? ? '<none>' : val}`"
160
+ wrap_backtick(val.nil? ? '<none>' : val)
150
161
  end
151
162
  value.gsub("#{Dir.pwd}/", '').rstrip
152
163
  end
153
164
 
165
+ def wrap_backtick(value)
166
+ if value.is_a?(String)
167
+ # Use `+` to prevent text like `**/*.gemspec` from being bold.
168
+ value.start_with?('*') ? "`+#{value}+`" : "`#{value}`"
169
+ else
170
+ "`#{value}`"
171
+ end
172
+ end
173
+
154
174
  def references(config, cop)
155
175
  cop_config = config.for_cop(cop)
156
176
  urls = RuboCop::Cop::MessageAnnotator.new(
@@ -159,7 +179,7 @@ task generate_cops_documentation: :yard_for_generate_documentation do
159
179
  return '' if urls.empty?
160
180
 
161
181
  content = h3('References')
162
- content << urls.map { |url| "* [#{url}](#{url})" }.join("\n")
182
+ content << urls.map { |url| "* #{url}" }.join("\n")
163
183
  content << "\n"
164
184
  content
165
185
  end
@@ -170,14 +190,15 @@ task generate_cops_documentation: :yard_for_generate_documentation do
170
190
  end
171
191
  return if selected_cops.empty?
172
192
 
173
- content = +"# #{department}\n"
193
+ selected_cops = cops_of_department(cops, department)
194
+ content = +"= #{department}\n"
174
195
  selected_cops.each do |cop|
175
196
  content << print_cop_with_doc(cop, config)
176
197
  end
177
- file_name = "#{Dir.pwd}/manual/cops_#{department.downcase}.md"
198
+ file_name = "#{Dir.pwd}/docs/modules/ROOT/pages/cops_#{department.downcase}.adoc"
178
199
  File.open(file_name, 'w') do |file|
179
200
  puts "* generated #{file_name}"
180
- file.write(content.strip + "\n")
201
+ file.write("#{content.strip}\n")
181
202
  end
182
203
  end
183
204
 
@@ -190,15 +211,21 @@ task generate_cops_documentation: :yard_for_generate_documentation do
190
211
  pars = t.reject { |k| non_display_keys.include? k }
191
212
  description = 'No documentation'
192
213
  examples_object = []
193
- YARD::Registry.all(:class).detect do |code_object|
194
- next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
195
-
214
+ cop_code(cop) do |code_object|
196
215
  description = code_object.docstring unless code_object.docstring.blank?
197
216
  examples_object = code_object.tags('example')
198
217
  end
199
218
  cops_body(config, cop, description, examples_object, pars)
200
219
  end
201
220
 
221
+ def cop_code(cop)
222
+ YARD::Registry.all(:class).detect do |code_object|
223
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
224
+
225
+ yield code_object
226
+ end
227
+ end
228
+
202
229
  # rubocop:disable Metrics/AbcSize
203
230
  def table_of_content_for_department(cops, department)
204
231
  selected_cops = cops_of_department(cops, department.to_sym).select do |cop|
@@ -207,11 +234,11 @@ task generate_cops_documentation: :yard_for_generate_documentation do
207
234
  return if selected_cops.empty?
208
235
 
209
236
  type_title = department[0].upcase + department[1..-1]
210
- filename = "cops_#{department.downcase}.md"
211
- content = +"#### Department [#{type_title}](#{filename})\n\n"
212
- selected_cops.each do |cop|
237
+ filename = "cops_#{department.downcase}.adoc"
238
+ content = +"= Department xref:#{filename}[#{type_title}]\n\n"
239
+ cops_of_department(cops, department.to_sym).each do |cop|
213
240
  anchor = cop.cop_name.sub('/', '').downcase
214
- content << "* [#{cop.cop_name}](#{filename}##{anchor})\n"
241
+ content << "* xref:#{filename}##{anchor}[#{cop.cop_name}]\n"
215
242
  end
216
243
 
217
244
  content
@@ -219,21 +246,17 @@ task generate_cops_documentation: :yard_for_generate_documentation do
219
246
  # rubocop:enable Metrics/AbcSize
220
247
 
221
248
  def print_table_of_contents(cops)
222
- path = "#{Dir.pwd}/manual/cops.md"
249
+ path = "#{Dir.pwd}/docs/modules/ROOT/pages/cops.adoc"
223
250
  original = File.read(path)
224
- content = +"<!-- START_COP_LIST -->\n"
251
+ content = +"// START_COP_LIST\n\n"
225
252
 
226
253
  content << table_contents(cops)
227
254
 
228
- content << "\n<!-- END_COP_LIST -->"
255
+ content << "\n// END_COP_LIST"
229
256
 
230
- content = if original.empty?
231
- content
232
- else
233
- original.sub(
234
- /<!-- START_COP_LIST -->.+<!-- END_COP_LIST -->/m, content
235
- )
236
- end
257
+ content = original.sub(
258
+ %r{// START_COP_LIST.+// END_COP_LIST}m, content
259
+ )
237
260
  File.write(path, content)
238
261
  end
239
262
 
@@ -243,19 +266,25 @@ task generate_cops_documentation: :yard_for_generate_documentation do
243
266
  .map(&:to_s)
244
267
  .sort
245
268
  .map { |department| table_of_content_for_department(cops, department) }
246
- .reject(&:nil?)
269
+ .compact
247
270
  .join("\n")
248
271
  end
249
272
 
250
- def assert_manual_synchronized
273
+ def cop_status(status)
274
+ return 'Disabled' unless status
275
+
276
+ status == 'pending' ? 'Pending' : 'Enabled'
277
+ end
278
+
279
+ def assert_docs_synchronized
251
280
  # Do not print diff and yield whether exit code was zero
252
- sh('git diff --quiet manual') do |outcome, _|
281
+ sh('git diff --quiet docs') do |outcome, _|
253
282
  return if outcome
254
283
 
255
284
  # Output diff before raising error
256
- sh('GIT_PAGER=cat git diff manual')
285
+ sh('GIT_PAGER=cat git diff docs')
257
286
 
258
- warn 'The manual directory is out of sync. ' \
287
+ warn 'The docs directory is out of sync. ' \
259
288
  'Run `rake generate_cops_documentation` and commit the results.'
260
289
  exit!
261
290
  end
@@ -272,7 +301,7 @@ task generate_cops_documentation: :yard_for_generate_documentation do
272
301
 
273
302
  print_table_of_contents(cops)
274
303
 
275
- assert_manual_synchronized if ENV['CI'] == 'true'
304
+ assert_docs_synchronized if ENV['CI'] == 'true'
276
305
  ensure
277
306
  RuboCop::ConfigLoader.default_configuration = nil
278
307
  end