tessella 0.3.0

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.
Files changed (188) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +900 -0
  4. data/doc/README.md +74 -0
  5. data/doc/bitfield.md +123 -0
  6. data/doc/charts.md +1370 -0
  7. data/doc/check.rb +75 -0
  8. data/doc/cli.md +483 -0
  9. data/doc/composition.md +599 -0
  10. data/doc/getting-started.md +121 -0
  11. data/doc/glyphs.md +134 -0
  12. data/doc/images.md +325 -0
  13. data/doc/library.md +239 -0
  14. data/doc/lint.md +270 -0
  15. data/doc/meter.md +210 -0
  16. data/doc/rule.md +51 -0
  17. data/doc/seq.md +169 -0
  18. data/doc/sparkline.md +63 -0
  19. data/doc/table.md +347 -0
  20. data/doc/targets.md +222 -0
  21. data/doc/text.md +84 -0
  22. data/doc/tree.md +108 -0
  23. data/doc/wave.md +122 -0
  24. data/examples/README.md +103 -0
  25. data/examples/ages.txt +9 -0
  26. data/examples/bad.csv +3 -0
  27. data/examples/boxes.txt +3 -0
  28. data/examples/broken.txt +4 -0
  29. data/examples/calibration.rb +12 -0
  30. data/examples/cities.csv +4 -0
  31. data/examples/cjk.rb +13 -0
  32. data/examples/comment.rb +9 -0
  33. data/examples/comment.sh +13 -0
  34. data/examples/cpu.txt +60 -0
  35. data/examples/dashboard.sh +25 -0
  36. data/examples/datasheet.rb +16 -0
  37. data/examples/disc.pgm +0 -0
  38. data/examples/disks.sh +18 -0
  39. data/examples/disks.txt +5 -0
  40. data/examples/dose.txt +7 -0
  41. data/examples/drift.txt +4 -0
  42. data/examples/ethernet.txt +3 -0
  43. data/examples/figure.c +5 -0
  44. data/examples/fit.rb +16 -0
  45. data/examples/floors.rb +21 -0
  46. data/examples/gallery.sh +20 -0
  47. data/examples/gauges.sh +31 -0
  48. data/examples/gradient.rb +16 -0
  49. data/examples/growth.txt +6 -0
  50. data/examples/hosts.csv +4 -0
  51. data/examples/icmp.txt +3 -0
  52. data/examples/ipv4.txt +12 -0
  53. data/examples/kinds.csv +4 -0
  54. data/examples/langs.csv +4 -0
  55. data/examples/lint.rb +16 -0
  56. data/examples/load.rb +14 -0
  57. data/examples/login.txt +10 -0
  58. data/examples/neg.csv +4 -0
  59. data/examples/normal.txt +200 -0
  60. data/examples/note.txt +2 -0
  61. data/examples/notes-fixed.md +17 -0
  62. data/examples/notes.md +17 -0
  63. data/examples/ohlc.txt +7 -0
  64. data/examples/os.csv +10 -0
  65. data/examples/outline.txt +8 -0
  66. data/examples/plot.txt +5 -0
  67. data/examples/refusals.rb +17 -0
  68. data/examples/report.sh +21 -0
  69. data/examples/rfc.sh +22 -0
  70. data/examples/samples.txt +7 -0
  71. data/examples/shapes.pgm +0 -0
  72. data/examples/sizes.tsv +3 -0
  73. data/examples/spi.txt +6 -0
  74. data/examples/status.sh +23 -0
  75. data/examples/stem.txt +12 -0
  76. data/examples/table-drift.txt +4 -0
  77. data/examples/temps.txt +31 -0
  78. data/examples/trig.sh +13 -0
  79. data/examples/trig.txt +102 -0
  80. data/examples/week.txt +8 -0
  81. data/examples/wide.txt +2 -0
  82. data/exe/tessella +6 -0
  83. data/lib/tessella/axis.rb +71 -0
  84. data/lib/tessella/bitfield.rb +194 -0
  85. data/lib/tessella/block.rb +56 -0
  86. data/lib/tessella/borders.rb +85 -0
  87. data/lib/tessella/canvas/area.rb +155 -0
  88. data/lib/tessella/canvas/ascii.rb +120 -0
  89. data/lib/tessella/canvas/block.rb +40 -0
  90. data/lib/tessella/canvas/braille.rb +30 -0
  91. data/lib/tessella/canvas/clip.rb +49 -0
  92. data/lib/tessella/canvas/density.rb +51 -0
  93. data/lib/tessella/canvas/dot.rb +27 -0
  94. data/lib/tessella/canvas/eighths.rb +43 -0
  95. data/lib/tessella/canvas/half.rb +51 -0
  96. data/lib/tessella/canvas/sextant.rb +36 -0
  97. data/lib/tessella/canvas.rb +168 -0
  98. data/lib/tessella/cell.rb +10 -0
  99. data/lib/tessella/chart.rb +211 -0
  100. data/lib/tessella/check.rb +52 -0
  101. data/lib/tessella/cli/bitfield.rb +121 -0
  102. data/lib/tessella/cli/chart.rb +615 -0
  103. data/lib/tessella/cli/chart_candle.rb +36 -0
  104. data/lib/tessella/cli/chart_heatmap.rb +21 -0
  105. data/lib/tessella/cli/chart_help.rb +85 -0
  106. data/lib/tessella/cli/chart_pie.rb +38 -0
  107. data/lib/tessella/cli/compose.rb +156 -0
  108. data/lib/tessella/cli/compose_options.rb +259 -0
  109. data/lib/tessella/cli/glyphs.rb +97 -0
  110. data/lib/tessella/cli/image.rb +250 -0
  111. data/lib/tessella/cli/input.rb +44 -0
  112. data/lib/tessella/cli/iso_time.rb +28 -0
  113. data/lib/tessella/cli/lint.rb +102 -0
  114. data/lib/tessella/cli/lint_options.rb +99 -0
  115. data/lib/tessella/cli/main.rb +121 -0
  116. data/lib/tessella/cli/meter.rb +80 -0
  117. data/lib/tessella/cli/rule.rb +57 -0
  118. data/lib/tessella/cli/seq.rb +117 -0
  119. data/lib/tessella/cli/sparkline.rb +72 -0
  120. data/lib/tessella/cli/table.rb +167 -0
  121. data/lib/tessella/cli/text.rb +78 -0
  122. data/lib/tessella/cli/tree.rb +100 -0
  123. data/lib/tessella/cli/wave.rb +148 -0
  124. data/lib/tessella/cli.rb +36 -0
  125. data/lib/tessella/color.rb +106 -0
  126. data/lib/tessella/compose.rb +243 -0
  127. data/lib/tessella/compose_fill.rb +176 -0
  128. data/lib/tessella/compose_grid.rb +36 -0
  129. data/lib/tessella/compose_shadow.rb +41 -0
  130. data/lib/tessella/error.rb +13 -0
  131. data/lib/tessella/frame.rb +170 -0
  132. data/lib/tessella/glyphs.rb +106 -0
  133. data/lib/tessella/image.rb +454 -0
  134. data/lib/tessella/image_octant.rb +46 -0
  135. data/lib/tessella/image_petscii.rb +116 -0
  136. data/lib/tessella/kinds/bar.rb +344 -0
  137. data/lib/tessella/kinds/box.rb +213 -0
  138. data/lib/tessella/kinds/box_upright.rb +110 -0
  139. data/lib/tessella/kinds/candlestick.rb +164 -0
  140. data/lib/tessella/kinds/columns.rb +259 -0
  141. data/lib/tessella/kinds/date_axis.rb +102 -0
  142. data/lib/tessella/kinds/error_bars.rb +71 -0
  143. data/lib/tessella/kinds/heatmap.rb +130 -0
  144. data/lib/tessella/kinds/line.rb +173 -0
  145. data/lib/tessella/kinds/multibar.rb +98 -0
  146. data/lib/tessella/kinds/multibar_columns.rb +130 -0
  147. data/lib/tessella/kinds/multibar_fine.rb +45 -0
  148. data/lib/tessella/kinds/multibar_rows.rb +93 -0
  149. data/lib/tessella/kinds/pie.rb +123 -0
  150. data/lib/tessella/kinds/pie_rim.rb +78 -0
  151. data/lib/tessella/kinds/sideways.rb +62 -0
  152. data/lib/tessella/kinds/stem.rb +134 -0
  153. data/lib/tessella/kinds/threshold.rb +73 -0
  154. data/lib/tessella/legend.rb +31 -0
  155. data/lib/tessella/lint/alphabet.rb +56 -0
  156. data/lib/tessella/lint/drift.rb +82 -0
  157. data/lib/tessella/lint/fences.rb +51 -0
  158. data/lib/tessella/lint/geometry.rb +120 -0
  159. data/lib/tessella/lint/geometry_checks.rb +224 -0
  160. data/lib/tessella/lint/lines.rb +115 -0
  161. data/lib/tessella/lint/mixing.rb +61 -0
  162. data/lib/tessella/lint/runner.rb +73 -0
  163. data/lib/tessella/lint/shadows.rb +120 -0
  164. data/lib/tessella/lint/target_rows.rb +66 -0
  165. data/lib/tessella/lint.rb +158 -0
  166. data/lib/tessella/meter.rb +133 -0
  167. data/lib/tessella/meter_upright.rb +43 -0
  168. data/lib/tessella/png.rb +456 -0
  169. data/lib/tessella/raster.rb +92 -0
  170. data/lib/tessella/rmagick_reader.rb +52 -0
  171. data/lib/tessella/rule.rb +59 -0
  172. data/lib/tessella/seq.rb +522 -0
  173. data/lib/tessella/sparkline.rb +57 -0
  174. data/lib/tessella/stats.rb +199 -0
  175. data/lib/tessella/table.rb +547 -0
  176. data/lib/tessella/table_cells.rb +225 -0
  177. data/lib/tessella/target.rb +105 -0
  178. data/lib/tessella/text.rb +76 -0
  179. data/lib/tessella/text_forms.rb +150 -0
  180. data/lib/tessella/tree.rb +221 -0
  181. data/lib/tessella/version.rb +5 -0
  182. data/lib/tessella/wave.rb +353 -0
  183. data/lib/tessella/width.rb +122 -0
  184. data/lib/tessella/width_class.rb +77 -0
  185. data/lib/tessella/width_invisible.rb +66 -0
  186. data/lib/tessella/width_invisible_high.rb +60 -0
  187. data/lib/tessella.rb +94 -0
  188. metadata +226 -0
