Skip to content

Commit

Permalink
Implement a StatsReporter
Browse files Browse the repository at this point in the history
  • Loading branch information
srawlins authored and sds committed Apr 6, 2016
1 parent 058b33f commit a7ddae5
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,24 @@ not ok 4 - not-ok2.scss:21:3 SCSSLint::Linter::PrivateNamingConvention
ok 5 - ok2.scss
```

### Stats

Outputs statistics about how many lints of each type were found, and across how many files. This
reporter can help in cleaning up a large codebase, allowing you to fix and then enable one lint
type at a time.

```
15 ColorKeyword (across 1 files)
15 ColorVariable (across 1 files)
11 StringQuotes (across 11 files)
11 EmptyLineBetweenBlocks (across 11 files)
5 Indentation (across 1 files)
5 QualifyingElement (across 2 files)
4 MergeableSelector (across 1 files)
-- ---------------------- -----------------
66 total (across 12 files)
```

### Plugins

There are also formatters that integrate with third-party tools which are available as plugins.
Expand Down
39 changes: 39 additions & 0 deletions lib/scss_lint/reporter/stats_reporter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module SCSSLint
# Reports a single line per lint.
class Reporter::StatsReporter < Reporter
def report_lints # rubocop:disable Metrics/AbcSize
return unless lints.any?

stats = organize_stats
total_lints = lints.length
linter_name_length =
stats.inject('') { |memo, stat| memo.length > stat[0].length ? memo : stat[0] }.length
total_files = lints.group_by(&:filename).size

# Math.log10(1) is 0; avoid this by using at least 1.
lint_count_length = [1, Math.log10(total_lints).ceil].max
file_count_length = [1, Math.log10(total_files).ceil].max

str = ''
stats.each do |linter_name, lint_count, file_count|
str << "%#{lint_count_length}d %-#{linter_name_length}s" % [lint_count, linter_name]
str << " (across %#{file_count_length}d files)\n" % [file_count]
end
str << "#{'-' * lint_count_length} #{'-' * linter_name_length}"
str << " #{'-' * (file_count_length + 15)}\n"
str << "%#{lint_count_length}d #{'total'.ljust(linter_name_length)}" % total_lints
str << " (across %#{file_count_length}d files)\n" % total_files
str
end

def organize_stats
lints
.group_by(&:linter)
.sort_by { |_, lints_by_linter| -lints_by_linter.size }
.inject([]) do |ary, (linter, lints_by_linter)|
file_count = lints_by_linter.group_by(&:filename).size
ary << [linter.name, lints_by_linter.size, file_count]
end
end
end
end
115 changes: 115 additions & 0 deletions spec/scss_lint/reporter/stats_reporter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
require 'spec_helper'

describe SCSSLint::Reporter::StatsReporter do
class SCSSLint::Linter::FakeLinter1 < SCSSLint::Linter; end
class SCSSLint::Linter::FakeLinter2 < SCSSLint::Linter; end

let(:logger) { SCSSLint::Logger.new($stdout) }
let(:linter_1) { SCSSLint::Linter::FakeLinter1.new }
let(:linter_2) { SCSSLint::Linter::FakeLinter2.new }
subject { SCSSLint::Reporter::StatsReporter.new(lints, [], logger) }

def new_lint(linter, filename, line)
SCSSLint::Lint.new(linter, filename, SCSSLint::Location.new(line), 'Description', :warning)
end

describe '#report_lints' do
context 'when there are no lints' do
let(:lints) { [] }

it 'returns nil' do
subject.report_lints.should be_nil
end
end

context 'when there are lints from one linter in one file' do
let(:lints) do
[new_lint(linter_1, 'a.scss', 10), new_lint(linter_1, 'a.scss', 20)]
end

it 'prints one line per linter with lints, plus 2 summary lines' do
subject.report_lints.count("\n").should eq 3
end

it 'prints the name of each linter with lints' do
subject.report_lints.scan(linter_1.name).count.should eq 1
end

it 'prints the number of lints per linter' do
subject.report_lints.should include '2 FakeLinter1'
end

it 'prints the number of files where each linter found lints' do
subject.report_lints.should include '1 files'
end

it 'prints the total lints and total lines' do
subject.report_lints.should match /2 total +\(across 1/
end
end

context 'when there are lints from multiple linters in one file' do
let(:lints) do
[new_lint(linter_1, 'a.scss', 10),
new_lint(linter_1, 'a.scss', 20),
new_lint(linter_2, 'a.scss', 30)]
end

it 'prints one line per linter with lints, plus 2 summary lines' do
subject.report_lints.count("\n").should eq 4
end

it 'prints the name of each linter with lints' do
subject.report_lints.scan(linter_1.name).count.should eq 1
subject.report_lints.scan(linter_2.name).count.should eq 1
end

it 'prints the number of lints per linter' do
subject.report_lints.should include '2 FakeLinter1'
subject.report_lints.should include '1 FakeLinter2'
end

it 'prints the number of files where each linter found lints' do
subject.report_lints.scan(/FakeLinter\d +\(across 1 files/).count.should eq 2
end

it 'prints the total lints and total lines' do
subject.report_lints.should match /3 total +\(across 1/
end
end

context 'when there are lints from multiple linters in multiple files' do
let(:lints) do
[new_lint(linter_1, 'a.scss', 10),
new_lint(linter_1, 'a.scss', 20),
new_lint(linter_2, 'a.scss', 30),
new_lint(linter_1, 'b.scss', 15),
new_lint(linter_2, 'b.scss', 25),
new_lint(linter_1, 'c.scss', 100)]
end

it 'prints one line per linter with lints, plus 2 summary lines' do
subject.report_lints.count("\n").should eq 4
end

it 'prints the name of each linter with lints' do
subject.report_lints.scan(linter_1.name).count.should eq 1
subject.report_lints.scan(linter_2.name).count.should eq 1
end

it 'prints the number of lints per linter' do
subject.report_lints.should include '4 FakeLinter1'
subject.report_lints.should include '2 FakeLinter2'
end

it 'prints the number of files where each linter found lints' do
subject.report_lints.scan(/FakeLinter2 +\(across 2 files/).count.should eq 1
subject.report_lints.scan(/FakeLinter1 +\(across 3 files/).count.should eq 1
end

it 'prints the total lints and total lines' do
subject.report_lints.should match /6 total +\(across 3/
end
end
end
end

0 comments on commit a7ddae5

Please sign in to comment.