yard-junk 0.0.3 → 0.0.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d528277a6fb7bba1da971f94aae6b57026c389f3
4
- data.tar.gz: 1e87ce70c14f718fcb2cd46eb4dcc5bbb86824e1
2
+ SHA256:
3
+ metadata.gz: 5ae36216a5faaa685ff336798cdac734e1e1088925647c2f4daed058bfe9ae24
4
+ data.tar.gz: 9d4bb2f2afd494922f317b5aeb3d29da03bc63bb05c2022fc5cb888eba9eb95b
5
5
  SHA512:
6
- metadata.gz: b8a095dad1cbc9da2e87a038ed30f563982ac38eb0f18c4f060cf0251ded6fea8cb40eccfb2405710789933b7f5c54faff649626e725678ef675bf3b35dd6d91
7
- data.tar.gz: 2466c0a768593a605283f7c136bfb4d012a28701dbf3b32026e48da138162528fd9789275bba4c7dfa94aa6d8a3db6136ae4b91419a5727ab317722d9552dc83
6
+ metadata.gz: 7ca4fee74f9c585756155d3182acbda310236c2a6e54a79c5df18f9a012beb89e40fef48921ddbc55488ea27212b644bb30f2d0959eec014f1e4529df4fa09a6
7
+ data.tar.gz: 809c9b9c79fb371a2d6a3b768000122c4dbddb85f97a8c6f41cae089ff591f7926ca009888826007b6bdcabca8616c033697b82c353b568606c560490383748d
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ main:
11
+ name: >-
12
+ ${{ matrix.ruby }}
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ ruby: [ 2.5, 2.6, 2.7, head ]
18
+
19
+ steps:
20
+ - name: checkout
21
+ uses: actions/checkout@v2
22
+ - name: set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby }}
26
+
27
+ - name: install dependencies
28
+ run: bundle install --jobs 3 --retry 3
29
+ - name: spec
30
+ run: bundle exec rake spec
31
+ - name: rubocop
32
+ run: bundle exec rake rubocop
@@ -1,5 +1,27 @@
1
1
  # Yard-Junk changelog
2
2
 
