Add generic Map implementation (#108)
Instead of waiting for a good time to switch the `Map` implementation, I've decided to just offer two implementations: one for Go versions before 1.18, and one for 1.18 and onwards. This is achieved using build tags in the source files. This is obviously a breaking change for consumers of this library that use Go 1.18 and onwards. See #88
This commit is contained in:
parent
3334d6c7d0
commit
f387a71230
@ -1,3 +1,6 @@
|
|||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -58,8 +61,8 @@ func Navbar(currentPath string, links []PageLink) g.Node {
|
|||||||
Ul(
|
Ul(
|
||||||
NavbarLink("/", "Home", currentPath),
|
NavbarLink("/", "Home", currentPath),
|
||||||
|
|
||||||
g.Group(g.Map(len(links), func(i int) g.Node {
|
g.Group(g.Map(links, func(pl PageLink) g.Node {
|
||||||
return NavbarLink(links[i].Path, links[i].Name, currentPath)
|
return NavbarLink(pl.Path, pl.Name, currentPath)
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -81,8 +84,8 @@ func Navbar(currentPath string, links []PageLink) g.Node {
|
|||||||
NavbarLink("/", "Home", currentPath == "/"),
|
NavbarLink("/", "Home", currentPath == "/"),
|
||||||
|
|
||||||
// We can Map custom slices to Nodes
|
// We can Map custom slices to Nodes
|
||||||
g.Group(g.Map(len(links), func(i int) g.Node {
|
g.Group(g.Map(links, func(pl PageLink) g.Node {
|
||||||
return NavbarLink(links[i].Path, links[i].Name, currentPath == links[i].Path)
|
return NavbarLink(pl.Path, pl.Name, currentPath == pl.Path)
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
2
go.mod
2
go.mod
@ -1,3 +1,3 @@
|
|||||||
module "github.com/maragudk/gomponents"
|
module "github.com/maragudk/gomponents"
|
||||||
|
|
||||||
go 1.15
|
go 1.18
|
||||||
|
@ -244,15 +244,6 @@ func Group(children []Node) Node {
|
|||||||
return group{children: children}
|
return group{children: children}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map something enumerable to a list of Nodes.
|
|
||||||
func Map(length int, cb func(i int) Node) []Node {
|
|
||||||
var nodes []Node
|
|
||||||
for i := 0; i < length; i++ {
|
|
||||||
nodes = append(nodes, cb(i))
|
|
||||||
}
|
|
||||||
return nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
// If condition is true, return the given Node. Otherwise, return nil.
|
// If condition is true, return the given Node. Otherwise, return nil.
|
||||||
// This helper function is good for inlining elements conditionally.
|
// This helper function is good for inlining elements conditionally.
|
||||||
func If(condition bool, n Node) Node {
|
func If(condition bool, n Node) Node {
|
||||||
|
13
gomponents_generic.go
Normal file
13
gomponents_generic.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package gomponents
|
||||||
|
|
||||||
|
// Map a slice of anything to a slice of Nodes.
|
||||||
|
func Map[T any](ts []T, cb func(T) Node) []Node {
|
||||||
|
var nodes []Node
|
||||||
|
for _, t := range ts {
|
||||||
|
nodes = append(nodes, cb(t))
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
34
gomponents_generic_test.go
Normal file
34
gomponents_generic_test.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package gomponents_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
g "github.com/maragudk/gomponents"
|
||||||
|
"github.com/maragudk/gomponents/internal/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMap(t *testing.T) {
|
||||||
|
t.Run("maps slices to nodes", func(t *testing.T) {
|
||||||
|
items := []string{"hat", "partyhat", "turtlehat"}
|
||||||
|
lis := g.Map(items, func(i string) g.Node {
|
||||||
|
return g.El("li", g.Text(i))
|
||||||
|
})
|
||||||
|
|
||||||
|
list := g.El("ul", lis...)
|
||||||
|
|
||||||
|
assert.Equal(t, `<ul><li>hat</li><li>partyhat</li><li>turtlehat</li></ul>`, list)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMap() {
|
||||||
|
items := []string{"party hat", "super hat"}
|
||||||
|
e := g.El("ul", g.Group(g.Map(items, func(i string) g.Node {
|
||||||
|
return g.El("li", g.Text(i))
|
||||||
|
})))
|
||||||
|
_ = e.Render(os.Stdout)
|
||||||
|
// Output: <ul><li>party hat</li><li>super hat</li></ul>
|
||||||
|
}
|
13
gomponents_non_generic.go
Normal file
13
gomponents_non_generic.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package gomponents
|
||||||
|
|
||||||
|
// Map something enumerable to a list of Nodes.
|
||||||
|
func Map(length int, cb func(i int) Node) []Node {
|
||||||
|
var nodes []Node
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
nodes = append(nodes, cb(i))
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
34
gomponents_non_generic_test.go
Normal file
34
gomponents_non_generic_test.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package gomponents_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
g "github.com/maragudk/gomponents"
|
||||||
|
"github.com/maragudk/gomponents/internal/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMap(t *testing.T) {
|
||||||
|
t.Run("maps slices to nodes", func(t *testing.T) {
|
||||||
|
items := []string{"hat", "partyhat", "turtlehat"}
|
||||||
|
lis := g.Map(len(items), func(i int) g.Node {
|
||||||
|
return g.El("li", g.Text(items[i]))
|
||||||
|
})
|
||||||
|
|
||||||
|
list := g.El("ul", lis...)
|
||||||
|
|
||||||
|
assert.Equal(t, `<ul><li>hat</li><li>partyhat</li><li>turtlehat</li></ul>`, list)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMap() {
|
||||||
|
items := []string{"party hat", "super hat"}
|
||||||
|
e := g.El("ul", g.Group(g.Map(len(items), func(i int) g.Node {
|
||||||
|
return g.El("li", g.Text(items[i]))
|
||||||
|
})))
|
||||||
|
_ = e.Render(os.Stdout)
|
||||||
|
// Output: <ul><li>party hat</li><li>super hat</li></ul>
|
||||||
|
}
|
@ -133,7 +133,7 @@ func TestEl(t *testing.T) {
|
|||||||
assert.Equal(t, `<div class="hat"><br></div>`, e)
|
assert.Equal(t, `<div class="hat"><br></div>`, e)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("renders outside if node does not implement placer", func(t *testing.T) {
|
t.Run("renders outside if node does not implement nodeTypeDescriber", func(t *testing.T) {
|
||||||
e := g.El("div", outsider{})
|
e := g.El("div", outsider{})
|
||||||
assert.Equal(t, `<div>outsider</div>`, e)
|
assert.Equal(t, `<div>outsider</div>`, e)
|
||||||
})
|
})
|
||||||
@ -248,28 +248,6 @@ func TestGroup(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMap(t *testing.T) {
|
|
||||||
t.Run("maps slices to nodes", func(t *testing.T) {
|
|
||||||
items := []string{"hat", "partyhat", "turtlehat"}
|
|
||||||
lis := g.Map(len(items), func(i int) g.Node {
|
|
||||||
return g.El("li", g.Text(items[i]))
|
|
||||||
})
|
|
||||||
|
|
||||||
list := g.El("ul", lis...)
|
|
||||||
|
|
||||||
assert.Equal(t, `<ul><li>hat</li><li>partyhat</li><li>turtlehat</li></ul>`, list)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleMap() {
|
|
||||||
items := []string{"party hat", "super hat"}
|
|
||||||
e := g.El("ul", g.Group(g.Map(len(items), func(i int) g.Node {
|
|
||||||
return g.El("li", g.Text(items[i]))
|
|
||||||
})))
|
|
||||||
_ = e.Render(os.Stdout)
|
|
||||||
// Output: <ul><li>party hat</li><li>super hat</li></ul>
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIf(t *testing.T) {
|
func TestIf(t *testing.T) {
|
||||||
t.Run("returns node if condition is true", func(t *testing.T) {
|
t.Run("returns node if condition is true", func(t *testing.T) {
|
||||||
n := g.El("div", g.If(true, g.El("span")))
|
n := g.El("div", g.If(true, g.El("span")))
|
||||||
|
Loading…
Reference in New Issue
Block a user