Module: SimpleCov::CLI::Show::Annotator

Extended by:
Annotator
Included in:
Annotator
Defined in:
lib/simplecov/cli/show/annotator.rb

Overview

Renders one file's annotated source: a right-aligned line-number gutter, the hit count beside it, and a caret line naming each miss under the line it happened on.

Instance Method Summary collapse

Instance Method Details

#call(source, entry, stdout, color:) ⇒ Object



12
13
14
15
16
17
18
19
# File 'lib/simplecov/cli/show/annotator.rb', line 12

def call(source, entry, stdout, color:)
  markers = markers_for(entry)
  widths = {number: source.size.to_s.length, count: count_width(entry)}
  source.each_with_index do |line, index|
    rendered = row(index + 1, entry.fetch("lines").at(index), line, widths, color)
    emit(stdout, rendered, markers[index + 1], widths, color)
  end
end

#count(hit, widths, color) ⇒ Object

Padded to width before it is painted, so escape codes can't skew the column, and blank for a line carrying no count.



74
75
76
77
78
79
# File 'lib/simplecov/cli/show/annotator.rb', line 74

def count(hit, widths, color)
  padded = (hit.instance_of?(Integer) ? hit.to_s : "").rjust(widths.fetch(:count))
  return padded unless hit.instance_of?(Integer)

  paint(padded, hit.zero? ? :red : :green, color)
end

#count_width(entry) ⇒ Object



64
65
66
# File 'lib/simplecov/cli/show/annotator.rb', line 64

def count_width(entry)
  entry.fetch("lines").grep(Integer) { |hit| hit.to_s.length }.max || 1
end

#each_missed(items) ⇒ Object



43
44
45
46
47
48
49
50
# File 'lib/simplecov/cli/show/annotator.rb', line 43

def each_missed(items)
  return unless items.instance_of?(Array)

  items.each do |item|
    line = missed_line_of(item)
    yield line if line
  end
end

#emit(stdout, rendered, labels, widths, color) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/simplecov/cli/show/annotator.rb', line 21

def emit(stdout, rendered, labels, widths, color)
  stdout.puts(rendered)
  return if labels.empty?

  gutter = " " * (widths.fetch(:number) + widths.fetch(:count) + 4)
  stdout.puts(gutter + paint("^ #{labels.join(", ")}", :red, color))
end

#markers_for(entry) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/simplecov/cli/show/annotator.rb', line 35

def markers_for(entry)
  markers = Hash.new { |hash, line| hash[line] = [] } #: Hash[Integer, Array[String]]
  missed_lines(entry).each { |line| markers[line] << "missed" }
  each_missed(entry["branches"]) { |line| markers[line] << "branch missed" }
  each_missed(entry["methods"]) { |line| markers[line] << "method missed" }
  markers
end

#missed_line_of(item) ⇒ Object

The reported line of a zero-hit item, nil for a covered or malformed one, the same tolerance the patch subcommand applies to branch entries.



54
55
56
57
58
59
60
61
62
# File 'lib/simplecov/cli/show/annotator.rb', line 54

def missed_line_of(item)
  return nil unless item.instance_of?(Hash)

  hits = item["coverage"]
  return nil unless hits.instance_of?(Integer) && hits.zero?

  line = item["report_line"] || item["start_line"]
  line if line.instance_of?(Integer)
end

#missed_lines(entry) ⇒ Object



29
30
31
32
33
# File 'lib/simplecov/cli/show/annotator.rb', line 29

def missed_lines(entry)
  entry.fetch("lines").each_with_index.filter_map do |hit, index|
    index + 1 if hit.instance_of?(Integer) && hit.zero?
  end
end

#paint(text, tint, color) ⇒ Object



81
82
83
# File 'lib/simplecov/cli/show/annotator.rb', line 81

def paint(text, tint, color)
  Color.colorize(text, tint, enabled: color)
end

#row(number, hit, line, widths, color) ⇒ Object



68
69
70
# File 'lib/simplecov/cli/show/annotator.rb', line 68

def row(number, hit, line, widths, color)
  format("%#{widths.fetch(:number)}d  %s  %s", number, count(hit, widths, color), line).rstrip
end