table_tennis 0.0.1
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.
- checksums.yaml +7 -0
- data/.github/workflows/test.yml +26 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +58 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +122 -0
- data/LICENSE +21 -0
- data/README.md +154 -0
- data/Rakefile +12 -0
- data/justfile +75 -0
- data/lib/table_tennis/column.rb +41 -0
- data/lib/table_tennis/config.rb +221 -0
- data/lib/table_tennis/row.rb +9 -0
- data/lib/table_tennis/stage/base.rb +19 -0
- data/lib/table_tennis/stage/format.rb +68 -0
- data/lib/table_tennis/stage/layout.rb +76 -0
- data/lib/table_tennis/stage/painter.rb +84 -0
- data/lib/table_tennis/stage/render.rb +146 -0
- data/lib/table_tennis/table.rb +79 -0
- data/lib/table_tennis/table_data.rb +161 -0
- data/lib/table_tennis/theme.rb +92 -0
- data/lib/table_tennis/util/colors.rb +524 -0
- data/lib/table_tennis/util/inspectable.rb +25 -0
- data/lib/table_tennis/util/scale.rb +55 -0
- data/lib/table_tennis/util/strings.rb +62 -0
- data/lib/table_tennis/util/termbg.rb +275 -0
- data/lib/table_tennis/version.rb +3 -0
- data/lib/table_tennis.rb +29 -0
- data/screenshots/dark.png +0 -0
- data/screenshots/droids.png +0 -0
- data/screenshots/hope.png +0 -0
- data/screenshots/light.png +0 -0
- data/screenshots/row_numbers.png +0 -0
- data/screenshots/scales.png +0 -0
- data/screenshots/themes.png +0 -0
- data/table_tennis.gemspec +28 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 03c38407a65288ded066cc1986f53453d8dafe6e51096ea597e843c8ad115afb
|
4
|
+
data.tar.gz: a76db1bbb2a0ef775a629f71f6f76c2ee5c67a42255ba9856c5ccb9f66bb89bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 51d515f45a6f62d6ede57e5b8d752ccd5a637dc107d170e526693600d91e9a91988cef1ee570104c413951759cf673e80d569076544a137398ac09bf1b2735e7
|
7
|
+
data.tar.gz: 3e269c16f3a95e4e948d55d8713d5349d2e5b5527b97c0fd5722d8cee88e17f182078d720b9bafb6d233dc9feb76f209a8b17780549ad03468817dcaaeb2aedb
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
paths-ignore:
|
6
|
+
- README.md
|
7
|
+
- 'screenshots/**'
|
8
|
+
pull_request:
|
9
|
+
workflow_dispatch:
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
strategy:
|
14
|
+
max-parallel: 3
|
15
|
+
matrix:
|
16
|
+
os: [macos, ubuntu, windows]
|
17
|
+
ruby-version: [3.0, 3.4]
|
18
|
+
runs-on: ${{ matrix.os }}-latest
|
19
|
+
steps:
|
20
|
+
- uses: actions/checkout@v3
|
21
|
+
- uses: taiki-e/install-action@just
|
22
|
+
- uses: ruby/setup-ruby@v1
|
23
|
+
with:
|
24
|
+
bundler-cache: true
|
25
|
+
ruby-version: ${{ matrix.ruby-version }}
|
26
|
+
- run: just ci
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require:
|
2
|
+
- standard
|
3
|
+
|
4
|
+
inherit_gem:
|
5
|
+
standard: config/ruby-3.3.yml
|
6
|
+
standard-custom: config/base.yml
|
7
|
+
standard-performance: config/base.yml
|
8
|
+
|
9
|
+
plugins:
|
10
|
+
- standard-custom
|
11
|
+
- standard-performance
|
12
|
+
- rubocop-performance
|
13
|
+
|
14
|
+
AllCops:
|
15
|
+
NewCops: enable
|
16
|
+
SuggestExtensions: false
|
17
|
+
|
18
|
+
#
|
19
|
+
# fight with standardrb!
|
20
|
+
#
|
21
|
+
|
22
|
+
# we like these, don't remove
|
23
|
+
Bundler/OrderedGems: { Enabled: true } # sort gems in gemfile
|
24
|
+
Layout/EmptyLineBetweenDefs: { AllowAdjacentOneLineDefs: true }
|
25
|
+
Lint/NonLocalExitFromIterator: { Enabled: false }
|
26
|
+
Lint/RedundantDirGlobSort: { Enabled: true } # glob is already sorted
|
27
|
+
Performance/RegexpMatch: { Enabled: false }
|
28
|
+
Style/HashSyntax: { EnforcedShorthandSyntax: always } # use modern hash syntax
|
29
|
+
Style/NestedTernaryOperator: { Enabled: false } # we do this sometimes
|
30
|
+
Style/NonNilCheck: { Enabled: false } # allow x != nil for clarity
|
31
|
+
Style/RedundantAssignment: { Enabled: false } # allows s=xxx;s=yyy;s
|
32
|
+
Style/RedundantReturn: { Enabled: false } # sometines we do this while working on something
|
33
|
+
Style/StringConcatenation: { Enabled: true } # prefer interpolation
|
34
|
+
Style/TrailingCommaInArrayLiteral: { EnforcedStyleForMultiline: consistent_comma } # commas!!
|
35
|
+
Style/TrailingCommaInHashLiteral: { EnforcedStyleForMultiline: consistent_comma } # commas!!
|
36
|
+
|
37
|
+
#
|
38
|
+
# These are rules that are not enabled by default (in standardrb) but we tend to
|
39
|
+
# write code this way. We don't often trigger these, but it matches our style.
|
40
|
+
#
|
41
|
+
|
42
|
+
Lint/MissingSuper: { Enabled: true }
|
43
|
+
Naming/FileName: { Enabled: true }
|
44
|
+
Naming/MemoizedInstanceVariableName: { Enabled: true }
|
45
|
+
Naming/MethodName: { Enabled: true }
|
46
|
+
Performance/MapCompact: { Enabled: true }
|
47
|
+
Performance/SelectMap: { Enabled: true }
|
48
|
+
Style/BlockDelimiters: { Enabled: true }
|
49
|
+
Style/CollectionCompact: { Enabled: true }
|
50
|
+
Style/CollectionMethods: { Enabled: true }
|
51
|
+
Style/HashEachMethods: { Enabled: true }
|
52
|
+
Style/HashTransformKeys: { Enabled: true }
|
53
|
+
Style/HashTransformValues: { Enabled: true }
|
54
|
+
Style/MinMax: { Enabled: true }
|
55
|
+
Style/PreferredHashMethods: { Enabled: true }
|
56
|
+
Style/SelectByRegexp: { Enabled: true }
|
57
|
+
Style/SymbolArray: { Enabled: true }
|
58
|
+
Style/WordArray: { Enabled: true }
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
gemspec
|
3
|
+
|
4
|
+
group :development, :test do
|
5
|
+
gem "amazing_print"
|
6
|
+
gem "minitest"
|
7
|
+
gem "minitest-hooks"
|
8
|
+
gem "mocha"
|
9
|
+
gem "ostruct" # required for Ruby 3.5+
|
10
|
+
gem "pry"
|
11
|
+
gem "rake"
|
12
|
+
gem "simplecov", require: false
|
13
|
+
gem "standard", require: false
|
14
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
table_tennis (0.0.1)
|
5
|
+
csv (~> 3.3)
|
6
|
+
ffi (~> 1.17)
|
7
|
+
memo_wise (~> 1.11)
|
8
|
+
paint (~> 2.3)
|
9
|
+
unicode-display_width (~> 3.1)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
amazing_print (1.7.2)
|
15
|
+
ast (2.4.3)
|
16
|
+
coderay (1.1.3)
|
17
|
+
csv (3.3.2)
|
18
|
+
docile (1.4.1)
|
19
|
+
ffi (1.17.1)
|
20
|
+
ffi (1.17.1-aarch64-linux-gnu)
|
21
|
+
ffi (1.17.1-aarch64-linux-musl)
|
22
|
+
ffi (1.17.1-arm-linux-gnu)
|
23
|
+
ffi (1.17.1-arm-linux-musl)
|
24
|
+
ffi (1.17.1-arm64-darwin)
|
25
|
+
ffi (1.17.1-x86-linux-gnu)
|
26
|
+
ffi (1.17.1-x86-linux-musl)
|
27
|
+
ffi (1.17.1-x86_64-darwin)
|
28
|
+
ffi (1.17.1-x86_64-linux-gnu)
|
29
|
+
ffi (1.17.1-x86_64-linux-musl)
|
30
|
+
json (2.10.2)
|
31
|
+
language_server-protocol (3.17.0.4)
|
32
|
+
lint_roller (1.1.0)
|
33
|
+
memo_wise (1.11.0)
|
34
|
+
method_source (1.1.0)
|
35
|
+
minitest (5.25.5)
|
36
|
+
minitest-hooks (1.5.2)
|
37
|
+
minitest (> 5.3)
|
38
|
+
mocha (2.7.1)
|
39
|
+
ruby2_keywords (>= 0.0.5)
|
40
|
+
ostruct (0.6.1)
|
41
|
+
paint (2.3.0)
|
42
|
+
parallel (1.26.3)
|
43
|
+
parser (3.3.7.4)
|
44
|
+
ast (~> 2.4.1)
|
45
|
+
racc
|
46
|
+
prism (1.4.0)
|
47
|
+
pry (0.15.2)
|
48
|
+
coderay (~> 1.1)
|
49
|
+
method_source (~> 1.0)
|
50
|
+
racc (1.8.1)
|
51
|
+
rainbow (3.1.1)
|
52
|
+
rake (13.2.1)
|
53
|
+
regexp_parser (2.10.0)
|
54
|
+
rubocop (1.73.2)
|
55
|
+
json (~> 2.3)
|
56
|
+
language_server-protocol (~> 3.17.0.2)
|
57
|
+
lint_roller (~> 1.1.0)
|
58
|
+
parallel (~> 1.10)
|
59
|
+
parser (>= 3.3.0.2)
|
60
|
+
rainbow (>= 2.2.2, < 4.0)
|
61
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
62
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
63
|
+
ruby-progressbar (~> 1.7)
|
64
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
65
|
+
rubocop-ast (1.43.0)
|
66
|
+
parser (>= 3.3.7.2)
|
67
|
+
prism (~> 1.4)
|
68
|
+
rubocop-performance (1.24.0)
|
69
|
+
lint_roller (~> 1.1)
|
70
|
+
rubocop (>= 1.72.1, < 2.0)
|
71
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
72
|
+
ruby-progressbar (1.13.0)
|
73
|
+
ruby2_keywords (0.0.5)
|
74
|
+
simplecov (0.22.0)
|
75
|
+
docile (~> 1.1)
|
76
|
+
simplecov-html (~> 0.11)
|
77
|
+
simplecov_json_formatter (~> 0.1)
|
78
|
+
simplecov-html (0.13.1)
|
79
|
+
simplecov_json_formatter (0.1.4)
|
80
|
+
standard (1.47.0)
|
81
|
+
language_server-protocol (~> 3.17.0.2)
|
82
|
+
lint_roller (~> 1.0)
|
83
|
+
rubocop (~> 1.73.0)
|
84
|
+
standard-custom (~> 1.0.0)
|
85
|
+
standard-performance (~> 1.7)
|
86
|
+
standard-custom (1.0.2)
|
87
|
+
lint_roller (~> 1.0)
|
88
|
+
rubocop (~> 1.50)
|
89
|
+
standard-performance (1.7.0)
|
90
|
+
lint_roller (~> 1.1)
|
91
|
+
rubocop-performance (~> 1.24.0)
|
92
|
+
unicode-display_width (3.1.4)
|
93
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
94
|
+
unicode-emoji (4.0.4)
|
95
|
+
|
96
|
+
PLATFORMS
|
97
|
+
aarch64-linux-gnu
|
98
|
+
aarch64-linux-musl
|
99
|
+
arm-linux-gnu
|
100
|
+
arm-linux-musl
|
101
|
+
arm64-darwin
|
102
|
+
ruby
|
103
|
+
x86-linux-gnu
|
104
|
+
x86-linux-musl
|
105
|
+
x86_64-darwin
|
106
|
+
x86_64-linux-gnu
|
107
|
+
x86_64-linux-musl
|
108
|
+
|
109
|
+
DEPENDENCIES
|
110
|
+
amazing_print
|
111
|
+
minitest
|
112
|
+
minitest-hooks
|
113
|
+
mocha
|
114
|
+
ostruct
|
115
|
+
pry
|
116
|
+
rake
|
117
|
+
simplecov
|
118
|
+
standard
|
119
|
+
table_tennis!
|
120
|
+
|
121
|
+
BUNDLED WITH
|
122
|
+
2.6.5
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 gurgeous
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
# TableTennis [](https://github.com/gurgeous/table_tennis/actions/workflows/test.yml)
|
2
|
+
|
3
|
+
TableTennis is a Ruby library for printing stylish tables in your terminal.
|
4
|
+
|
5
|
+
```rb
|
6
|
+
require "table_tennis"
|
7
|
+
|
8
|
+
options = { title: "Star Wars People", zebra: true, color_scale: :height }
|
9
|
+
puts TableTennis.new(Starwars.all, options)
|
10
|
+
```
|
11
|
+
|
12
|
+
Prints this lovely table in your terminal:
|
13
|
+
|
14
|
+

