Last active
August 4, 2016 13:29
-
-
Save bodhi/e8aa6207295e8a6574d1acd7134f495a to your computer and use it in GitHub Desktop.
Toy templating in Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div | |
><div | |
><img | |
src="http://lolcats.com/lolcat.jpg" alt="logo"></img> | |
<h1 | |
>hello</h1> | |
</div> | |
<p | |
>little bobby tables: <script>alert('xss!')</script></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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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