Module: SimpleCov::CLI::History::Output
Overview
Renders the trend: Unicode sparklines scaled to each series' own range, with the numbers beside them carrying the absolute scale.
Constant Summary collapse
- BARS =
%w[▁ ▂ ▃ ▄ ▅ ▆ ▇ █].freeze
- CRITERIA_ORDER =
%w[line branch method].freeze
Instance Method Summary collapse
- #bar(value, min, span) ⇒ Object
- #branch_of(entry) ⇒ Object
- #emit(stdout, opts, entries, color:) ⇒ Object
- #emit_criteria_views(stdout, entries, color, *path) ⇒ Object
- #emit_file(stdout, opts, entries, color) ⇒ Object
- #emit_json(stdout, opts, entries) ⇒ Object
- #emit_rows(stdout, entries) ⇒ Object
- #emit_sparklines(stdout, entries, criteria, color, path) ⇒ Object
- #emit_totals(stdout, opts, entries, color) ⇒ Object
-
#measured_criteria(entries, path) ⇒ Object
Criteria some run recorded a number for, in canonical order, so a criterion enabled midway still gets its sparkline.
- #numeric(value) ⇒ Object
- #percents_cell(entry, criteria, path) ⇒ Object
- #pluralize(number, noun) ⇒ Object
-
#sparkline(series) ⇒ Object
Min-max scaled block characters, one per run, a space where the series has no value for that run.
- #trend(series, color) ⇒ Object
Instance Method Details
#bar(value, min, span) ⇒ Object
88 89 90 |
# File 'lib/simplecov/cli/history/output.rb', line 88 def (value, min, span) span.zero? ? BARS.fetch(3) : BARS.fetch(((value - min) / span * (BARS.length - 1)).round) end |
#branch_of(entry) ⇒ Object
62 63 64 |
# File 'lib/simplecov/cli/history/output.rb', line 62 def branch_of(entry) entry["branch"] || "-" end |
#emit(stdout, opts, entries, color:) ⇒ Object
15 16 17 18 19 20 21 22 23 24 |
# File 'lib/simplecov/cli/history/output.rb', line 15 def emit(stdout, opts, entries, color:) return emit_json(stdout, opts, entries) if opts.fetch(:json) return stdout.puts("simplecov history: no recorded runs in #{opts.fetch(:input)}") if entries.empty? if opts.fetch(:file) emit_file(stdout, opts, entries, color) else emit_totals(stdout, opts, entries, color) end end |
#emit_criteria_views(stdout, entries, color, *path) ⇒ Object
39 40 41 42 43 44 |
# File 'lib/simplecov/cli/history/output.rb', line 39 def emit_criteria_views(stdout, entries, color, *path) criteria = measured_criteria(entries, path) emit_sparklines(stdout, entries, criteria, color, path) stdout.puts emit_rows(stdout, entries) { |entry| percents_cell(entry, criteria, path) } end |
#emit_file(stdout, opts, entries, color) ⇒ Object
32 33 34 35 36 37 |
# File 'lib/simplecov/cli/history/output.rb', line 32 def emit_file(stdout, opts, entries, color) file = opts.fetch(:file) stdout.puts("Coverage history for #{file} (#{pluralize(entries.length, "run")})") stdout.puts emit_criteria_views(stdout, entries, color, "files", file) end |
#emit_json(stdout, opts, entries) ⇒ Object
102 103 104 105 106 107 108 109 110 111 |
# File 'lib/simplecov/cli/history/output.rb', line 102 def emit_json(stdout, opts, entries) return stdout.puts(JSON.generate(entries)) unless opts.fetch(:file) rows = entries.map do |entry| percents = entry.dig("files", opts.fetch(:file)) {created_at: entry["created_at"], branch: entry["branch"], commit: entry["commit"], percents: (percents if percents.instance_of?(Hash))} end stdout.puts(JSON.generate(rows)) end |
#emit_rows(stdout, entries) ⇒ Object
54 55 56 57 58 59 60 |
# File 'lib/simplecov/cli/history/output.rb', line 54 def emit_rows(stdout, entries) width = entries.map { |entry| branch_of(entry).length }.max entries.each do |entry| commit = (entry["commit"] || "-")[0, 7].ljust(7) stdout.puts(" #{entry["created_at"]} #{branch_of(entry).ljust(width)} #{commit} #{yield(entry)}") end end |
#emit_sparklines(stdout, entries, criteria, color, path) ⇒ Object
46 47 48 49 50 51 52 |
# File 'lib/simplecov/cli/history/output.rb', line 46 def emit_sparklines(stdout, entries, criteria, color, path) width = criteria.map(&:length).max criteria.each do |criterion| series = entries.map { |entry| numeric(entry.dig(*path, criterion)) } stdout.puts(" #{criterion.ljust(width)} #{sparkline(series)} #{trend(series, color)}") end end |
#emit_totals(stdout, opts, entries, color) ⇒ Object
26 27 28 29 30 |
# File 'lib/simplecov/cli/history/output.rb', line 26 def emit_totals(stdout, opts, entries, color) stdout.puts("Coverage history: #{opts.fetch(:input)} (#{pluralize(entries.length, "run")})") stdout.puts emit_criteria_views(stdout, entries, color, "totals") end |
#measured_criteria(entries, path) ⇒ Object
Criteria some run recorded a number for, in canonical order, so a criterion enabled midway still gets its sparkline. One no run recorded is left out: an all-gaps sparkline has no trend to read off it.
116 117 118 119 120 121 122 123 |
# File 'lib/simplecov/cli/history/output.rb', line 116 def measured_criteria(entries, path) CRITERIA_ORDER.select do |criterion| entries.any? do |entry| percents = entry.dig(*path) percents.instance_of?(Hash) && numeric(percents[criterion]) end end end |
#numeric(value) ⇒ Object
125 126 127 |
# File 'lib/simplecov/cli/history/output.rb', line 125 def numeric(value) value if value.is_a?(Numeric) end |
#percents_cell(entry, criteria, path) ⇒ Object
66 67 68 69 70 71 72 |
# File 'lib/simplecov/cli/history/output.rb', line 66 def percents_cell(entry, criteria, path) cell = criteria.filter_map do |criterion| value = numeric(entry.dig(*path, criterion)) "#{criterion} #{value}%" if value end.join(" ") cell.empty? ? "-" : cell end |
#pluralize(number, noun) ⇒ Object
129 130 131 |
# File 'lib/simplecov/cli/history/output.rb', line 129 def pluralize(number, noun) "#{number} #{noun}#{"s" unless number.eql?(1)}" end |
#sparkline(series) ⇒ Object
Min-max scaled block characters, one per run, a space where the series has no value for that run. A flat series renders at mid height: direction of travel is the message, and a flat line says it plainly. A series with no numbers at all is all gaps, and answering that outright keeps the scale off a range it doesn't have.
79 80 81 82 83 84 85 86 |
# File 'lib/simplecov/cli/history/output.rb', line 79 def sparkline(series) numeric = series.compact return " " * series.length if numeric.empty? min = numeric.min span = numeric.max - min.to_f series.map { |value| value.nil? ? " " : (value, min, span) }.join end |
#trend(series, color) ⇒ Object
92 93 94 95 96 97 98 99 100 |
# File 'lib/simplecov/cli/history/output.rb', line 92 def trend(series, color) numeric = series.compact first = numeric.first last = numeric.last delta = (last - first).round(2) sign = "+" unless delta.negative? delta_text = Color.colorize("(#{sign}#{delta})", delta.negative? ? :red : :green, enabled: color) "#{first}% → #{last}% #{delta_text}" end |