data/doc/meter.md ADDED
@@ -0,0 +1,210 @@
1
+ # Meters
2
+
3
+ `meter` draws one line: a bar filled to a fraction, between brackets,
4
+ with its percentage after it. A progress line in a log, a gauge in a
5
+ status report, a column of them in a dashboard.
6
+
7
+ ```ruby
8
+ Tessella.meter(fraction, style: :block, width: 20, title: nil,
9
+ title_width: nil, label: true, brackets: true,
10
+ orientation: :horizontal, height: 8,
11
+ ascii: false) # => Block
12
+ ```
13
+
14
+ ```text
15
+ tessella meter [--style S] [--width N] [--title T] [--title-width N]
16
+ [--no-label] [--no-brackets] [--ascii]
17
+ [--orientation horizontal|vertical] [--height N] FRACTION
18
+ ```
19
+
20
+ `FRACTION` is a number from 0 to 1, or a percentage, `45%`.
21
+
22
+ ```text
23
+ $ tessella meter 0.5
24
+ [██████████··········] 50 %
25
+ ```
26
+
27
+ ```text
28
+ $ tessella meter --width 10 --title disk 37%
29
+ disk [███▊······] 37 %
30
+ ```
31
+
32
+ `--width` is the bar's cells, 20 by default. The default `block`
33
+ style fills its last cell by eighths, so a bar moves by an eighth of
34
+ a cell, not a whole one. `--no-label` drops the percentage and
35
+ `--no-brackets` the brackets:
36
+
37
+ ```text
38
+ $ tessella meter --no-label --no-brackets 0.25
39
+ █████···············
40
+ ```
41
+
42
+ ## Styles
43
+
44
+ A style is a fill glyph and a track glyph. The named ones are the
45
+ meter sets in the [registry](glyphs.md#the-registry):
46
+
47
+ ```text
48
+ $ for s in arrow chevron classic rectangle wave block box circle star; do \
49
+ tessella meter --style $s --width 12 --title $s --title-width 9 0.6; \
50
+ done
51
+ arrow [▸▸▸▸▸▸▸▹▹▹▹▹] 60 %
52
+ chevron [››››››› ] 60 %
53
+ classic [======= ] 60 %
54
+ rectangle [▮▮▮▮▮▮▮▯▯▯▯▯] 60 %
55
+ wave [~~~~~~~_____] 60 %
56
+ block [███████▎····] 60 %
57
+ box [■■■■■■■□□□□□] 60 %
58
+ circle [●●●●●●●○○○○○] 60 %
59
+ star [★★★★★★★☆☆☆☆☆] 60 %
60
+ ```
61
+
62
+ `blade` (`▰▱`) and `button` (`⦿⦾`) exist too, but many fonts lack
63
+ their glyphs: try them in the reader's font first.
64
+ `tessella glyphs meter` lists every set with its width class.
65
+
66
+ A style of one's own is two glyphs, fill then track, one column each
67
+ and of one [width class](glyphs.md#width-classes):
68
+
69
+ ```text
70
+ $ tessella meter --style '▰▱' 0.33
71
+ [▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱] 33 %
72
+ ```
73
+
74
+ ```text
75
+ $ tessella meter --style '■░' 0.5
76
+ tessella meter: meter style "■░" mixes width classes: A, N
77
+ ```
78
+
79
+ ## Upright meters
80
+
81
+ `--orientation vertical` stands the bar up: a column `--height` cells
82
+ tall (8 by default), filled from the bottom, between `─` caps (`-`
83
+ under `--ascii`, none with `--no-brackets`), the title centred above
84
+ and the percentage below. The block style tops its column with an
85
+ eighth, `▁` to `▇`. An upright meter takes `--height`, not
86
+ `--width`, and the other way round across; either one in the wrong
87
+ orientation is a usage error.
88
+
89
+ ```text
90
+ $ tessella meter --orientation vertical --height 6 --title cpu 0.62
91
+ cpu
92
+ ─
93
+ ·
94
+ ·
95
+ ▆
96
+ █
97
+ █
98
+ █
99
+ ─
100
+ 62 %
101
+ ```
102
+
103
+ Upright meters stand side by side with `compose beside`, their
104
+ bottoms aligned. `gauges.sh` draws one per line of `disks.txt`:
105
+
106
+ ```sh
107
+ #!/bin/sh
108
+ # examples/gauges.sh -- upright meters side by side, one per line of
109
+ # "name fraction", bottoms aligned: a row of gauges.
110
+ # usage: sh gauges.sh [file] (default disks.txt)
111
+ set -eu
112
+
113
+ cd -- "$(dirname -- "$0")" || exit 1
114
+ input=${1:-disks.txt}
115
+
116
+ tmpdir=
117
+ cleanup() { [ -z "$tmpdir" ] || rm -rf -- "$tmpdir"; }
118
+ trap cleanup EXIT INT HUP TERM
119
+ tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/gauges.XXXXXX") || exit 1
120
+
121
+ n=0
122
+ while read -r name fraction; do
123
+ case $name in
124
+ '' | '#'*) continue ;;
125
+ esac
126
+ n=$((n + 1))
127
+ tessella meter --orientation vertical --height 6 --title "$name" \
128
+ -- "$fraction" > "$tmpdir/$n"
129
+ done < "$input"
130
+
131
+ set --
132
+ i=1
133
+ while [ "$i" -le "$n" ]; do
134
+ set -- "$@" "$tmpdir/$i"
135
+ i=$((i + 1))
136
+ done
137
+ tessella compose beside --gap 3 --align bottom "$@"
138
+ ```
139
+
140
+ ```text
141
+ $ sh gauges.sh
142
+ / /home /var /tmp
143
+ ─ ─ ─ ─
144
+ · ▂ · ·
145
+ · █ · ·
146
+ ▆ █ · ·
147
+ █ █ · ·
148
+ █ █ ▇ ·
149
+ █ █ █ ▂
150
+ ─ ─ ─ ─
151
+ 62 % 87 % 31 % 4 %
152
+ ```
153
+
154
+ ## ASCII
155
+
156
+ `--ascii` draws the classic style, `=` on a blank track:
157
+
158
+ ```text
159
+ $ tessella meter --ascii 0.5
160
+ [========== ] 50 %
161
+ ```
162
+
163
+ ## A status board
164
+
165
+ Meters are blocks like any figure, so they stack and frame.
166
+ `--title-width N` (`title_width:`) pads a title to N columns, so a
167
+ column of meters lines up; a longer title is refused (exit 2).
168
+ `disks.sh` reads `name fraction` lines and draws one meter each:
169
+
170
+ ```sh
171
+ #!/bin/sh
172
+ # examples/disks.sh -- one meter per line of "name fraction", their
173
+ # titles padded to one width so the bars line up, framed: a small
174
+ # status board.
175
+ # usage: sh disks.sh [file] (default disks.txt)
176
+ set -eu
177
+
178
+ cd -- "$(dirname -- "$0")" || exit 1
179
+ input=${1:-disks.txt}
180
+
181
+ while read -r name fraction; do
182
+ case $name in
183
+ '' | '#'*) continue ;;
184
+ esac
185
+ tessella meter --width 16 --title "$name" --title-width 6 \
186
+ -- "$fraction"
187
+ done < "$input" |
188
+ tessella compose frame --title disks -
189
+ ```
190
+
191
+ ```text
192
+ $ sh disks.sh
193
+ ┌──────────── disks ─────────────┐
194
+ │ / [█████████▉······] 62 % │
195
+ │ /home [█████████████▉··] 87 % │
196
+ │ /var [█████···········] 31 % │
197
+ │ /tmp [▋···············] 4 % │
198
+ └────────────────────────────────┘
199
+ ```
200
+
201
+ ## Errors
202
+
203
+ A fraction outside 0..1 (or 0%..100%), an unknown style, a style that
204
+ is not two glyphs of one class, or a missing fraction is a usage error,
205
+ exit 2:
206
+
207
+ ```text
208
+ $ tessella meter 1.5
209
+ tessella meter: fraction must be 0..1 or 0%..100%: "1.5"
210
+ ```
data/doc/rule.md ADDED
@@ -0,0 +1,51 @@
1
+ # Rules
2
+
3
+ `rule` draws a divider: one line in a rule style, with an optional
4
+ ornament centred in it. It separates the parts of a report, a log, a
5
+ plain-text document.
6
+
7
+ ```ruby
8
+ Tessella.rule(width: 78, ornament: nil, style: :light,
9
+ ascii: false) # => Block
10
+ ```
11
+
12
+ ```text
13
+ tessella rule [--width N] [--ornament T] [--style S] [--ascii]
14
+ ```
15
+
16
+ ```text
17
+ $ tessella rule --width 30
18
+ ──────────────────────────────
19
+ ```
20
+
21
+ The ornament is any text, centred by display width with a blank on
22
+ each side:
23
+
24
+ ```text
25
+ $ tessella rule --width 30 --ornament '✦'
26
+ ───────────── ✦ ──────────────
27
+ ```
28
+
29
+ ```text
30
+ $ tessella rule --width 30 --style double --ornament 'Part II'
31
+ ══════════ Part II ═══════════
32
+ ```
33
+
34
+ The styles are the rule sets in the [registry](glyphs.md#the-registry):
35
+ `light` (`─`, the default), `heavy` (`━`), `double` (`═`), `dashed`
36
+ (`┄`) and `ascii` (`-`). `--ascii` draws `-`, and refuses an ornament
37
+ that is not ASCII:
38
+
39
+ ```text
40
+ $ tessella rule --width 30 --ascii --ornament '* * *'
41
+ ----------- * * * ------------
42
+ ```
43
+
44
+ ```text
45
+ $ tessella rule --ascii --ornament '✦'
46
+ tessella rule: ornament is non-ASCII under ascii: true
47
+ ```
48
+
49
+ `stack`'s `rule:` draws a plain line between figures; `rule` is the
50
+ one to reach for when the line needs a style or an ornament, or
51
+ stands alone.
data/doc/seq.md ADDED
@@ -0,0 +1,169 @@
1
+ # Sequence diagrams
2
+
3
+ `seq` draws a UML-style sequence diagram: participants across the
4
+ top, their lifelines down, and messages between them in order.
5
+
6
+ ```ruby
7
+ Tessella.seq(text, ascii: false, numbered: false, footer: false)
8
+ # => Block
9
+ ```
10
+
11
+ ```text
12
+ tessella seq [--ascii] [--numbered] [--footer] [--max-width N] [file]
13
+ ```
14
+
15
+ ## Input
16
+
17
+ One statement per line; blank lines and `#` comments are skipped.
18
+
19
+ | Statement | Draws |
20
+ |-------------------------|-----------------------------------------|
21
+ | `participant A` | declares A, fixing its column |
22
+ | `A -> B: text` | a call, solid arrow |
23
+ | `A --> B: text` | a reply, dashed arrow |
24
+ | `A ->> B: text` | an asynchronous message, double head |
25
+ | `A -> A: text` | a self call, a loop right of A |
26
+ | `note over A: text` | a note on A's lifeline |
27
+ | `note over A,B: text` | a note spanning A to B |
28
+
29
+ A name is a run of letters, digits, `_`, `.` or `-`, not ending in
30
+ `-`, so `A-->B` reads as a reply with or without blanks. Participants
31
+ take their columns in the order they are declared, or first appear;
32
+ columns widen to fit every label, never truncating one.
33
+
34
+ ```text
35
+ $ cat login.txt
36
+ participant Browser
37
+ participant Server
38
+ participant DB
39
+ Browser -> Server: POST /login
40
+ Server -> DB: SELECT user
41
+ DB --> Server: row
42
+ Server -> Server: check hash
43
+ note over Server,DB: bcrypt, cost 12
44
+ Server ->> DB: log attempt
45
+ Server --> Browser: 200 + cookie
46
+ ```
47
+
48
+ ```text
49
+ $ tessella seq login.txt
50
+ ┌─────────┐ ┌─────────┐ ┌─────┐
51
+ │ Browser │ │ Server │ │ DB │
52
+ └────┬────┘ └────┬────┘ └──┬──┘
53
+ │ │ │
54
+ │ POST /login │ │
55
+ │─────────────►│ │
56
+ │ │ │
57
+ │ │ SELECT user │
58
+ │ │───────────────►│
59
+ │ │ │
60
+ │ │ row │
61
+ │ │◄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄│
62
+ │ │ │
63
+ │ │──┐ │
64
+ │ │ │ check hash │
65
+ │ │◄─┘ │
66
+ │ │ │
67
+ │ ┌────────────────┐
68
+ │ │bcrypt, cost 12 │
69
+ │ └────────────────┘
70
+ │ │ │
71
+ │ │ log attempt │
72
+ │ │──────────────►►│
73
+ │ │ │
74
+ │ 200 + cookie │ │
75
+ │◄┄┄┄┄┄┄┄┄┄┄┄┄┄│ │
76
+ │ │ │
77
+ ```
78
+
79
+ ## Arrow heads
80
+
81
+ Calls and replies end in `►` or `◄`, asynchronous messages in a
82
+ double head, `►►` or `◄◄`, in every [width target](targets.md). These
83
+ heads read at a glance and never turn into emoji in a browser, but a
84
+ font that lacks them draws them at a fallback width
85
+ ([on the web](targets.md#web)). Under `--ascii` they are `>` and `<`,
86
+ and `>>` and `<<` for an asynchronous message.
87
+
88
+ ## Options
89
+
90
+ `--numbered` numbers the messages; `--footer` repeats the participant
91
+ boxes under the lifelines, which helps a long diagram:
92
+
93
+ ```text
94
+ $ tessella seq --numbered --footer login.txt
95
+ ┌─────────┐ ┌─────────┐ ┌─────┐
96
+ │ Browser │ │ Server │ │ DB │
97
+ └────┬────┘ └────┬────┘ └──┬──┘
98
+ │ │ │
99
+ │ 1. POST /login │ │
100
+ │────────────────►│ │
101
+ │ │ │
102
+ │ │ 2. SELECT user │
103
+ │ │──────────────────►│
104
+ │ │ │
105
+ │ │ 3. row │
106
+ │ │◄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄│
107
+ │ │ │
108
+ │ │──┐ │
109
+ │ │ │ 4. check hash │
110
+ │ │◄─┘ │
111
+ │ │ │
112
+ │ ┌───────────────────┐
113
+ │ │ bcrypt, cost 12 │
114
+ │ └───────────────────┘
115
+ │ │ │
116
+ │ │ 5. log attempt │
117
+ │ │─────────────────►►│
118
+ │ │ │
119
+ │ 6. 200 + cookie │ │
120
+ │◄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄│ │
121
+ │ │ │
122
+ ┌────┴────┐ ┌────┴────┐ ┌──┴──┐
123
+ │ Browser │ │ Server │ │ DB │
124
+ └─────────┘ └─────────┘ └─────┘
125
+ ```
126
+
127
+ `--ascii` draws in `+ - |`, with `- - -` for a reply:
128
+
129
+ ```text
130
+ $ tessella seq --ascii login.txt
131
+ +---------+ +---------+ +-----+
132
+ | Browser | | Server | | DB |
133
+ +----+----+ +----+----+ +--+--+
134
+ | | |
135
+ | POST /login | |
136
+ |------------->| |
137
+ | | |
138
+ | | SELECT user |
139
+ | |--------------->|
140
+ | | |
141
+ | | row |
142
+ | |<- - - - - - - -|
143
+ | | |
144
+ | |--+ |
145
+ | | | check hash |
146
+ | |<-+ |
147
+ | | |
148
+ | +----------------+
149
+ | |bcrypt, cost 12 |
150
+ | +----------------+
151
+ | | |
152
+ | | log attempt |
153
+ | |-------------->>|
154
+ | | |
155
+ | 200 + cookie | |
156
+ |<- - - - - - -| |
157
+ | | |
158
+ ```
159
+
160
+ ## Errors
161
+
162
+ A line that is none of the statements above is refused, quoting it
163
+ (exit 1); so is input with no statement, and a non-ASCII name under
164
+ `--ascii`.
165
+
166
+ ```text
167
+ $ printf 'A => B: x\n' | tessella seq
168
+ tessella seq: line 1: A => B: x
169
+ ```
data/doc/sparkline.md ADDED
@@ -0,0 +1,63 @@
1
+ # Sparklines
2
+
3
+ A sparkline is a chart one line high and one cell a value, small
4
+ enough to sit in a sentence, a table cell or a log line: ▁▂▄▃█▁▂.
5
+
6
+ ```ruby
7
+ Tessella.sparkline(values, width: nil, min: nil, max: nil,
8
+ ascii: false) # => Block
9
+ ```
10
+
11
+ ```text
12
+ tessella sparkline [--width N] [--min A] [--max B] [--ascii] [VALUE ...]
13
+ ```
14
+
15
+ The command reads the values given, or stdin when there are none,
16
+ split on blanks and commas:
17
+
18
+ ```text
19
+ $ tessella sparkline 1 5 22 13 53 2 8
20
+ ▁▂▄▃█▁▂
21
+ ```
22
+
23
+ ```text
24
+ $ printf '1,2\n3 4\n' | tessella sparkline
25
+ ▁▃▆█
26
+ ```
27
+
28
+ Each value takes one of eight steps, `▁` to `█`, from the lowest value
29
+ to the highest. Under `--ascii` the steps are `_.-:=+*#`:
30
+
31
+ ```text
32
+ $ tessella sparkline --ascii 1 5 22 13 53 2 8
33
+ _.:-#_.
34
+ ```
35
+
36
+ ## Width and range
37
+
38
+ `--width N` averages the values into N cells, for a long series in a
39
+ short space (with fewer values than cells, each is repeated to fill
40
+ them). `cpu.txt` holds 60 values:
41
+
42
+ ```text
43
+ $ tessella sparkline --width 20 < cpu.txt
44
+ ▅▇██▇▆▄▃▂▁▁▃▄▆▇██▇▅▄
45
+ ```
46
+
47
+ By default the range is the values' own, so every sparkline uses all
48
+ eight steps. `--min` and `--max` fix it, so several sparklines share
49
+ one scale and can be compared:
50
+
51
+ ```text
52
+ $ tessella sparkline --min 0 --max 100 10 50 90
53
+ ▂▅▇
54
+ ```
55
+
56
+ ## Errors
57
+
58
+ A value that is not a number is bad input, exit 1:
59
+
60
+ ```text
61
+ $ tessella sparkline 1 x
62
+ tessella sparkline: not a number: "x"
63
+ ```