/
table.go
122 lines (92 loc) · 2.1 KB
/
table.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package cmd
import "strings"
// Table provides a generic table interface
// for Printer's to consume table data from.
type Table interface {
// Headers returns the table's headers if any.
Headers() []string
// Rows returns a 2-dimensional slice of Fields
// representing the Table data.
Rows() [][]Field
}
// NewDefaultTable returns a Table implementation which
// will only select Fields from each row if the Field's
// name matches the provided Headers. If no Headers are
// provided all fields will be present in the table Data.
func NewDefaultTable(opts ...TableOption) *DefaultTable {
var cfg TableConfig
cfg.Option(opts...)
return &DefaultTable{
cfg: cfg,
}
}
type DefaultTable struct {
cfg TableConfig
data table
}
func (t *DefaultTable) Headers() []string {
return t.cfg.Headers
}
func (t *DefaultTable) AddRow(fields ...Field) {
t.data = append(t.data, row(fields))
}
func (t *DefaultTable) Rows() [][]Field {
if len(t.cfg.Headers) == 0 {
return t.data.Fields()
}
res := make([][]Field, 0, len(t.data))
for _, r := range t.data {
row := r.SelectFields(t.cfg.Headers...)
if len(row) < 1 {
continue
}
res = append(res, row)
}
return res
}
type TableConfig struct {
Headers []string
}
func (c *TableConfig) Option(opts ...TableOption) {
for _, opt := range opts {
opt.ConfigureTable(c)
}
}
type TableOption interface {
ConfigureTable(*TableConfig)
}
type table []row
func (t table) Fields() [][]Field {
res := make([][]Field, 0, len(t))
for _, r := range t {
res = append(res, []Field(r))
}
return res
}
type row []Field
func (r row) SelectFields(names ...string) []Field {
var res row
for _, n := range names {
if ok, f := r.GetField(n); ok {
res = append(res, f)
}
}
return res
}
func (r row) GetField(name string) (bool, Field) {
for _, f := range r {
if normalize(f.Name) == normalize(name) {
return true, f
}
}
return false, Field{}
}
func normalize(name string) string {
trimmed := strings.TrimSpace(name)
snaked := strings.Join(strings.Fields(trimmed), "_")
return strings.ToLower(snaked)
}
type Field struct {
Name string
Value any
}