|
15
|
+
|
16
|
+
### Installation
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
# install gem
|
20
|
+
$ gem install table_tennis
|
21
|
+
|
22
|
+
# or add to your Gemfile
|
23
|
+
gem "table_tennis"
|
24
|
+
```
|
25
|
+
|
26
|
+
### Important Features
|
27
|
+
|
28
|
+
- auto-themes to pick light or dark based on your terminal background
|
29
|
+
- auto-layout to fit your terminal window
|
30
|
+
- auto-format floats and dates
|
31
|
+
- auto-color numeric columns
|
32
|
+
- titles, row numbers, zebra stripes...
|
33
|
+
|
34
|
+
### Themes
|
35
|
+
|
36
|
+
TableTennis examines the background color of your terminal to pick either the dark or light theme. You can also specify `:dark` or `:light` manually, or even an `:ansi` theme to use your terminal's default colors. This feature is [surprisingly complicated](https://github.com/gurgeous/table_tennis/blob/main/lib/table_tennis/util/termbg.rb).
|
37
|
+
|
38
|
+

|
39
|
+
|
40
|
+
### Rows (Your Data)
|
41
|
+
|
42
|
+
Construct your table with an array of rows. Rows are hashes, ActiveRecord objects, structs, Data records, or anything that responds to `to_h`. It also supports oddballs like arrays (as rows) or even a single hash.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
puts TableTennis.new([{a: "hello", b: "world"}, {a: "foo", b: "bar"})
|
46
|
+
puts TableTennis.new(Recipe.all.to_a) # activerecord
|
47
|
+
puts TableTennis.new(array_of_structs) # these use to_h
|
48
|
+
puts TableTennis.new([[1,2],[3,4]]]) # array of arrays
|
49
|
+
puts TableTennis.new(authors[0]) # single hash
|
50
|
+
```
|
51
|
+
|
52
|
+
### Big List of Options
|
53
|
+
|
54
|
+
Here is a more complex example to get you started:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
options = {
|
58
|
+
color_scales: :commission,
|
59
|
+
columns: %i[ name commission bday phone ],
|
60
|
+
mark: -> { _1[:name] =~ /jane|john/i },
|
61
|
+
row_numbers: true,
|
62
|
+
save: "/tmp/people.csv",
|
63
|
+
search: "february",
|
64
|
+
title: "Employees",
|
65
|
+
zebra: true,
|
66
|
+
}
|
67
|
+
```
|
68
|
+
|
69
|
+
| option | default | details |
|
70
|
+
| ------ | ------- | ------- |
|
71
|
+
| `color_scales` | ─ | Color code a column of floats, similar to the "conditional formatting" feature in Google Sheets. See [docs below](#color-scales). |
|
72
|
+
| `color` | `nil` | Are ANSI colors enabled? Specify `true` or `false`, or leave it as nil to autodetect. Autodetect will turn on color unless redirecting to a file. When using autodetect, you can force it on by setting `ENV["FORCE_COLOR"]`, or off with `ENV["NO_COLOR"]`. |
|
73
|
+
| `columns` | `nil` | Manually set which columns to include. Leave unset to show all columns.
|
74
|
+
| `digits` | `3` | Format floats to this number of digits. TableTennis will look for either `Float` cells or string floats. |
|
75
|
+
| `layout` | `true` | This controls column widths. Leave unset or use `true` for autolayout. Autolayout will shrink the table to fit inside the terminal. `false` turns off layout and columns will be full width. Use an int to fix all columns to a certain width, or a hash to just set a few. |
|
76
|
+
| `mark` | ─ | `mark` is a way to highlight specific columns with a nice color. For example, use `mark: ->(row) { row[:planet] == "tatooine" }` to highlight those rows. Your lambda can also return a specific color if you want.
|
77
|
+
| `placeholder` | `"—"` | Put this into empty cells. |
|
78
|
+
| `row_numbers` | `false` | Show row numbers in the table. |
|
79
|
+
| `save` | ─ | If you set this to a file path, TableTennis will save your table as a CSV file too. Useful if you want to do something else with the data. |
|
80
|
+
| `search` | ─ | string/regex to highlight in output |
|
81
|
+
| `strftime` | see → | strftime string for formatting Date/Time objects. The default is `"%Y-%m-%d"`, which looks like `2025-04-21` |
|
82
|
+
| `theme` | nil | When unset, will be autodetected based on terminal background color. If autodetect fails the theme defaults to :dark. You can also manually specify `:dark`, `:light` or `:ansi`. If colors are turned off this setting has no effect.|
|
83
|
+
| `title` | ─ | Add a title line to the table. |
|
84
|
+
| `zebra` | `false` | Turn on zebra stripes. |
|
85
|
+
|
86
|
+
### Color Scales
|
87
|
+
|
88
|
+
Color scales are useful for visualizing numeric columns. The `:color_scales` option can be a single column, an array of column names, or a hash from column names to colors. The scale defaults to `:b` (blue) if you don't use a hash.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
puts TableTennis.new(rows, color_scales: :price)
|
92
|
+
puts TableTennis.new(rows, color_scales: [ :price, :quantity ])
|
93
|
+
puts TableTennis.new(rows, color_scales: { price: :b, quantity: :r })
|
94
|
+
```
|
95
|
+
|
96
|
+
The color names are abbreviations, so `:gyr` goes from green to yellow to red. Here is the full list of supported color scales - `%i[g y r b gw yw rw bw rg gr gyr]`. For clarity this screenshot uses sorted columns, but note that TableTennis never does any sorting:
|
97
|
+
|
98
|
+

