Benchmark against html/template
This commit is contained in:
parent
c00d92595e
commit
0d7bf2514d
@ -6,6 +6,8 @@ hatmill - HTML generation DSL for Go
|
|||||||
[![GoDoc](https://godoc.org/gitlab.codemonkeysoftware.net/b/hatmill?status.svg)](https://godoc.org/gitlab.codemonkeysoftware.net/b/hatmill)
|
[![GoDoc](https://godoc.org/gitlab.codemonkeysoftware.net/b/hatmill?status.svg)](https://godoc.org/gitlab.codemonkeysoftware.net/b/hatmill)
|
||||||
![Badge count](https://img.shields.io/badge/badges-5-yellow.svg)
|
![Badge count](https://img.shields.io/badge/badges-5-yellow.svg)
|
||||||
|
|
||||||
|
`hatmill` provides a simple set of types and helper functions for writing HTML in plain Go code, without having to deal with any template languages. It is not spectacularly performant, but is comparable to the `html/template` package (at least in simple cases; run `go test -bench=. -benchmem` for proof). `hatmill` “templates” are arguably easier to read and write than many template languages.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
---------------
|
---------------
|
||||||
There are three necessary packages:
|
There are three necessary packages:
|
||||||
|
104
benchmark_test.go
Normal file
104
benchmark_test.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package hatmill_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
h "gitlab.codemonkeysoftware.net/b/hatmill"
|
||||||
|
he "gitlab.codemonkeysoftware.net/b/hatmill/element"
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type benchPerson struct {
|
||||||
|
Name string
|
||||||
|
FavoriteAnimals []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type benchModel struct {
|
||||||
|
Title string
|
||||||
|
Persons []benchPerson
|
||||||
|
}
|
||||||
|
|
||||||
|
var benchData = benchModel{
|
||||||
|
Title: "People I know",
|
||||||
|
Persons: []benchPerson{
|
||||||
|
{Name: "Malter Witty", FavoriteAnimals: []string{"porpoise"}},
|
||||||
|
{Name: "Perry Moppins", FavoriteAnimals: []string{"penguin"}},
|
||||||
|
{Name: "Ralbus Fumblemore", FavoriteAnimals: []string{"owl", "cat", "toad"}},
|
||||||
|
{Name: "Wuce Brayne", FavoriteAnimals: []string{"bat", "robin"}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type testingT interface {
|
||||||
|
Helper()
|
||||||
|
Error(args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkError(t testingT, err error) {
|
||||||
|
t.Helper()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stdHtmlTemplate(t testingT) func(testingT, io.Writer, benchModel) {
|
||||||
|
// hatmill does not pretty-print its output, so neither must we here.
|
||||||
|
const tpl = `<!DOCTYPE html><html><head><title>{{.Title}}</title></head>` +
|
||||||
|
`<body>{{range .Persons}}<div><h1>{{.Name}}</h1>` +
|
||||||
|
`<ul>{{range .FavoriteAnimals}}<li>{{ . }}</li>{{end}}</ul>` +
|
||||||
|
`</div>{{end}}</body></html>`
|
||||||
|
compiled, err := template.New("page").Parse(tpl)
|
||||||
|
checkError(t, err)
|
||||||
|
return func(t testingT, w io.Writer, model benchModel) {
|
||||||
|
checkError(t, compiled.Execute(w, model))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hatmillTemplate(t testingT, w io.Writer, model benchModel) {
|
||||||
|
var personHtml h.Terms
|
||||||
|
for _, p := range model.Persons {
|
||||||
|
var animalHtml h.Terms
|
||||||
|
for _, a := range p.FavoriteAnimals {
|
||||||
|
animalHtml = append(animalHtml, he.Li()(h.Text(a)))
|
||||||
|
}
|
||||||
|
personHtml = append(personHtml, he.Div()(
|
||||||
|
he.H1()(h.Text(p.Name)),
|
||||||
|
he.Ul()(animalHtml),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
html := he.Html()(
|
||||||
|
he.Head()(
|
||||||
|
he.Title()(h.Text(model.Title)),
|
||||||
|
),
|
||||||
|
he.Body()(personHtml),
|
||||||
|
)
|
||||||
|
_, err := h.WriteDocument(w, html)
|
||||||
|
checkError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBenchmarkEquivalence(t *testing.T) {
|
||||||
|
var stdHtmlOutput bytes.Buffer
|
||||||
|
stdHtmlTemplate(t)(t, &stdHtmlOutput, benchData)
|
||||||
|
var hatmillOutput bytes.Buffer
|
||||||
|
hatmillTemplate(t, &hatmillOutput, benchData)
|
||||||
|
if stdHtmlOutput.String() != hatmillOutput.String() {
|
||||||
|
t.Fatalf("Output does not match\nhtml/template: %s\nhatmill: %s",
|
||||||
|
&stdHtmlOutput, &hatmillOutput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doBenchmark(b *testing.B, tpl func(testingT, io.Writer, benchModel)) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
buf.Reset()
|
||||||
|
tpl(b, &buf, benchData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkStdHtmlTemplate(b *testing.B) {
|
||||||
|
doBenchmark(b, stdHtmlTemplate(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHatmill(b *testing.B) {
|
||||||
|
doBenchmark(b, hatmillTemplate)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user