rubocop-minitest 0.2.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.
@@ -0,0 +1 @@
1
+ A [RuboCop](https://github.com/rubocop-hq/rubocop) extension focused on enforcing Minitest best practices and coding conventions.
@@ -0,0 +1,11 @@
1
+ Just install the `rubocop-minitest` gem
2
+
3
+ ```sh
4
+ gem install rubocop-minitest
5
+ ```
6
+
7
+ or if you use bundler put this in your `Gemfile`
8
+
9
+ ```ruby
10
+ gem 'rubocop-minitest'
11
+ ```
@@ -0,0 +1,27 @@
1
+ You need to tell RuboCop to load the Minitest extension. There are three
2
+ ways to do this:
3
+
4
+ ### RuboCop configuration file
5
+
6
+ Put this into your `.rubocop.yml`.
7
+
8
+ ```yaml
9
+ require: rubocop-minitest
10
+ ```
11
+
12
+ Now you can run `rubocop` and it will automatically load the RuboCop Minitest
13
+ cops together with the standard cops.
14
+
15
+ ### Command line
16
+
17
+ ```sh
18
+ rubocop --require rubocop-minitest
19
+ ```
20
+
21
+ ### Rake task
22
+
23
+ ```ruby
24
+ RuboCop::RakeTask.new do |task|
25
+ task.requires << 'rubocop-minitest'
26
+ end
27
+ ```
@@ -0,0 +1,13 @@
1
+ site_name: "A RuboCop extension focused on enforcing Minitest best practices and coding conventions."
2
+ repo_url: https://github.com/rubocop-hq/rubocop-minitest
3
+ edit_uri: edit/master/manual/
4
+ copyright: "Copyright &copy; 2019 Bozhidar Batsov, Jonas Arvidsson, Koichi ITO, and RuboCop contributors"
5
+ docs_dir: manual
6
+ pages:
7
+ - Home: index.md
8
+ - Installation: installation.md
9
+ - Usage: usage.md
10
+ - Cops: cops.md
11
+ - Cops Documentation:
12
+ - Minitest Cops: cops_minitest.md
13
+ theme: readthedocs
@@ -0,0 +1,5 @@
1
+ build:
2
+ image: stable
3
+
4
+ formats:
5
+ - htmlzip
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rubocop/minitest/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'rubocop-minitest'
9
+ spec.version = RuboCop::Minitest::VERSION
10
+ spec.authors = ['Bozhidar Batsov', 'Jonas Arvidsson', 'Koichi ITO']
11
+
12
+ spec.summary = 'Automatic Minitest code style checking tool.'
13
+ spec.description = <<~DESCRIPTION
14
+ Automatic Minitest code style checking tool.
15
+ A RuboCop extension focused on enforcing Minitest best practices and coding conventions.
16
+ DESCRIPTION
17
+ spec.license = 'MIT'
18
+
19
+ spec.required_ruby_version = '>= 2.3.0'
20
+ spec.metadata = {
21
+ 'homepage_uri' => 'https://docs.rubocop.org/projects/minitest',
22
+ 'changelog_uri' => 'https://github.com/rubocop-hq/rubocop-minitest/blob/master/CHANGELOG.md',
23
+ 'source_code_uri' => 'https://github.com/rubocop-hq/rubocop-minitest',
24
+ 'documentation_uri' => 'https://docs.rubocop.org/projects/minitest',
25
+ 'bug_tracker_uri' => 'https://github.com/rubocop-hq/rubocop-minitest/issues'
26
+ }
27
+
28
+ # Specify which files should be added to the gem when it is released.
29
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
31
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
+ end
33
+ spec.bindir = 'exe'
34
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ['lib']
36
+
37
+ spec.add_runtime_dependency 'rubocop', '>= 0.74'
38
+ spec.add_development_dependency 'minitest', '~> 5.11'
39
+ end
@@ -0,0 +1,312 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yard'
4
+ require 'rubocop'
5
+ require 'rubocop-minitest'
6
+
7
+ YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task|
8
+ task.files = ['lib/rubocop/cop/**/*.rb']
9
+ task.options = ['--no-output']
10
+ end
11
+
12
+ desc 'Generate docs of all cops departments'
13
+ task generate_cops_documentation: :yard_for_generate_documentation do
14
+ def cops_of_department(cops, department)
15
+ cops.with_department(department).sort!
16
+ end
17
+
18
+ def cops_body(config, cop, description, examples_objects, pars)
19
+ content = h2(cop.cop_name)
20
+ content << properties(config, cop)
21
+ content << "#{description}\n"
22
+ content << examples(examples_objects) if examples_objects.count.positive?
23
+ content << configurations(pars)
24
+ content << references(config, cop)
25
+ content
26
+ end
27
+
28
+ def examples(examples_object)
29
+ examples_object.each_with_object(h3('Examples').dup) do |example, content|
30
+ content << h4(example.name) unless example.name == ''
31
+ content << code_example(example)
32
+ end
33
+ end
34
+
35
+ # rubocop:disable Metrics/MethodLength
36
+ def properties(config, cop)
37
+ header = [
38
+ 'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
39
+ 'VersionChanged'
40
+ ]
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}"
45
+ else
46
+ 'No'
47
+ end
48
+ content = [[
49
+ config.fetch('Enabled') ? 'Enabled' : 'Disabled',
50
+ config.fetch('Safe', true) ? 'Yes' : 'No',
51
+ autocorrect,
52
+ config.fetch('VersionAdded', '-'),
53
+ config.fetch('VersionChanged', '-')
54
+ ]]
55
+ to_table(header, content) + "\n"
56
+ end
57
+ # rubocop:enable Metrics/MethodLength
58
+
59
+ def h2(title)
60
+ content = +"\n"
61
+ content << "## #{title}\n"
62
+ content << "\n"
63
+ content
64
+ end
65
+
66
+ def h3(title)
67
+ content = +"\n"
68
+ content << "### #{title}\n"
69
+ content << "\n"
70
+ content
71
+ end
72
+
73
+ def h4(title)
74
+ content = +"#### #{title}\n"
75
+ content << "\n"
76
+ content
77
+ end
78
+
79
+ 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"
84
+ content
85
+ end
86
+
87
+ def configurations(pars)
88
+ return '' if pars.empty?
89
+
90
+ header = ['Name', 'Default value', 'Configurable values']
91
+ configs = pars.each_key.reject { |key| key.start_with?('Supported') }
92
+ content = configs.map do |name|
93
+ configurable = configurable_values(pars, name)
94
+ default = format_table_value(pars[name])
95
+ [name, default, configurable]
96
+ end
97
+
98
+ h3('Configurable attributes') + to_table(header, content)
99
+ end
100
+
101
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
102
+ def configurable_values(pars, name)
103
+ case name
104
+ when /^Enforced/
105
+ supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
106
+ format_table_value(pars[supported_style_name])
107
+ when 'IndentationWidth'
108
+ 'Integer'
109
+ when 'Database'
110
+ format_table_value(pars['SupportedDatabases'])
111
+ else
112
+ case pars[name]
113
+ when String
114
+ 'String'
115
+ when Integer
116
+ 'Integer'
117
+ when Float
118
+ 'Float'
119
+ when true, false
120
+ 'Boolean'
121
+ when Array
122
+ 'Array'
123
+ else
124
+ ''
125
+ end
126
+ end
127
+ end
128
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
129
+
130
+ def to_table(header, content)
131
+ table = [
132
+ header.join(' | '),
133
+ Array.new(header.size, '---').join(' | ')
134
+ ]
135
+ table.concat(content.map { |c| c.join(' | ') })
136
+ table.join("\n") + "\n"
137
+ end
138
+
139
+ def format_table_value(val)
140
+ value =
141
+ case val
142
+ when Array
143
+ if val.empty?
144
+ '`[]`'
145
+ else
146
+ val.map { |config| format_table_value(config) }.join(', ')
147
+ end
148
+ else
149
+ "`#{val.nil? ? '<none>' : val}`"
150
+ end
151
+ value.gsub("#{Dir.pwd}/", '').rstrip
152
+ end
153
+
154
+ def references(config, cop)
155
+ cop_config = config.for_cop(cop)
156
+ urls = RuboCop::Cop::MessageAnnotator.new(
157
+ config, cop.name, cop_config, {}
158
+ ).urls
159
+ return '' if urls.empty?
160
+
161
+ content = h3('References')
162
+ content << urls.map { |url| "* [#{url}](#{url})" }.join("\n")
163
+ content << "\n"
164
+ content
165
+ end
166
+
167
+ def print_cops_of_department(cops, department, config)
168
+ selected_cops = cops_of_department(cops, department).select do |cop|
169
+ cop.to_s.start_with?('RuboCop::Cop::Minitest')
170
+ end
171
+ return if selected_cops.empty?
172
+
173
+ content = +"# #{department}\n"
174
+ selected_cops.each do |cop|
175
+ content << print_cop_with_doc(cop, config)
176
+ end
177
+ file_name = "#{Dir.pwd}/manual/cops_#{department.downcase}.md"
178
+ File.open(file_name, 'w') do |file|
179
+ puts "* generated #{file_name}"
180
+ file.write(content.strip + "\n")
181
+ end
182
+ end
183
+
184
+ def print_cop_with_doc(cop, config)
185
+ t = config.for_cop(cop)
186
+ non_display_keys = %w[
187
+ Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
188
+ VersionChanged
189
+ ]
190
+ pars = t.reject { |k| non_display_keys.include? k }
191
+ description = 'No documentation'
192
+ 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
+
196
+ description = code_object.docstring unless code_object.docstring.blank?
197
+ examples_object = code_object.tags('example')
198
+ end
199
+ cops_body(config, cop, description, examples_object, pars)
200
+ end
201
+
202
+ # rubocop:disable Metrics/AbcSize
203
+ def table_of_content_for_department(cops, department)
204
+ selected_cops = cops_of_department(cops, department.to_sym).select do |cop|
205
+ cop.to_s.start_with?('RuboCop::Cop::Minitest')
206
+ end
207
+ return if selected_cops.empty?
208
+
209
+ 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|
213
+ anchor = cop.cop_name.sub('/', '').downcase
214
+ content << "* [#{cop.cop_name}](#{filename}##{anchor})\n"
215
+ end
216
+
217
+ content
218
+ end
219
+ # rubocop:enable Metrics/AbcSize
220
+
221
+ def print_table_of_contents(cops)
222
+ path = "#{Dir.pwd}/manual/cops.md"
223
+ original = File.read(path)
224
+ content = +"<!-- START_COP_LIST -->\n"
225
+
226
+ content << table_contents(cops)
227
+
228
+ content << "\n<!-- END_COP_LIST -->"
229
+
230
+ content = if original.empty?
231
+ content
232
+ else
233
+ original.sub(
234
+ /<!-- START_COP_LIST -->.+<!-- END_COP_LIST -->/m, content
235
+ )
236
+ end
237
+ File.write(path, content)
238
+ end
239
+
240
+ def table_contents(cops)
241
+ cops
242
+ .departments
243
+ .map(&:to_s)
244
+ .sort
245
+ .map { |department| table_of_content_for_department(cops, department) }
246
+ .reject(&:nil?)
247
+ .join("\n")
248
+ end
249
+
250
+ def assert_manual_synchronized
251
+ # Do not print diff and yield whether exit code was zero
252
+ sh('git diff --quiet manual') do |outcome, _|
253
+ return if outcome
254
+
255
+ # Output diff before raising error
256
+ sh('GIT_PAGER=cat git diff manual')
257
+
258
+ warn 'The manual directory is out of sync. ' \
259
+ 'Run `rake generate_cops_documentation` and commit the results.'
260
+ exit!
261
+ end
262
+ end
263
+
264
+ def main
265
+ cops = RuboCop::Cop::Cop.registry
266
+ config = RuboCop::ConfigLoader.load_file('config/default.yml')
267
+
268
+ YARD::Registry.load!
269
+ cops.departments.sort!.each do |department|
270
+ print_cops_of_department(cops, department, config)
271
+ end
272
+
273
+ print_table_of_contents(cops)
274
+
275
+ assert_manual_synchronized if ENV['CI'] == 'true'
276
+ ensure
277
+ RuboCop::ConfigLoader.default_configuration = nil
278
+ end
279
+
280
+ main
281
+ end
282
+
283
+ desc 'Syntax check for the documentation comments'
284
+ task documentation_syntax_check: :yard_for_generate_documentation do
285
+ require 'parser/ruby25'
286
+
287
+ ok = true
288
+ YARD::Registry.load!
289
+ cops = RuboCop::Cop::Cop.registry
290
+ cops.each do |cop|
291
+ examples = YARD::Registry.all(:class).find do |code_object|
292
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
293
+
294
+ break code_object.tags('example')
295
+ end
296
+
297
+ examples.to_a.each do |example|
298
+ begin
299
+ buffer = Parser::Source::Buffer.new('<code>', 1)
300
+ buffer.source = example.text
301
+ parser = Parser::Ruby25.new(RuboCop::AST::Builder.new)
302
+ parser.diagnostics.all_errors_are_fatal = true
303
+ parser.parse(buffer)
304
+ rescue Parser::SyntaxError => e
305
+ path = example.object.file
306
+ puts "#{path}: Syntax Error in an example. #{e}"
307
+ ok = false
308
+ end
309
+ end
310
+ end
311
+ abort unless ok
312
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubocop-minitest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Bozhidar Batsov
8
+ - Jonas Arvidsson
9
+ - Koichi ITO
10
+ autorequire:
11
+ bindir: exe
12
+ cert_chain: []
13
+ date: 2019-09-24 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rubocop
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '0.74'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '0.74'
29
+ - !ruby/object:Gem::Dependency
30
+ name: minitest
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '5.11'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '5.11'
43
+ description: |
44
+ Automatic Minitest code style checking tool.
45
+ A RuboCop extension focused on enforcing Minitest best practices and coding conventions.
46
+ email:
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".circleci/config.yml"
52
+ - ".github/ISSUE_TEMPLATE/bug_report.md"
53
+ - ".github/ISSUE_TEMPLATE/feature_request.md"
54
+ - ".github/PULL_REQUEST_TEMPLATE.md"
55
+ - ".gitignore"
56
+ - ".rubocop.yml"
57
+ - ".rubocop_todo.yml"
58
+ - CHANGELOG.md
59
+ - CONTRIBUTING.md
60
+ - Gemfile
61
+ - LICENSE.txt
62
+ - README.md
63
+ - Rakefile
64
+ - bin/console
65
+ - bin/setup
66
+ - config/default.yml
67
+ - lib/rubocop-minitest.rb
68
+ - lib/rubocop/cop/minitest/assert_empty.rb
69
+ - lib/rubocop/cop/minitest/assert_includes.rb
70
+ - lib/rubocop/cop/minitest/assert_nil.rb
71
+ - lib/rubocop/cop/minitest/assert_truthy.rb
72
+ - lib/rubocop/cop/minitest/refute_nil.rb
73
+ - lib/rubocop/cop/minitest_cops.rb
74
+ - lib/rubocop/minitest.rb
75
+ - lib/rubocop/minitest/inject.rb
76
+ - lib/rubocop/minitest/version.rb
77
+ - manual/cops.md
78
+ - manual/cops_minitest.md
79
+ - manual/index.md
80
+ - manual/installation.md
81
+ - manual/usage.md
82
+ - mkdocs.yml
83
+ - readthedocs.yml
84
+ - rubocop-minitest.gemspec
85
+ - tasks/cops_documentation.rake
86
+ homepage:
87
+ licenses:
88
+ - MIT
89
+ metadata:
90
+ homepage_uri: https://docs.rubocop.org/projects/minitest
91
+ changelog_uri: https://github.com/rubocop-hq/rubocop-minitest/blob/master/CHANGELOG.md
92
+ source_code_uri: https://github.com/rubocop-hq/rubocop-minitest
93
+ documentation_uri: https://docs.rubocop.org/projects/minitest
94
+ bug_tracker_uri: https://github.com/rubocop-hq/rubocop-minitest/issues
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.3.0
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubygems_version: 3.0.6
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Automatic Minitest code style checking tool.
114
+ test_files: []