Skip to content

Commit

Permalink
Make asciitable more flexible (#5)
Browse files Browse the repository at this point in the history
* Skip table grid lines and add support for '+' and '*' delimitters.

* Add test case for tables with 'grid lines' and a 'title' over the column header row
  • Loading branch information
jak3kaj authored Dec 24, 2024
1 parent b0bf169 commit 3ada379
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 10 deletions.
59 changes: 49 additions & 10 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,33 @@ import (

// Unmarshal parses an ASCII table into a slice of the specified type.
func Unmarshal[E any](asciiTable string, v E) ([]string, []E, error) {
var delimitter = "*+|"
var skip = []string{"---"}
lines := strings.Split(strings.TrimSpace(asciiTable), "\n")
if len(lines) < 4 {
return nil, nil, errors.New("invalid ascii table format, must have at least 4 lines")
}

// Extract headers
headerLine := strings.Trim(lines[1], "| ")
headers := splitRow(headerLine)
// Look for headers in the first 10 lines
var headers []string
var headerLineNumber int

var defaultLines = 10
if len(lines) < defaultLines {
defaultLines = len(lines) - 1
}

for i, line := range lines[0:defaultLines] {
headerLine := strings.Trim(line, delimitter+" ")
if skipLine(headerLine, skip) {
continue
}
headers = splitRow(headerLine, delimitter)
if len(headers) > 1 {
headerLineNumber = i
break
}
}

// Reflect on the type of E
var results []E
Expand All @@ -27,8 +46,12 @@ func Unmarshal[E any](asciiTable string, v E) ([]string, []E, error) {
}

// Process rows
for _, line := range lines[3 : len(lines)-1] { // Skip header and separator line
row := splitRow(strings.Trim(line, "| "))
for _, line := range lines[headerLineNumber+1 : len(lines)-1] { // Begin after header
if skipLine(line, skip) {
continue
}

row := splitRow(strings.Trim(line, delimitter+" "), delimitter)
if len(row) != len(headers) {
return nil, nil, fmt.Errorf("row length does not match header length: %v", row)
}
Expand Down Expand Up @@ -56,11 +79,17 @@ func Unmarshal[E any](asciiTable string, v E) ([]string, []E, error) {
return headers, results, nil
}

// Helper function to split a row by `|` and trim whitespace
func splitRow(row string) []string {
cells := strings.Split(row, "|")
for i := range cells {
cells[i] = strings.TrimSpace(cells[i])
// Helper function to split a row by the first character in the delimitter string and trim whitespace.
func splitRow(row string, delimitter string) []string {
var cells []string
for _, char := range strings.Split(delimitter, "") {
cells = strings.Split(row, char)
for i := range cells {
cells[i] = strings.TrimSpace(cells[i])
}
if len(cells) > 1 {
break
}
}
return cells
}
Expand Down Expand Up @@ -98,3 +127,13 @@ func setFieldValue(field reflect.Value, value string) error {

return nil
}

// Return `true` if any string in the skip slice is in the line.
func skipLine(line string, skip []string) bool {
for _, s := range skip {
if strings.Contains(line, s) {
return true
}
}
return false
}
15 changes: 15 additions & 0 deletions decode_grid.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
+-------------------+-------------------+-------------------+-------------------+
| ROM Info |
+-------------------+-------------------+-------------------+-------------------+
| param_name | rom1 | rom2 | rom3 |
+-------------------+-------------------+-------------------+-------------------+
| chip_tech | CB | EB | PB |
+-------------------+-------------------+-------------------+-------------------+
| default_v | 14000 | 14000 | 14000 |
+-------------------+-------------------+-------------------+-------------------+
| default_clk | 490 | 490 | 490 |
+-------------------+-------------------+-------------------+-------------------+
| warmup_temp | 41 | 41 | 45 |
+-------------------+-------------------+-------------------+-------------------+
| cooldown_temp | 56 | 59 | 62 |
+-------------------+-------------------+-------------------+-------------------+
27 changes: 27 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,30 @@ func TestDecodeNormalData(t *testing.T) {
}
require.Equal(t, expected, results)
}

type gridData struct {
Name string `asciitable:"param_name"`
ROM1 string `asciitable:"rom1"`
ROM2 string `asciitable:"rom2"`
ROM3 string `asciitable:"rom3"`
}

func TestDecodeGridData(t *testing.T) {
bytes, err := os.ReadFile("decode_grid.txt")
require.NoError(t, err)

table := string(bytes)
headers, results, err := Unmarshal(table, gridData{})
require.NoError(t, err)

require.Equal(t, []string{"param_name", "rom1", "rom2", "rom3"}, headers)

expected := []gridData{
{Name:"chip_tech", ROM1:"CB", ROM2:"EB", ROM3:"PB"},
{Name:"default_v", ROM1:"14000", ROM2:"14000", ROM3:"14000"},
{Name:"default_clk", ROM1:"490", ROM2:"490", ROM3:"490"},
{Name:"warmup_temp", ROM1:"41", ROM2:"41", ROM3:"45"},
{Name:"cooldown_temp", ROM1:"56", ROM2:"59", ROM3:"62"},
}
require.Equal(t, expected, results)
}

0 comments on commit 3ada379

Please sign in to comment.