3
+ ## 0.0.8 -- 2020-11-12
4
+
5
+ * Support Ruby 2.7 (and hopefully 3.0)
6
+ * Drop support for Rubies below 2.5 :shrug:
7
+
8
+ ## 0.0.7 -- 2017-09-21
9
+
10
+ * Fix problems with links resolution for RDoc.
11
+
12
+ ## 0.0.6 -- 2017-09-20
13
+
14
+ * More robust (and more logical) colorization on text output (#25);
15
+ * Fast "sanity check" for using in pre-commit hook on large codebases (#24).
16
+
17
+ ## 0.0.5 -- 2017-09-11
18
+
19
+ * Fix gem conflict with `did_you_mean`.
20
+
21
+ ## 0.0.4 -- 2017-09-09
22
+
23
+ * Support for partial reports `yard-junk --path path/to/folder` (#13)
24
+
3
25
  ## 0.0.3 -- 2017-09-07
4
26
 
5
27
  * Wiser dependency on `did_you_mean`, should not break CIs now.
@@ -0,0 +1,90 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ yard-junk (0.0.8)
5
+ backports (>= 3.18)
6
+ rainbow
7
+ yard
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ ast (2.4.1)
13
+ backports (3.18.2)
14
+ diff-lcs (1.4.4)
15
+ docile (1.1.5)
16
+ fakefs (1.2.2)
17
+ json (2.3.1)
18
+ json (2.3.1-java)
19
+ kramdown (2.3.0)
20
+ rexml
21
+ parallel (1.20.0)
22
+ parser (2.7.2.0)
23
+ ast (~> 2.4.1)
24
+ rainbow (3.0.0)
25
+ rake (13.0.1)
26
+ regexp_parser (1.8.2)
27
+ rexml (3.2.4)
28
+ rspec (3.10.0)
29
+ rspec-core (~> 3.10.0)
30
+ rspec-expectations (~> 3.10.0)
31
+ rspec-mocks (~> 3.10.0)
32
+ rspec-core (3.10.0)
33
+ rspec-support (~> 3.10.0)
34
+ rspec-expectations (3.10.0)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.10.0)
37
+ rspec-its (1.2.0)
38
+ rspec-core (>= 3.0.0)
39
+ rspec-expectations (>= 3.0.0)
40
+ rspec-mocks (3.10.0)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.10.0)
43
+ rspec-support (3.10.0)
44
+ rubocop (1.3.0)
45
+ parallel (~> 1.10)
46
+ parser (>= 2.7.1.5)
47
+ rainbow (>= 2.2.2, < 4.0)
48
+ regexp_parser (>= 1.8)
49
+ rexml
50
+ rubocop-ast (>= 1.1.1)
51
+ ruby-progressbar (~> 1.7)
52
+ unicode-display_width (>= 1.4.0, < 2.0)
53
+ rubocop-ast (1.1.1)
54
+ parser (>= 2.7.1.5)
55
+ rubocop-rspec (2.0.0)
56
+ rubocop (~> 1.0)
57
+ rubocop-ast (>= 1.1.0)
58
+ ruby-progressbar (1.10.1)
59
+ ruby2_keywords (0.0.2)
60
+ rubygems-tasks (0.2.4)
61
+ saharspec (0.0.8)
62
+ ruby2_keywords
63
+ simplecov (0.15.0)
64
+ docile (~> 1.1.0)
65
+ json (>= 1.8, < 3)
66
+ simplecov-html (~> 0.10.0)
67
+ simplecov-html (0.10.2)
68
+ unicode-display_width (1.7.0)
69
+ yard (0.9.25)
70
+
71
+ PLATFORMS
72
+ java
73
+ ruby
74
+
75
+ DEPENDENCIES
76
+ fakefs
77
+ kramdown
78
+ rake
79
+ rspec (>= 3)
80
+ rspec-its (~> 1)
81
+ rubocop
82
+ rubocop-rspec
83
+ rubygems-tasks
84
+ saharspec
85
+ simplecov (~> 0.9)
86
+ yard
87
+ yard-junk!
88
+
89
+ BUNDLED WITH
90
+ 1.17.3
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Yard-Junk: get rid of junk in your YARD docs!
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/yard-junk.svg)](http://badge.fury.io/rb/yard-junk)
4
- [![Build Status](https://travis-ci.org/zverok/yard-junk.svg?branch=master)](https://travis-ci.org/zverok/yard-junk)
4
+ ![Build Status](https://github.com/zverok/yard-junk/workflows/CI/badge.svg?branch=master)
5
5
 
6
6
  Yard-Junk is [yard](https://github.com/lsegal/yard) plugin/patch, that provides:
7
7
 
@@ -381,6 +381,19 @@ Examples:
381
381
  * `yard-junk --text --html build-artifacts/junk-yard.html` (several formatters at once: text to console,
382
382
  HTML to file).
383
383
 
384
+ You can also specify pathes to report (useful when working on large codebases, when you want to check
385
+ only your recent piece of work):
386
+
387
+ ```
388
+ yard-junk --path some/path/
389
+ yard-junk --path other/path/*sample*.rb
390
+ yard-junk --path specific/path.rb
391
+ yard-junk --path several,different/*.rb,patterns.rb
392
+ ```
393
+
394
+ Note that `yard-junk` would parse the pathes that set in `.yardopts` as usually, and then
395
+ **filter report** by pattern specified.
396
+
384
397
  ### Rake task (integrating in CI)
385
398
 
386
399
  Add this to your `Rakefile`:
@@ -416,17 +429,15 @@ Therefore, this independent tool was made.
416
429
 
417
430
  ## Caveats
418
431
 
419
- * Sometimes YARD doesn't provide enough information to guess in which line of code the problem is;
420
- in those cases `yard-junk` just writes something like `file.rb:1` (to stay consistent and not break
421
- go-to-file tools);
422
- * Checking of links to files and URLs proven to be incomplete ([#12](https://github.com/zverok/yard-junk/issues/12)).
432
+ Sometimes YARD doesn't provide enough information to guess in which line of code the problem is;
433
+ in those cases `yard-junk` just writes something like `file.rb:1` (to stay consistent and not break
434
+ go-to-file tools).
423
435
 
424
436
  ## Roadmap
425
437
 
426
438
  * Docs for usage as a system-wide YARD plugin;
427
439
  * Docs for internals;
428
- * Documentation quality checks as a next level of YARD checker ([#14](https://github.com/zverok/yard-junk/issues/14));
429
- * Option to check only selected parts of code ([#13](https://github.com/zverok/yard-junk/issues/13)).
440
+ * Documentation quality checks as a next level of YARD checker ([#14](https://github.com/zverok/yard-junk/issues/14)).
430
441
 
431
442
  ## Some examples of problems found in popular gems:
432
443
 
@@ -8,12 +8,14 @@ require 'yard-junk'
8
8
  require 'optparse'
9
9
 
10
10
  formatters = {}
11
+ options = {}
11
12
 
12
- OptionParser.new do |opts|
13
+ OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
13
14
  opts.banner = 'Usage: yard-junk [formatters]'
14
15
  opts.separator ''
15
16
  opts.separator 'Formatters'
16
- opts.separator '(you can use several at once, for example --text to print in console and --html to save HTML report somewhere)'
17
+ opts.separator '(you can use several at once, for example --text to print in console '\
18
+ 'and --html to save HTML report somewhere)'
17
19
  opts.separator 'Default is: text formatter, printing to STDOUT.'
18
20
  opts.separator ''
19
21
 
@@ -21,13 +23,31 @@ OptionParser.new do |opts|
21
23
  formatters[:text] = path
22
24
  end
23
25
 
24
- opts.on('--html [PATH]', 'HTML formatter, useful as CI artifact (prints to STDOUT by default)') do |path|
26
+ opts.on('--html [PATH]',
27
+ 'HTML formatter, useful as CI artifact (prints to STDOUT by default)') do |path|
25
28
  formatters[:html] = path
26
29
  end
27
30
 
28
31
  opts.separator ''
29
32
  opts.separator 'Other options'
30
33
 
34
+ opts.on('-f', '--path PATTERN1,PATTERN2,PATTERN3',
35
+ 'Limit output only to this files. '\
36
+ 'Can be path to file or folder, or glob pattern') do |patterns|
37
+ options[:pathes] = patterns.split(',')
38
+ end
39
+
40
+ opts.on('-s', '--sanity',
41
+ 'Sanity check for docs: just catch mistyped tags and similar stuff. '\
42
+ 'On large codebases, MUCH faster than full check.') do
43
+ options[:mode] = :sanity
44
+ end
45
+
46
+ opts.on_tail('-v', '--version', 'Prints version') do
47
+ puts "YardJunk #{YardJunk::VERSION}"
48
+ exit
49
+ end
50
+
31
51
  opts.on_tail('-h', '--help', 'Show this message') do
32
52
  puts opts
33
53
  exit
@@ -36,6 +56,6 @@ end.parse!
36
56
 
37
57
  formatters = {text: nil} if formatters.empty?
38
58
 
39
- janitor = YardJunk::Janitor.new
59
+ janitor = YardJunk::Janitor.new(**options)
40
60
  janitor.run
41
61
  exit janitor.report(**formatters)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'yard'
4
+ require_relative 'yard-junk/version'
3
5
  require_relative 'yard-junk/logger'
4
6
  require_relative 'yard-junk/command_line'
5
7
  require_relative 'yard-junk/janitor'
@@ -8,11 +8,15 @@ module YardJunk
8
8
  opts.separator ''
9
9
  opts.separator 'YardJunk plugin options'
10
10
 
11
- opts.on('--junk-log-format [FMT]', "YardJunk::Logger format string, by default #{Logger::Message::DEFAULT_FORMAT.inspect}") do |format|
11
+ opts.on('--junk-log-format [FMT]',
12
+ 'YardJunk::Logger format string, by default '\
13
+ "#{Logger::Message::DEFAULT_FORMAT.inspect}") do |format|
12
14
  Logger.instance.format = format
13
15
  end
14
16
 
15
- opts.on('--junk-log-ignore [TYPE1,TYPE2,...]', "YardJunk::Logger message types to ignore, by default #{Logger::DEFAULT_IGNORE.map(&:inspect).join(', ')}") do |ignore|
17
+ opts.on('--junk-log-ignore [TYPE1,TYPE2,...]',
18
+ 'YardJunk::Logger message types to ignore, by default '\
19
+ "#{Logger::DEFAULT_IGNORE.map(&:inspect).join(', ')}") do |ignore|
16
20
  Logger.instance.ignore = ignore.to_s.split(',')
17
21
  end
18
22
 
@@ -2,19 +2,25 @@
2
2
 
3
3
  require 'benchmark'
4
4
  require 'backports/2.3.0/enumerable/grep_v'
5
+ require 'backports/2.6.0/array/to_h'
5
6
 
6
7
  module YardJunk
7
8
  class Janitor
9
+ def initialize(mode: :full, pathes: nil)
10
+ @mode = mode
11
+ @files = expand_pathes(pathes)
12
+ end
13
+
8
14
  def run(*opts)
9
15
  YARD::Registry.clear # Somehow loads all Ruby stdlib classes before Rake task started...
10
- Logger.instance.format = nil
16
+ Logger.instance.format = nil # Nothing shouuld be printed
11
17
 
12
- puts "Running YardJunk janitor...\n\n"
18
+ puts "Running YardJunk janitor (version #{YardJunk::VERSION})...\n\n"
13
19
 
14
20
  @duration = Benchmark.realtime do
15
21
  command = YARD::CLI::Yardoc.new
16
- command.run('--no-save', '--no-progress', '--no-stats', '--no-output', *opts)
17
- Resolver.resolve_all(command.options)
22
+ command.run(*prepare_options(opts))
23
+ Resolver.resolve_all(command.options) unless mode == :sanity
18
24
  end
19
25
 
20
26
  self
@@ -41,15 +47,43 @@ module YardJunk
41
47
  end
42
48
 
43
49
  def exit_code
44
- return 2 unless errors.empty?
45
- return 1 unless problems.empty?
46
- 0
50
+ case
51
+ when !errors.empty? then 2
52
+ when !problems.empty? then 1
53
+ else 0
54
+ end
47
55
  end
48
56
 
49
57
  private
50
58
 
59
+ attr_reader :mode, :files, :yardopts
60
+
61
+ BASE_OPTS = %w[--no-save --no-progress --no-stats --no-output --no-cache].freeze
62
+
63
+ def prepare_options(opts)
64
+ case
65
+ when mode == :full || mode == :sanity && files.nil?
66
+ [*BASE_OPTS, *opts]
67
+ when mode == :sanity
68
+ # TODO: specs
69
+ [*BASE_OPTS, '--no-yardopts', *yardopts_with_files(files)]
70
+ else
71
+ fail ArgumentError, "Undefined mode: #{mode.inspect}"
72
+ end
73
+ end
74
+
75
+ def yardopts_with_files(files)
76
+ # Use all options from .yardopts file, but replace file lists
77
+ YardOptions.new.remove_option('--files').set_files(*files)
78
+ end
79
+
51
80
  def messages
52
- YardJunk::Logger.instance.messages.grep_v(Logger::Undocumentable) # FIXME: Not DRY
81
+ # FIXME: dropping Undocumentable here is not DRY
82
+ @messages ||= YardJunk::Logger
83
+ .instance
84
+ .messages
85
+ .grep_v(Logger::Undocumentable)
86
+ .select { |m| !files || !m.file || files.include?(File.expand_path(m.file)) }
53
87
  end
54
88
 
55
89
  def errors
@@ -60,12 +94,23 @@ module YardJunk
60
94
  messages.select(&:warn?)
61
95
  end
62
96
 
97
+ def expand_pathes(pathes)
98
+ return unless pathes
99
+
100
+ Array(pathes)
101
+ .map { |path| File.directory?(path) ? File.join(path, '**', '*.*') : path }
102
+ .flat_map(&Dir.method(:[]))
103
+ .map(&File.method(:expand_path))
104
+ end
105
+
63
106
  # TODO: specs for the logic
64
107
  def guess_reporters(*symbols, **symbols_with_args)
65
108
  symbols
66
- .map { |sym| [sym, nil] }.to_h.merge(symbols_with_args)
109
+ .to_h { |sym| [sym, nil] }.merge(symbols_with_args)
67
110
  .map { |sym, args| ["#{sym.to_s.capitalize}Reporter", args] }
68
- .each { |name, _| Janitor.const_defined?(name) or fail(ArgumentError, "Reporter #{name} not found") }
111
+ .each { |name,|
112
+ Janitor.const_defined?(name) or fail(ArgumentError, "Reporter #{name} not found")
113
+ }
69
114
  .map { |name, args| Janitor.const_get(name).new(*args) }
70
115
  end
71
116
  end
@@ -75,3 +120,4 @@ require_relative 'janitor/base_reporter'
75
120
  require_relative 'janitor/text_reporter'
76
121
  require_relative 'janitor/html_reporter'
77
122
  require_relative 'janitor/resolver'
123
+ require_relative 'janitor/yard_options'
@@ -19,7 +19,7 @@ module YardJunk
19
19
  #
20
20
  # @overload initialize(filename)
21
21
  # @param filename [String] Name of file to save the output.
22
- def initialize(io_or_filename = STDOUT)
22
+ def initialize(io_or_filename = $stdout)
23
23
  @io =
24
24
  case io_or_filename
25
25
  when ->(i) { i.respond_to?(:puts) } # quacks!
@@ -35,6 +35,7 @@ module YardJunk
35
35
 
36
36
  def section(title, explanation, messages)
37
37
  return if messages.empty?
38
+
38
39
  header(title, explanation)
39
40
 
40
41
  messages
@@ -43,7 +44,7 @@ module YardJunk
43
44
  end
44
45
 
45
46
  def stats(**stat)
46
- _stats(stat.merge(duration: humanize_duration(stat[:duration])))
47
+ _stats(**stat.merge(duration: humanize_duration(stat[:duration])))
47
48
  end
48
49
 
49
50
  private
@@ -2,25 +2,39 @@
2
2
 
3
3
  module YardJunk
4
4
  class Janitor
5
- # TODO: Tests
6
5
  class Resolver
7
6
  include YARD::Templates::Helpers::HtmlHelper
7
+ include YARD::Templates::Helpers::MarkupHelper
8
8
 
9
- MESSAGE_PATTERN = 'In file `%{file}\':%{line}: Cannot resolve link to %{name} from text: %{link}'
9
+ # This one is copied from real YARD output
10
+ OBJECT_MESSAGE_PATTERN = "In file `%{file}':%{line}: " \
11
+ 'Cannot resolve link to %{name} from text: %{link}'
12
+
13
+ # ...while this one is totally invented, YARD doesn't check file existance at all
14
+ FILE_MESSAGE_PATTERN = "In file `%{file}':%{line}: File '%{name}' does not exist: %{link}"
10
15
 
11
16
  def self.resolve_all(yard_options)
12
17
  YARD::Registry.all.map(&:base_docstring).each { |ds| new(ds, yard_options).resolve }
18
+ yard_options.files.each { |file| new(file, yard_options).resolve }
13
19
  end
14
20
 
15
- def initialize(docstring, yard_options)
16
- @docstring = docstring
21
+ def initialize(object, yard_options)
17
22
  @options = yard_options
23
+ case object
24
+ when YARD::CodeObjects::ExtraFileObject
25
+ init_file(object)
26
+ when YARD::Docstring
27
+ init_docstring(object)
28
+ else
29
+ fail "Unknown object to resolve #{object.class}"
30
+ end
18
31
  end
19
32
 
20
33
  def resolve
21
- markup_meth = "html_markup_#{options.markup}"
34
+ markup_meth = "html_markup_#{markup}"
22
35
  return unless respond_to?(markup_meth)
23
- send(markup_meth, @docstring)
36
+
37
+ send(markup_meth, @string)
24
38
  .gsub(%r{<(code|tt|pre)[^>]*>(.*?)</\1>}im, '')
25
39
  .scan(/{[^}]+}/).flatten
26
40
  .map(&CGI.method(:unescapeHTML))
@@ -29,20 +43,62 @@ module YardJunk
29
43
 
30
44
  private
31
45
 
32
- attr_reader :options
46
+ def init_file(file)
47
+ @string = file.contents
48
+ @file = file.filename
49
+ @line = 1
50
+ @markup = markup_for_file(file.contents, file.filename)
51
+ end
52
+
53
+ def init_docstring(docstring)
54
+ @string = docstring
55
+ @root_object = docstring.object
56
+ @file = @root_object.file
57
+ @line = @root_object.line
58
+ @markup = options.markup
59
+ end
60
+
61
+ attr_reader :options, :file, :line, :markup
33
62
 
34
63
  def try_resolve(link)
35
64
  name, _comment = link.tr('{}', '').split(/\s+/, 2)
36
- resolved = YARD::Registry.resolve(@docstring.object, name, true, true)
65
+
66
+ # See YARD::Templates::Helpers::BaseHelper#linkify for the source of patterns
67
+ # TODO: there is also {include:}, {include:file:} and {render:} syntaxes, but I've never seen
68
+ # a project using them. /shrug
69
+ case name
70
+ when %r{://}, /^mailto:/ # that's pattern YARD uses
71
+ # do nothing, assume it is correct
72
+ when /^file:(\S+?)(?:#(\S+))?$/
73
+ resolve_file(Regexp.last_match[1], link)
74
+ else
75
+ resolve_code_object(name, link)
76
+ end
77
+ end
78
+
79
+ def resolve_file(name, link)
80
+ return if options.files.any? { |f| f.name == name || f.filename == name }
81
+
82
+ Logger.instance.register(
83
+ FILE_MESSAGE_PATTERN % {file: file, line: line, name: name, link: link}
84
+ )
85
+ end
86
+
87
+ def resolve_code_object(name, link)
88
+ resolved = YARD::Registry.resolve(@root_object, name, true, true)
37
89
  return unless resolved.is_a?(YARD::CodeObjects::Proxy)
38
- Logger.instance.register(MESSAGE_PATTERN % {file: object.file, line: object.line, name: name, link: link})
90
+
91
+ Logger.instance.register(
92
+ OBJECT_MESSAGE_PATTERN % {file: file, line: line, name: name, link: link}
93
+ )
39
94
  end
40
95
 
96
+ # Used by HtmlHelper for RDoc
41
97
  def object
42
- @docstring.object
98
+ @string.object if @string.is_a?(YARD::Docstring)
43
99
  end
44
100
 
45
- # required by HtmlHelper
101
+ # Used by HtmlHelper
46
102
  def serializer
47
103
  nil
48
104
  end
@@ -11,26 +11,24 @@ module YardJunk
11
11
  private
12
12
 
13
13
  def _stats(**stat)
14
- @io.puts "\n#{template_for(stat) % stat}"
14
+ @io.puts "\n#{colorized_stats(**stat)}"
15
15
  end
16
16
 
17
- NO_ISSUES_TEMPLATE = [
18
- Rainbow('%<errors>i failures, %<problems>i problems').green,
19
- Rainbow(', (%<duration>s to run)').gray
20
- ].join('').freeze
21
-
22
- ERROR_COUNT_TEMPLATE = [
23
- Rainbow('%<errors>i failures').red,
24
- Rainbow(',').gray,
25
- Rainbow(' %<problems>i problems').yellow,
26
- Rainbow(', (%<duration>s to run)').gray
27
- ].join('').freeze
28
-
29
- def template_for(stat)
30
- if stat[:errors].zero? && stat[:problems].zero?
31
- NO_ISSUES_TEMPLATE
32
- else
33
- ERROR_COUNT_TEMPLATE
17
+ def colorized_stats(errors:, problems:, duration:)
18
+ colorize(
19
+ format('%i failures, %i problems', errors, problems), status_color(errors, problems)
20
+ ) + format(' (%s to run)', duration)
21
+ end
22
+
23
+ def colorize(text, color)
24
+ Rainbow(text).color(color)
25
+ end
26
+
27
+ def status_color(errors, problems)
28
+ case
29
+ when errors.positive? then :red
30
+ when problems.positive? then :yellow
31
+ else :green
34
32
  end
35
33
  end
36
34
 
@@ -38,7 +36,7 @@ module YardJunk
38
36
  @io.puts
39
37
  @io.puts title
40
38
  @io.puts '-' * title.length
41
- @io.puts explanation + "\n\n"
39
+ @io.puts "#{explanation}\n\n"
42
40
  end
43
41
 
44
42
  def row(msg)
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YardJunk
4
+ class Janitor
5
+ # Allows to properly parse `.yardopts` or other option file YARD supports and gracefully replace
6
+ # or remove some of options.
7
+ class YardOptions
8
+ attr_reader :options, :files, :extra_files
9
+
10
+ def initialize
11
+ internal = Internal.new
12
+ internal.parse_arguments
13
+ @options = internal.option_args
14
+ @files = internal.files
15
+ @extra_files = internal.options.files
16
+ end
17
+
18
+ def set_files(*files) # rubocop:disable Naming/AccessorMethodName
19
+ # TODO: REALLY fragile :(
20
+ @files, @extra_files = files.partition { |f| f =~ /\.(rb|c|cxx|cpp|rake)/ }
21
+ self
22
+ end
23
+
24
+ def remove_option(long, short = nil)
25
+ [short, long].compact.each do |o|
26
+ i = @options.index(o)
27
+ next unless i
28
+
29
+ @options.delete_at(i)
30
+ @options.delete_at(i) unless @options[i].start_with?('-') # it was argument
31
+ end
32
+ self
33
+ end
34
+
35
+ def to_a
36
+ (@options + @files)
37
+ .tap { |res| res.concat(['-', *@extra_files]) unless @extra_files.empty? }
38
+ end
39
+
40
+ # The easiest way to think like Yardoc is to become Yardoc, you know.
41
+ class Internal < YARD::CLI::Yardoc
42
+ attr_reader :option_args
43
+
44
+ def optparse(*args)
45
+ # remember all passed options...
46
+ @all_args = args
47
+ super
48
+ end
49
+
50
+ def parse_files(*args)
51
+ # ...and substract what left after they were parsed as options, and only files left
52
+ @option_args = @all_args - args
53
+ super
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -3,6 +3,8 @@
3
3
  require 'singleton'
4
4
  require 'pp'
5
5
 
6
+ require 'backports/2.7.0/enumerable/filter_map'
7
+
6
8
  module YardJunk
7
9
  class Logger
8
10
  require_relative 'logger/message'
@@ -16,9 +18,10 @@ module YardJunk
16
18
  end
17
19
 
18
20
  def register(msg, severity = :warn)
19
- message = Message.registry
20
- .map { |t| t.try_parse(msg, severity: severity, file: @current_parsed_file) }
21
- .compact.first || Message.new(message: msg, file: @current_parsed_file)
21
+ message =
22
+ Message.registry.filter_map { |t|
23
+ t.try_parse(msg, severity: severity, file: @current_parsed_file)
24
+ }.first || Message.new(message: msg, file: @current_parsed_file)
22
25
  messages << message
23
26
  puts message.to_s(@format) if output?(message)
24
27
  end
@@ -44,8 +47,10 @@ module YardJunk
44
47
  end
45
48
 
46
49
  def ignore=(list)
47
- @ignore = Array(list).map(&:to_s)
48
- .each { |type| Message.valid_type?(type) or fail(ArgumentError, "Unrecognized message type to ignore: #{type}") }
50
+ @ignore = Array(list).map(&:to_s).each do |type|
51
+ Message.valid_type?(type) or
52
+ fail(ArgumentError, "Unrecognized message type to ignore: #{type}")
53
+ end
49
54
  end
50
55
 
51
56
  private
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'did_you_mean'
3
+ require_relative 'spellcheck'
4
4
 
5
5
  module YardJunk
6
6
  class Logger
@@ -10,7 +10,7 @@ module YardJunk
10
10
  def initialize(message:, severity: :warn, code_object: nil, file: nil, line: nil, **extra)
11
11
  @message = message.gsub(/\s{2,}/, ' ')
12
12
  @file = file
13
- @line = line && line.to_i
13
+ @line = line&.to_i
14
14
  @code_object = code_object
15
15
  @severity = severity
16
16
  @extra = extra
@@ -25,7 +25,7 @@ module YardJunk
25
25
  type: type,
26
26
  message: message,
27
27
  file: file,
28
- line: (line && line.to_i) || 1
28
+ line: line&.to_i || 1
29
29
  }.merge(extra)
30
30
  end
31
31
 
@@ -43,43 +43,7 @@ module YardJunk
43
43
  self.class.type
44
44
  end
45
45
 
46
- private
47
-
48
- # DidYouMean changed API dramatically between 1.0 and 1.1, and different rubies have different
49
- # versions of it bundled.
50
- if DidYouMean.const_defined?(:SpellCheckable) # 1.0 +
51
- class SpellChecker < Struct.new(:error, :dictionary) # rubocop:disable Style/StructInheritance
52
- include DidYouMean::SpellCheckable
53
-
54
- def candidates
55
- {error => dictionary}
56
- end
57
- end
58
-
59
- def spell_check(error, dictionary)
60
- SpellChecker.new(error, dictionary).corrections
61
- end
62
- elsif DidYouMean.const_defined?(:SpellChecker) # 1.1+
63
- def spell_check(error, dictionary)
64
- DidYouMean::SpellChecker.new(dictionary: dictionary).correct(error)
65
- end
66
- elsif DidYouMean.const_defined?(:BaseFinder) # < 1.0
67
- class SpellFinder < Struct.new(:error, :dictionary) # rubocop:disable Style/StructInheritance
68
- include DidYouMean::BaseFinder
69
-
70
- def searches
71
- {error => dictionary}
72
- end
73
- end
74
-
75
- def spell_check(error, dictionary)
76
- SpellFinder.new(error, dictionary).suggestions
77
- end
78
- else
79
- def spell_check(*)
80
- []
81
- end
82
- end
46
+ include Spellcheck
83
47
 
84
48
  class << self
85
49
  def registry
@@ -98,8 +62,8 @@ module YardJunk
98
62
  def try_parse(line, **context)
99
63
  @pattern or fail StandardError, "Pattern is not defined for #{self}"
100
64
  match = @pattern.match(line) or return nil
101
- data = context.reject { |_, v| v.nil? }
102
- .merge(match.names.map(&:to_sym).zip(match.captures).to_h.reject { |_, v| v.nil? })
65
+ data = context.compact
66
+ .merge(match.names.map(&:to_sym).zip(match.captures).to_h.compact)
103
67
  data = guard_line(data)
104
68
  new(**data)
105
69
  end
@@ -114,17 +78,17 @@ module YardJunk
114
78
 
115
79
  private
116
80
 
117
- def guard_line(data) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
81
+ def guard_line(data) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
118
82
  # FIXME: Ugly, huh?
119
83
  data[:file] && data[:line] && @search_up or return data
120
84
  data = data.merge(line: data[:line].to_i)
121
85
  data = data.merge(code_object: find_object(data[:file], data[:line]))
122
86
  lines = File.readlines(data[:file]) rescue (return data) # rubocop:disable Style/RescueModifier
123
- pattern = Regexp.new(@search_up % data.map { |k, v| [k, Regexp.escape(v.to_s)] }.to_h)
87
+ pattern = Regexp.new(@search_up % data.transform_values { |v| Regexp.escape(v.to_s) })
124
88
  _, num = lines.map
125
89
  .with_index { |ln, i| [ln, i + 1] }
126
90
  .first(data[:line]).reverse
127
- .detect { |ln, _| pattern.match(ln) }
91
+ .detect { |ln,| pattern.match(ln) }
128
92
  num or return data
129
93
 
130
94
  data.merge(line: num)
@@ -136,6 +100,7 @@ module YardJunk
136
100
  end
137
101
  end
138
102
 
103
+ # rubocop:disable Layout/LineLength
139
104
  class UnknownTag < Message
140
105
  pattern %r{^(?<message>Unknown tag (?<tag>@\S+))( in file `(?<file>[^`]+)` near line (?<line>\d+))?$}
141
106
  search_up '%{tag}(\W|$)'
@@ -261,5 +226,11 @@ module YardJunk
261
226
  pattern %r{^In file `(?<file>[^']+)':(?<line>\d+): (?<message>Cannot resolve link to (?<object>\S+) from text:\s+(?<quote>.+))$}
262
227
  search_up '%{quote}'
263
228
  end
229
+
230
+ class InvalidFileLink < Message
231
+ pattern %r{^In file `(?<file>[^']+)':(?<line>\d+): (?<message>File '(?<object>\S+)' does not exist:\s+(?<quote>.+))$}
232
+ search_up '%{quote}'
233
+ end
234
+ # rubocop:enable Layout/LineLength
264
235
  end
265
236
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'did_you_mean'
5
+ rescue LoadError # rubocop:disable Lint/SuppressedException
6
+ end
7
+
8
+ module YardJunk
9
+ class Logger
10
+ module Spellcheck
11
+ # DidYouMean changed API dramatically between 1.0 and 1.1, and different rubies have different
12
+ # versions of it bundled.
13
+ if !Kernel.const_defined?(:DidYouMean)
14
+ def spell_check(*)
15
+ []
16
+ end
17
+ elsif DidYouMean.const_defined?(:SpellCheckable) # 1.0 +
18
+ class SpellChecker < Struct.new(:error, :dictionary) # rubocop:disable Style/StructInheritance
19
+ include DidYouMean::SpellCheckable
20
+
21
+ def candidates
22
+ {error => dictionary}
23
+ end
24
+ end
25
+
26
+ def spell_check(error, dictionary)
27
+ SpellChecker.new(error, dictionary).corrections
28
+ end
29
+ elsif DidYouMean.const_defined?(:SpellChecker) # 1.1+
30
+ def spell_check(error, dictionary)
31
+ DidYouMean::SpellChecker.new(dictionary: dictionary).correct(error)
32
+ end
33
+ elsif DidYouMean.const_defined?(:BaseFinder) # < 1.0
34
+ class SpellFinder < Struct.new(:error, :dictionary) # rubocop:disable Style/StructInheritance
35
+ include DidYouMean::BaseFinder
36
+
37
+ def searches
38
+ {error => dictionary}
39
+ end
40
+ end
41
+
42
+ def spell_check(error, dictionary)
43
+ SpellFinder.new(error, dictionary).suggestions
44
+ end
45
+ else # rubocop:disable Lint/DuplicateBranch -- actually, just impossibility catcher
46
+ def spell_check(*)
47
+ []
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YardJunk
4
+ # @private
5
+ MAJOR = 0
6
+ # @private
7
+ MINOR = 0
8
+ # @private
9
+ PATCH = 8
10
+
11
+ # @private
12
+ VERSION = [MINOR, MAJOR, PATCH].join('.')
13
+ end
@@ -1,6 +1,8 @@
1
+ require_relative 'lib/yard-junk/version'
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = 'yard-junk'
3
- s.version = '0.0.3'
5
+ s.version = YardJunk::VERSION
4
6
  s.authors = ['Victor Shepelev']
5
7
  s.email = 'zverok.offline@gmail.com'
6
8
  s.homepage = 'https://github.com/zverok/junk_yard'
@@ -11,7 +13,7 @@ Gem::Specification.new do |s|
11
13
  EOF
12
14
  s.licenses = ['MIT']
13
15
 
14
- s.required_ruby_version = '>= 2.1.0'
16
+ s.required_ruby_version = '>= 2.5.0'
15
17
 
16
18
  s.files = `git ls-files`.split($RS).reject do |file|
17
19
  file =~ /^(?:
@@ -31,19 +33,20 @@ Gem::Specification.new do |s|
31
33
  s.bindir = 'exe'
32
34
  s.executables << 'yard-junk'
33
35
 
34
- s.add_dependency 'rainbow'
35
36
  s.add_dependency 'yard'
36
- s.add_dependency 'did_you_mean'
37
- s.add_dependency 'backports'
37
+ s.add_dependency 'did_you_mean' if RUBY_VERSION < '2.3'
38
+ s.add_dependency 'backports', '>= 3.18'
39
+ s.add_dependency 'rainbow'
38
40
 
39
- s.add_development_dependency 'rubocop', '>= 0.49'
41
+ s.add_development_dependency 'rubocop'
40
42
  s.add_development_dependency 'rspec', '>= 3'
41
- s.add_development_dependency 'rubocop-rspec', '= 1.15.1' # 1.16.0 is broken on JRuby
43
+ s.add_development_dependency 'rubocop-rspec'
42
44
  s.add_development_dependency 'rspec-its', '~> 1'
43
- #s.add_development_dependency 'saharspec' # saharspec is moving target!
45
+ s.add_development_dependency 'saharspec'
44
46
  s.add_development_dependency 'fakefs'
45
47
  s.add_development_dependency 'simplecov', '~> 0.9'
46
48
  s.add_development_dependency 'rake'
47
49
  s.add_development_dependency 'rubygems-tasks'
48
50
  s.add_development_dependency 'yard'
51
+ s.add_development_dependency 'kramdown'
49
52
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard-junk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Shepelev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-07 00:00:00.000000000 Z
11
+ date: 2020-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rainbow
14
+ name: yard
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,21 +25,21 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: yard
28
+ name: backports
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '3.18'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '3.18'
41
41
  - !ruby/object:Gem::Dependency
42
- name: did_you_mean
42
+ name: rainbow
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,13 +53,13 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: backports
56
+ name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- type: :runtime
62
+ type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
@@ -67,61 +67,61 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rubocop
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '0.49'
75
+ version: '3'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '0.49'
82
+ version: '3'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rspec
84
+ name: rubocop-rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '3'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '3'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rubocop-rspec
98
+ name: rspec-its
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '='
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 1.15.1
103
+ version: '1'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '='
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 1.15.1
110
+ version: '1'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rspec-its
112
+ name: saharspec
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '1'
117
+ version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '1'
124
+ version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: fakefs
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -192,6 +192,20 @@ dependencies:
192
192
  - - ">="
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: kramdown
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
195
209
  description: " YardJunk is structured logger/error validator plugin for YARD documentation
196
210
  gem.\n"
197
211
  email: zverok.offline@gmail.com
@@ -200,7 +214,9 @@ executables:
200
214
  extensions: []
201
215
  extra_rdoc_files: []
202
216
  files:
217
+ - ".github/workflows/ci.yml"
203
218
  - Changelog.md
219
+ - Gemfile.lock
204
220
  - README.md
205
221
  - examples/bare_log.rb
206
222
  - examples/formatted_log.rb
@@ -215,9 +231,12 @@ files:
215
231
  - lib/yard-junk/janitor/html_reporter.rb
216
232
  - lib/yard-junk/janitor/resolver.rb
217
233
  - lib/yard-junk/janitor/text_reporter.rb
234
+ - lib/yard-junk/janitor/yard_options.rb
218
235
  - lib/yard-junk/logger.rb
219
236
  - lib/yard-junk/logger/message.rb
237
+ - lib/yard-junk/logger/spellcheck.rb
220
238
  - lib/yard-junk/rake.rb
239
+ - lib/yard-junk/version.rb
221
240
  - yard-junk.gemspec
222
241
  homepage: https://github.com/zverok/junk_yard
223
242
  licenses:
@@ -231,15 +250,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
231
250
  requirements:
232
251
  - - ">="
233
252
  - !ruby/object:Gem::Version
234
- version: 2.1.0
253
+ version: 2.5.0
235
254
  required_rubygems_version: !ruby/object:Gem::Requirement
236
255
  requirements:
237
256
  - - ">="
238
257
  - !ruby/object:Gem::Version
239
258
  version: '0'
240
259
  requirements: []
241
- rubyforge_project:
242
- rubygems_version: 2.6.10
260
+ rubygems_version: 3.0.3
243
261
  signing_key:
244
262
  specification_version: 4
245
263
  summary: Get rid of the junk in your YARD docs