|
99
|
+
|
100
|
+
### Tips
|
101
|
+
|
102
|
+
Use **mark** to highlight certain rows. Maybe you need to find the droids? Or **search** to highlight text. I almost always use **row numbers** and **zebra stripes** too.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
puts TableTennis.new(rows, mark: ->(row) { row[:homeworld] =~ /droids/i })
|
106
|
+
puts TableTennis.new(rows, search: /hope.*empire/i })
|
107
|
+
puts TableTennis.new(rows, row_numbers: true, zebra: true)
|
108
|
+
```
|
109
|
+
|
110
|
+
| `:mark` | `:search` | `:row_numbers` and `:zebra` |
|
111
|
+
| - | - | - |
|
112
|
+
|  |  |  |
|
113
|
+
|
114
|
+
### Advanced Usage
|
115
|
+
|
116
|
+
TableTennis can be configured a few different ways:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
|
120
|
+
TableTennis.defaults = { title: "All Tables Have This Name" }
|
121
|
+
TableTennis.new(rows, title: "An Amazing Title")
|
122
|
+
TableTennis.new do |t|
|
123
|
+
t.title = "Yet Another Way To Set Things Up"
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
Tables usually get `puts` to $stdout, but there are other ways to do it:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
# Uses `to_s`, so there can be a pause before output shows up. Best for small tables.
|
131
|
+
puts TableTennis.new(rows)
|
132
|
+
|
133
|
+
# Write to `$stdout` one row at a time. Prefer this for tables over 10,000 rows.
|
134
|
+
TableTennis.new(rows).render
|
135
|
+
|
136
|
+
# Render to any I/O stream ($stdout/$stderr, an open file, StringIO...)
|
137
|
+
TableTennis.new(rows).render(io)
|
138
|
+
```
|
139
|
+
|
140
|
+
### Similar Tools
|
141
|
+
|
142
|
+
We love CSV tools and use them all the time! Here are a few that we rely on:
|
143
|
+
|
144
|
+
- [bat](https://github.com/sharkdp/bat) - syntax highlights csv files, and many others
|
145
|
+
- [csvlens](https://github.com/YS-L/csvlens) & [tidy viewer](https://github.com/alexhallam/tv) - great viewers for CSV files, beautiful and fun
|
146
|
+
- [qsv](https://github.com/dathere/qsv) - filter, sort, combine, join... (a fork of [xsv](https://github.com/BurntSushi/xsv))
|
147
|
+
- [Terminal::Table](https://github.com/tj/terminal-table) - wonderful rubygem for pretty printing tables, great for non-hash data like confusion matrices
|
148
|
+
- [visidata](https://www.visidata.org) - the best for poking around large files, it does everything
|
149
|
+
|
150
|
+
### Special Thanks
|
151
|
+
|
152
|
+
- [termbg](https://github.com/dalance/termbg) and [termenv](https://github.com/muesli/termenv) for showing how to safely detect the terminal background color. These libraries are widely used for Rust/Go, but as far as I know nothing similar exists for Ruby.
|
153
|
+
- The [Paint gem](https://github.com/janlelis/paint) for help with ansi colors.
|
154
|
+
- Google Sheets for providing nice color scales
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
Rake::TestTask.new do
|
5
|
+
# let the user pass *.rb on the command line
|
6
|
+
files = ARGV.grep(%r{^test/.*\.rb$}).sort
|
7
|
+
_1.test_files = files.empty? ? FileList["test/**/test_*.rb"] : files
|
8
|
+
# autoload test_helper
|
9
|
+
_1.ruby_opts = ["-w", "-r#{File.realpath("test/test_helper.rb")}"]
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: :test
|
data/justfile
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
# read gem version
|
3
|
+
gemver := `grep -Eo "[0-9]+\.[0-9]+\.[0-9]+" lib/table_tennis/version.rb`
|
4
|
+
|
5
|
+
#
|
6
|
+
# dev
|
7
|
+
#
|
8
|
+
|
9
|
+
default:
|
10
|
+
@just --list
|
11
|
+
|
12
|
+
check: lint test
|
13
|
+
|
14
|
+
ci: check
|
15
|
+
|
16
|
+
demo-watch *ARGS:
|
17
|
+
@watchexec --stop-timeout=0 --clear clear table-tennis-demo {{ARGS}}
|
18
|
+
|
19
|
+
format:
|
20
|
+
@just banner format...
|
21
|
+
bundle exec rubocop -a
|
22
|
+
|
23
|
+
image_optim:
|
24
|
+
@bundle exec image_optim --allow-lossy --svgo-precision=1 -r .
|
25
|
+
|
26
|
+
lint:
|
27
|
+
@just banner lint...
|
28
|
+
bundle exec rubocop
|
29
|
+
|
30
|
+
pry:
|
31
|
+
bundle exec pry -I lib -r table_tennis.rb
|
32
|
+
|
33
|
+
test *ARGS:
|
34
|
+
@just banner rake test {{ARGS}}
|
35
|
+
@bundle exec rake test {{ARGS}}
|
36
|
+
|
37
|
+
test-watch *ARGS:
|
38
|
+
@watchexec --stop-timeout=0 --clear clear just test "{{ARGS}}"
|
39
|
+
|
40
|
+
#
|
41
|
+
# coverage/profiling
|
42
|
+
#
|
43
|
+
|
44
|
+
coverage:
|
45
|
+
COVERAGE=1 just test
|
46
|
+
open /tmp/coverage/index.html
|
47
|
+
|
48
|
+
#
|
49
|
+
# gem tasks
|
50
|
+
#
|
51
|
+
|
52
|
+
# you can test locally from another project by dropping gem file into vendor/cache
|
53
|
+
gem-push: check-git-status
|
54
|
+
@just banner gem build...
|
55
|
+
gem build table_tennis.gemspec
|
56
|
+
@just banner tag...
|
57
|
+
git tag -a "v{{gemver}}" -m "Tagging {{gemver}}"
|
58
|
+
git push --tags
|
59
|
+
@just banner gem push...
|
60
|
+
gem push "table_tennis-{{gemver}}.gem"
|
61
|
+
|
62
|
+
#
|
63
|
+
# util
|
64
|
+
#
|
65
|
+
|
66
|
+
banner *ARGS: (_banner BG_GREEN ARGS)
|
67
|
+
warning *ARGS: (_banner BG_YELLOW ARGS)
|
68
|
+
fatal *ARGS: (_banner BG_RED ARGS)
|
69
|
+
@exit 1
|
70
|
+
_banner color *ARGS:
|
71
|
+
@msg=$(printf "[%s] %s" $(date +%H:%M:%S) "{{ARGS}}") ; \
|
72
|
+
printf "{{color+BOLD+WHITE}}%-72s{{ NORMAL }}\n" "$msg"
|
73
|
+
|
74
|
+
check-git-status:
|
75
|
+
@if [ ! -z "$(git status --porcelain)" ]; then just fatal "git status is dirty, bailing."; fi
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module TableTennis
|
2
|
+
#
|
3
|
+
# A single column in a table. The data is actually stored in the rows, but it
|
4
|
+
# can be enumerated from here. Mostly used for layout calculations.
|
5
|
+
#
|
6
|
+
|
7
|
+
class Column
|
8
|
+
include Enumerable
|
9
|
+
prepend MemoWise
|
10
|
+
|
11
|
+
attr_reader :name
|
12
|
+
attr_accessor :header, :width
|
13
|
+
|
14
|
+
def initialize(name, data)
|
15
|
+
@name, @data = name, data
|
16
|
+
@header = name.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def each(&block)
|
20
|
+
return to_enum(__method__) unless block_given?
|
21
|
+
@data.rows.each { yield(_1[name]) }
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def each_index(&block)
|
26
|
+
return to_enum(__method__) unless block_given?
|
27
|
+
@data.rows.each_index { yield(_1) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def map!(&block) = @data.rows.each { _1[name] = yield(_1[name]) }
|
31
|
+
|
32
|
+
def truncate(stop)
|
33
|
+
@header = Util::Strings.truncate(header, stop)
|
34
|
+
map! { Util::Strings.truncate(_1, stop) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def measure
|
38
|
+
[2, max_by(&:length)&.length, header.length].max
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|