Skip to content

Commit

Permalink
Merge pull request #2 from yosssi/load-string
Browse files Browse the repository at this point in the history
Parse template strings and load templates from memory.
  • Loading branch information
yosssi committed Mar 29, 2014
2 parents f04a318 + 3fd425e commit c7da669
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 49 deletions.
91 changes: 81 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Gold - Template engine for Golang
# Gold - Template engine for Go

[![Build Status](http://128.199.249.74/github.com/yosssi/gold/status.png?branch=master)](http://128.199.249.74/github.com/yosssi/gold)
[![Coverage Status](https://coveralls.io/repos/yosssi/gold/badge.png?branch=master)](https://coveralls.io/r/yosssi/gold?branch=master)
[![GoDoc](http://godoc.org/github.com/yosssi/gold?status.png)](http://godoc.org/github.com/yosssi/gold)

Gold is a template engine for [Golang](http://golang.org/). This simplifies HTML coding in Golang web application development. This is influenced by [Slim](http://slim-lang.com/) and [Jade](http://jade-lang.com/).
Gold is a template engine for [Go](http://golang.org/). This simplifies HTML coding in Go web application development. This is influenced by [Slim](http://slim-lang.com/) and [Jade](http://jade-lang.com/).

## Example

Expand All @@ -14,14 +14,14 @@ html lang=en
head
title {{.Title}}
body
h1 Gold - Template engine for Golang
h1 Gold - Template engine for Go
#container.wrapper
{{if true}}
p You can use an expression of Golang text/template package in a Gold template.
p You can use an expression of Go text/template package in a Gold template.
{{end}}
p.
Gold is a template engine for Golang.
This simplifies HTML coding in Golang web application development.
Gold is a template engine for Go.
This simplifies HTML coding in Go web application development.
javascript:
msg = 'Welcome to Gold!';
alert(msg);
Expand All @@ -36,12 +36,12 @@ becomes
<title>Gold</title>
</head>
<body>
<h1>Gold - Template engine for Golang</h1>
<h1>Gold - Template engine for Go</h1>
<div id="container" class="wrapper">
<p>You can use an expression of Golang html/template package in a Gold template.</p>
<p>You can use an expression of Go html/template package in a Gold template.</p>
<p>
Gold is a template engine for Golang.
This simplifies HTML coding in Golang web application development.
Gold is a template engine for Go.
This simplifies HTML coding in Go web application development.
</p>
</div>
<script type="text/javascript">
Expand Down Expand Up @@ -357,6 +357,77 @@ div
{{end}}
```

### Parse template strings

You can parse template strings and load templates from memory by using the generator's `ParseString` method.

```go
package main

import (
"net/http"

"github.com/yosssi/gold"
)

// Create a generator which parses a Gold templates and
// returns a html/template package's template.
// You can have a generator cache templates by passing
// true to NewGenerator function.
var g = gold.NewGenerator(true)

func handler(w http.ResponseWriter, r *http.Request) {

// template strings
parent := `
doctype html
html
head
title Gold
body
block content
footer
block footer
`
child := `
extends parent
block content
#container
| Hello Gold
block footer
.footer
| Copyright XXX
`

stringTemplates := map[string]string{"parent": parent, "child": child}

// ParseString parses a Gold template strings and
// returns an html/template package's template.
tpl, err := g.ParseString(stringTemplates, "child")

if err != nil {
panic(err)
}

data := map[string]interface{}{"Title": "Gold"}

// Call Execute method of the html/template
// package's template.
err = tpl.Execute(w, data)

if err != nil {
panic(err)
}
}

func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
```

## Docs

* [GoDoc](http://godoc.org/github.com/yosssi/gold)
Expand Down
4 changes: 2 additions & 2 deletions block.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ func (b *Block) AppendChild(child *Element) {
}

// Html writes the block's html to the buffer.
func (b *Block) Html(bf *bytes.Buffer) {
func (b *Block) Html(bf *bytes.Buffer, stringTemplates map[string]string) {
for _, e := range b.Elements {
e.Html(bf)
e.Html(bf, stringTemplates)
}
}
2 changes: 1 addition & 1 deletion block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestBlockHtml(t *testing.T) {
}
b.AppendChild(e)
var bf bytes.Buffer
b.Html(&bf)
b.Html(&bf, nil)
if bf.String() != `<div id="id" class="class" attr="val">This is a text.</div>` {
t.Errorf("Html returns an invalid string.")
}
Expand Down
21 changes: 14 additions & 7 deletions element.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var (
}
)

// An Element represents an element of a Gold template.
// An Element represents an element of a Gold template.
type Element struct {
Text string
Tokens []string
Expand Down Expand Up @@ -189,13 +189,13 @@ func (e *Element) AppendChild(child *Element) {
}

// Html writes the element's html to the buffer.
func (e *Element) Html(bf *bytes.Buffer) error {
func (e *Element) Html(bf *bytes.Buffer, stringTemplates map[string]string) error {
switch {
case e.comment():
case e.Type == TypeContent || e.Type == TypeExpression:
e.writeText(bf)
for _, child := range e.Children {
err := child.Html(bf)
err := child.Html(bf, stringTemplates)
if err != nil {
return err
}
Expand All @@ -215,18 +215,25 @@ func (e *Element) Html(bf *bytes.Buffer) error {
if block == nil {
return errors.New(fmt.Sprintf("The sub template does not have the %s block.", name))
}
block.Html(bf)
block.Html(bf, stringTemplates)
case e.Type == TypeInclude:
if len(e.Tokens) < 2 {
return errors.New(fmt.Sprintf("The include element does not have a path. (line no: %d)", e.LineNo))
}
tpl := e.getTemplate()
incTplPath := e.Tokens[1]
g := tpl.Generator
incTpl, err := g.Parse(tpl.Dir() + e.Tokens[1] + goldExtension)
var incTpl *Template
var err error
if stringTemplates == nil {
incTpl, err = g.parse(tpl.Dir()+incTplPath+goldExtension, nil)
} else {
incTpl, err = g.parse(incTplPath, stringTemplates)
}
if err != nil {
return err
}
incHtml, err := incTpl.Html()
incHtml, err := incTpl.Html(stringTemplates)
if err != nil {
return err
}
Expand All @@ -237,7 +244,7 @@ func (e *Element) Html(bf *bytes.Buffer) error {
e.writeTextValue(bf)
}
for _, child := range e.Children {
err := child.Html(bf)
err := child.Html(bf, stringTemplates)
if err != nil {
return err
}
Expand Down
30 changes: 15 additions & 15 deletions element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ func TestElementHtml(t *testing.T) {
parent.AppendChild(child)
var bf bytes.Buffer
expectedErrMsg := fmt.Sprintf("The block element does not have a name. (line no: %d)", child.LineNo)
if err := parent.Html(&bf); err == nil || err.Error() != expectedErrMsg {
if err := parent.Html(&bf, nil); err == nil || err.Error() != expectedErrMsg {
t.Errorf("Error(%s) should be returned.", expectedErrMsg)
}

Expand All @@ -311,7 +311,7 @@ func TestElementHtml(t *testing.T) {
t.Errorf("An error(%s) occurred.", err.Error())
}
bf = bytes.Buffer{}
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}
if bf.String() != "abc" {
Expand All @@ -326,7 +326,7 @@ func TestElementHtml(t *testing.T) {
}
bf = bytes.Buffer{}
expectedErrMsg = "The template does not have a sub template."
if err := e.Html(&bf); err == nil || err.Error() != expectedErrMsg {
if err := e.Html(&bf, nil); err == nil || err.Error() != expectedErrMsg {
t.Errorf("Error(%s) should be returned.", expectedErrMsg)
}

Expand All @@ -338,7 +338,7 @@ func TestElementHtml(t *testing.T) {
}
bf = bytes.Buffer{}
expectedErrMsg = fmt.Sprintf("The sub template does not have the %s block.", e.Tokens[1])
if err := e.Html(&bf); err == nil || err.Error() != expectedErrMsg {
if err := e.Html(&bf, nil); err == nil || err.Error() != expectedErrMsg {
t.Errorf("Error(%s) should be returned.", expectedErrMsg)
}

Expand All @@ -355,7 +355,7 @@ func TestElementHtml(t *testing.T) {
t.Errorf("An error(%s) occurred.", err.Error())
}
bf = bytes.Buffer{}
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}
expectedString := `<div id="id" class="class" attr="val">This is a text.</div>`
Expand All @@ -365,32 +365,32 @@ func TestElementHtml(t *testing.T) {

// When the element's type is tag and child.Html returns an error.
e, err = NewElement("p This is a text.", 1, 0, nil, nil, nil)
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}
child, err = NewElement("block", 2, 1, e, nil, nil)
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}
e.AppendChild(child)
bf = bytes.Buffer{}
expectedErrMsg = fmt.Sprintf("The block element does not have a name. (line no: %d)", child.LineNo)
if err := e.Html(&bf); err == nil || err.Error() != expectedErrMsg {
if err := e.Html(&bf, nil); err == nil || err.Error() != expectedErrMsg {
t.Errorf("Error(%s) should be returned.", expectedErrMsg)
}

// When the element's type is tag and child.Html returns an error.
e, err = NewElement("div.class", 1, 0, nil, nil, nil)
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}
child, err = NewElement("p This is a text.", 2, 1, e, nil, nil)
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}
e.AppendChild(child)
bf = bytes.Buffer{}
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}
expectedString = `<div class="class"><p>This is a text.</p></div>`
Expand All @@ -401,7 +401,7 @@ func TestElementHtml(t *testing.T) {
// When the element's type is include and tokens' length < 2.
e, err = NewElement("include", 1, 0, nil, nil, nil)
expectedErrMsg = fmt.Sprintf("The include element does not have a path. (line no: %d)", e.LineNo)
if err := e.Html(&bf); err == nil || err.Error() != expectedErrMsg {
if err := e.Html(&bf, nil); err == nil || err.Error() != expectedErrMsg {
t.Errorf("Error(%s) should be returned.", expectedErrMsg)
}

Expand All @@ -411,7 +411,7 @@ func TestElementHtml(t *testing.T) {
e, err = NewElement("include ./somepath/somefile", 1, 0, nil, tpl, nil)
bf = bytes.Buffer{}
expectedErrMsg = "open ././somepath/somefile.gold: no such file or directory"
if err := e.Html(&bf); err == nil || err.Error() != expectedErrMsg {
if err := e.Html(&bf, nil); err == nil || err.Error() != expectedErrMsg {
t.Errorf("Error(%s) should be returned.", expectedErrMsg)
}

Expand All @@ -421,7 +421,7 @@ func TestElementHtml(t *testing.T) {
e, err = NewElement("include ./001", 1, 0, nil, tpl, nil)
bf = bytes.Buffer{}
expectedErrMsg = "The block element does not have a name. (line no: 1)"
if err := e.Html(&bf); err == nil || err.Error() != expectedErrMsg {
if err := e.Html(&bf, nil); err == nil || err.Error() != expectedErrMsg {
t.Errorf("Error(%s) should be returned.", expectedErrMsg)
}

Expand All @@ -430,7 +430,7 @@ func TestElementHtml(t *testing.T) {
tpl = NewTemplate("./test/TestElementHtml/somefile.gold", g)
e, err = NewElement("include ./002", 1, 0, nil, tpl, nil)
bf = bytes.Buffer{}
if err := e.Html(&bf); err != nil {
if err := e.Html(&bf, nil); err != nil {
t.Errorf("An error(%s) occurred.", err.Error())
}

Expand Down

0 comments on commit c7da669

Please sign in to comment.