Skip to content

Instantly share code, notes, and snippets.

@bodhi
Last active August 4, 2016 13:29
Show Gist options
  • Save bodhi/e8aa6207295e8a6574d1acd7134f495a to your computer and use it in GitHub Desktop.
Save bodhi/e8aa6207295e8a6574d1acd7134f495a to your computer and use it in GitHub Desktop.
Toy templating in Go
<div
><div
><img
src="http://lolcats.com/lolcat.jpg" alt="logo"></img>
<h1
>hello</h1>
</div>
<p
>little bobby tables: &lt;script&gt;alert(&#39;xss!&#39;)&lt;/script&gt;</p>
<ul
><li
>1</li>
<li
>2</li>
<li
>3</li>
<li
>4</li>
<li
>5</li>
<li
>6</li>
<li
>7</li>
<li
>8</li>
<li
>9</li>
</ul>
<p
>footer</p>
<ul
><li
>very important</li>
</ul>
<p
>no items</p>
</div>
package main
import (
"bytes"
"fmt"
"html/template"
)
type element interface {
flatten() string
}
type basicElement struct {
tag string
children []element
}
func (e basicElement) flatten() string {
s := fmt.Sprintf("<%s\n", e.tag)
closed := false
for _, c := range e.children {
if attr, ok := c.(attr); ok && !closed {
s += attr.flatten()
} else if !closed {
closed = true
s += ">" + c.flatten()
} else {
s += c.flatten()
}
}
if !closed {
s += ">"
}
s += fmt.Sprintf("</%s>\n", e.tag)
return s
}
type genericElement struct {
flat func() string
}
func (n genericElement) flatten() string {
return n.flat()
}
var t = template.Must(template.New("text").Parse("{{.}}"))
func text(s string) element {
return genericElement{
flat: func() string {
b := bytes.Buffer{}
t.Execute(&b, s)
return b.String()
},
}
}
func genElement(tag string) func(children ...element) element {
return func(children ...element) element {
return basicElement{
tag: tag,
children: children,
}
}
}
type attr struct {
k string
v string
}
func (a attr) flatten() string {
return " " + a.k + "=\"" + text(a.v).flatten() + "\""
}
var div = genElement("div")
var h1 = genElement("h1")
var p = genElement("p")
var ul = genElement("ul")
var li = genElement("li")
var img = genElement("img")
func header(h string) element {
return div(
img(attr{k: "src", v: "http://lolcats.com/lolcat.jpg"}, attr{k: "alt", v: "logo"}),
h1(text(h)),
)
}
func content() element {
return p(text("little bobby tables: <script>alert('xss!')</script>"))
}
func fancyList(items ...element) element {
if len(items) == 0 {
return p(text("no items"))
} else {
list := []element{}
for _, i := range items {
list = append(list, li(i))
}
return ul(list...)
}
}
func page() element {
list := []element{}
for i := 1; i < 10; i++ {
list = append(list, li(text(fmt.Sprintf("%d", i))))
}
return div(
header("hello"),
content(),
ul(list...),
p(text("footer")),
fancyList(text("very important")),
fancyList(),
)
}
func main() {
fmt.Println(page().flatten())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment