Skip to content

Commit

Permalink
feat: add p/moul/mdtable (#3100)
Browse files Browse the repository at this point in the history
Can be useful for #3096.

---------

Signed-off-by: moul <94029+moul@users.noreply.github.com>
  • Loading branch information
moul authored Nov 15, 2024
1 parent 6c5329d commit a1812af
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/gno.land/p/moul/mdtable/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module gno.land/p/moul/mdtable

require gno.land/p/demo/urequire v0.0.0-latest
66 changes: 66 additions & 0 deletions examples/gno.land/p/moul/mdtable/mdtable.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Package mdtable provides a simple way to create Markdown tables.
//
// Example usage:
//
// import "gno.land/p/moul/mdtable"
//
// func Render(path string) string {
// table := mdtable.Table{
// Headers: []string{"ID", "Title", "Status", "Date"},
// }
// table.Append([]string{"#1", "Add a new validator", "succeed", "2024-01-01"})
// table.Append([]string{"#2", "Change parameter", "timed out", "2024-01-02"})
// return table.String()
// }
//
// Output:
//
// | ID | Title | Status | Date |
// | --- | --- | --- | --- |
// | #1 | Add a new validator | succeed | 2024-01-01 |
// | #2 | Change parameter | timed out | 2024-01-02 |
package mdtable

import (
"strings"
)

type Table struct {
Headers []string
Rows [][]string
// XXX: optional headers alignment.
}

func (t *Table) Append(row []string) {
t.Rows = append(t.Rows, row)
}

func (t Table) String() string {
// XXX: switch to using text/tabwriter when porting to Gno to support
// better-formatted raw Markdown output.

if len(t.Headers) == 0 && len(t.Rows) == 0 {
return ""
}

var sb strings.Builder

if len(t.Headers) == 0 {
t.Headers = make([]string, len(t.Rows[0]))
}

// Print header.
sb.WriteString("| " + strings.Join(t.Headers, " | ") + " |\n")
sb.WriteString("|" + strings.Repeat(" --- |", len(t.Headers)) + "\n")

// Print rows.
for _, row := range t.Rows {
escapedRow := make([]string, len(row))
for i, cell := range row {
escapedRow[i] = strings.ReplaceAll(cell, "|", "&#124;") // Escape pipe characters.
}
sb.WriteString("| " + strings.Join(escapedRow, " | ") + " |\n")
}

return sb.String()
}
158 changes: 158 additions & 0 deletions examples/gno.land/p/moul/mdtable/mdtable_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package mdtable_test

import (
"testing"

"gno.land/p/demo/urequire"
"gno.land/p/moul/mdtable"
)

// XXX: switch to `func Example() {}` when supported.
func TestExample(t *testing.T) {
table := mdtable.Table{
Headers: []string{"ID", "Title", "Status"},
Rows: [][]string{
{"#1", "Add a new validator", "succeed"},
{"#2", "Change parameter", "timed out"},
{"#3", "Fill pool", "active"},
},
}

got := table.String()
expected := `| ID | Title | Status |
| --- | --- | --- |
| #1 | Add a new validator | succeed |
| #2 | Change parameter | timed out |
| #3 | Fill pool | active |
`

urequire.Equal(t, got, expected)
}

func TestTableString(t *testing.T) {
tests := []struct {
name string
table mdtable.Table
expected string
}{
{
name: "With Headers and Rows",
table: mdtable.Table{
Headers: []string{"ID", "Title", "Status", "Date"},
Rows: [][]string{
{"#1", "Add a new validator", "succeed", "2024-01-01"},
{"#2", "Change parameter", "timed out", "2024-01-02"},
},
},
expected: `| ID | Title | Status | Date |
| --- | --- | --- | --- |
| #1 | Add a new validator | succeed | 2024-01-01 |
| #2 | Change parameter | timed out | 2024-01-02 |
`,
},
{
name: "Without Headers",
table: mdtable.Table{
Rows: [][]string{
{"#1", "Add a new validator", "succeed", "2024-01-01"},
{"#2", "Change parameter", "timed out", "2024-01-02"},
},
},
expected: `| | | | |
| --- | --- | --- | --- |
| #1 | Add a new validator | succeed | 2024-01-01 |
| #2 | Change parameter | timed out | 2024-01-02 |
`,
},
{
name: "Without Rows",
table: mdtable.Table{
Headers: []string{"ID", "Title", "Status", "Date"},
},
expected: `| ID | Title | Status | Date |
| --- | --- | --- | --- |
`,
},
{
name: "With Pipe Character in Content",
table: mdtable.Table{
Headers: []string{"ID", "Title", "Status", "Date"},
Rows: [][]string{
{"#1", "Add a new | validator", "succeed", "2024-01-01"},
{"#2", "Change parameter", "timed out", "2024-01-02"},
},
},
expected: `| ID | Title | Status | Date |
| --- | --- | --- | --- |
| #1 | Add a new &#124; validator | succeed | 2024-01-01 |
| #2 | Change parameter | timed out | 2024-01-02 |
`,
},
{
name: "With Varying Row Sizes", // XXX: should we have a different behavior?
table: mdtable.Table{
Headers: []string{"ID", "Title"},
Rows: [][]string{
{"#1", "Add a new validator"},
{"#2", "Change parameter", "Extra Column"},
{"#3", "Fill pool"},
},
},
expected: `| ID | Title |
| --- | --- |
| #1 | Add a new validator |
| #2 | Change parameter | Extra Column |
| #3 | Fill pool |
`,
},
{
name: "With UTF-8 Characters",
table: mdtable.Table{
Headers: []string{"ID", "Title", "Status", "Date"},
Rows: [][]string{
{"#1", "Café", "succeed", "2024-01-01"},
{"#2", "München", "timed out", "2024-01-02"},
{"#3", "São Paulo", "active", "2024-01-03"},
},
},
expected: `| ID | Title | Status | Date |
| --- | --- | --- | --- |
| #1 | Café | succeed | 2024-01-01 |
| #2 | München | timed out | 2024-01-02 |
| #3 | São Paulo | active | 2024-01-03 |
`,
},
{
name: "With no Headers and no Rows",
table: mdtable.Table{},
expected: ``,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.table.String()
urequire.Equal(t, got, tt.expected)
})
}
}

func TestTableAppend(t *testing.T) {
table := mdtable.Table{
Headers: []string{"ID", "Title", "Status", "Date"},
}

// Use the Append method to add rows to the table
table.Append([]string{"#1", "Add a new validator", "succeed", "2024-01-01"})
table.Append([]string{"#2", "Change parameter", "timed out", "2024-01-02"})
table.Append([]string{"#3", "Fill pool", "active", "2024-01-03"})
got := table.String()

expected := `| ID | Title | Status | Date |
| --- | --- | --- | --- |
| #1 | Add a new validator | succeed | 2024-01-01 |
| #2 | Change parameter | timed out | 2024-01-02 |
| #3 | Fill pool | active | 2024-01-03 |
`
urequire.Equal(t, got, expected)
}

0 comments on commit a1812af

Please sign in to comment.