Module: SimpleCov::CLI::Badge::Svg

Extended by:
Svg
Included in:
Svg
Defined in:
lib/simplecov/cli/badge/svg.rb

Overview

Renders the badge SVG in shields.io's flat style: 20px tall with 3px rounded corners, the label on #555 and the value on its ladder color, each text drawn twice for the drop shadow at 10x scale. textLength pins the layout, so the estimated segment widths never let glyphs spill.

Constant Summary collapse

COLORS =
[[90, "#4c1"], [80, "#97ca00"], [70, "#a4a61d"], [60, "#dfb317"], [50, "#fe7d37"]].freeze

Instance Method Summary collapse

Instance Method Details

#color(percent) ⇒ Object



15
16
17
18
# File 'lib/simplecov/cli/badge/svg.rb', line 15

def color(percent)
  rung = COLORS.detect { |floor, _color| percent >= floor }
  rung ? rung.fetch(1) : "#e05d44"
end

#document(label:, value:, fill:, geo:) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/simplecov/cli/badge/svg.rb', line 44

def document(label:, value:, fill:, geo:)
  "    <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"\#{geo.fetch(:total)}\" height=\"20\" role=\"img\" aria-label=\"\#{label}: \#{value}\">\n      <title>\#{label}: \#{value}</title>\n      <linearGradient id=\"s\" x2=\"0\" y2=\"100%\">\n        <stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>\n        <stop offset=\"1\" stop-opacity=\".1\"/>\n      </linearGradient>\n      <clipPath id=\"r\"><rect width=\"\#{geo.fetch(:total)}\" height=\"20\" rx=\"3\" fill=\"#fff\"/></clipPath>\n      <g clip-path=\"url(#r)\">\n        <rect width=\"\#{geo.fetch(:label_width)}\" height=\"20\" fill=\"#555\"/>\n        <rect x=\"\#{geo.fetch(:label_width)}\" width=\"\#{geo.fetch(:value_width)}\" height=\"20\" fill=\"\#{fill}\"/>\n        <rect width=\"\#{geo.fetch(:total)}\" height=\"20\" fill=\"url(#s)\"/>\n      </g>\n      <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"Verdana,Geneva,DejaVu Sans,sans-serif\" text-rendering=\"geometricPrecision\" font-size=\"110\">\n        <text aria-hidden=\"true\" x=\"\#{geo.fetch(:label_x)}\" y=\"150\" fill=\"#010101\" fill-opacity=\".3\" transform=\"scale(.1)\" textLength=\"\#{geo.fetch(:label_span)}\">\#{label}</text>\n        <text x=\"\#{geo.fetch(:label_x)}\" y=\"140\" transform=\"scale(.1)\" fill=\"#fff\" textLength=\"\#{geo.fetch(:label_span)}\">\#{label}</text>\n        <text aria-hidden=\"true\" x=\"\#{geo.fetch(:value_x)}\" y=\"150\" fill=\"#010101\" fill-opacity=\".3\" transform=\"scale(.1)\" textLength=\"\#{geo.fetch(:value_span)}\">\#{value}</text>\n        <text x=\"\#{geo.fetch(:value_x)}\" y=\"140\" transform=\"scale(.1)\" fill=\"#fff\" textLength=\"\#{geo.fetch(:value_span)}\">\#{value}</text>\n      </g>\n    </svg>\n  SVG\nend\n"

#escape(text) ⇒ Object



40
41
42
# File 'lib/simplecov/cli/badge/svg.rb', line 40

def escape(text)
  text.gsub(/[&<>"]/, "&" => "&amp;", "<" => "&lt;", ">" => "&gt;", '"' => "&quot;")
end

#geometry(label_width, value_width) ⇒ Object

The scale(.1) trick draws text at 10x and shrinks it, so the text coordinates live in a 10x space: centers at 10 * (offset + width / 2) and textLength spanning the width less padding.



34
35
36
37
38
# File 'lib/simplecov/cli/badge/svg.rb', line 34

def geometry(label_width, value_width)
  {label_width: label_width, value_width: value_width, total: label_width + value_width,
   label_x: 5 * label_width, value_x: (10 * label_width) + (5 * value_width),
   label_span: 10 * (label_width - 10), value_span: 10 * (value_width - 10)}
end

#render(label:, percent:) ⇒ Object



20
21
22
23
24
# File 'lib/simplecov/cli/badge/svg.rb', line 20

def render(label:, percent:)
  value = format("%.2f%%", percent)
  document(label: escape(label), value: value, fill: color(percent),
    geo: geometry(width(label), width(value)))
end

#width(text) ⇒ Object

Estimates 11px Verdana; textLength absorbs the error.



27
28
29
# File 'lib/simplecov/cli/badge/svg.rb', line 27

def width(text)
  (7 * text.length) + 10
end