-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgostache.go
executable file
·159 lines (140 loc) · 4.01 KB
/
gostache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package gostache
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"reflect"
"regexp"
"strings"
)
type Template struct {
Template string
Context interface{}
}
func (t *Template) ParseSection(body string) (string, error) {
return body, nil
}
// ParsePartial will find all occurences of the partial-mustache pattern
// in body and replace it with the content of the partial template file that
// matches the name used in the partial-mustache pattern if any such file exist
// parsePartial assumes that partials are placed inside the
// templates/partials/ directory in the current-working-directory
func (t *Template) ParsePartial(body string) (string, error) {
r := regexp.MustCompile(`{{>(\w+)}}`)
matches := r.FindAllStringSubmatch(body, -1)
for _, match := range matches {
if len(match) > 0 {
cwd := os.Getenv("CWD")
filename := match[1]
filepath := cwd + "templates/partials/" + filename + ".mustache"
f, err := os.Open(filepath)
f.Close()
if err != nil {
return "", err
}
partial_template, err := ioutil.ReadFile(filepath)
if err != nil {
return "", err
}
body = strings.Replace(body, "{{>"+filename+"}}", string(partial_template), -1)
}
}
return body, nil
}
// ParseString will find all occurences of the triple- and double-mustache
// pattern and replace it with the string value of the field in t.Context that
// matches and one exist
func (t *Template) ParseString(body string) (string, error) {
triple := regexp.MustCompile(`{{{(\w+)}}}`)
double := regexp.MustCompile(`{{(\w+)}}`)
rgs := [2]*regexp.Regexp{triple, double}
for _, r := range rgs {
matches := r.FindAllStringSubmatch(body, -1)
for _, match := range matches {
if len(match) > 0 {
pattern := match[0]
fieldname := match[1]
v := reflect.ValueOf(t.Context)
value := v.FieldByName(fieldname)
new_str := fmt.Sprintf("%v", value.Interface())
var old_str string
if len(pattern) == (len(fieldname) + 4) {
old_str = "{{" + fieldname + "}}"
new_str = HTMLEscape(new_str)
} else {
old_str = "{{{" + fieldname + "}}}"
}
body = strings.Replace(body, old_str, new_str, -1)
}
}
}
return body, nil
}
// Render will consecutively call t.ParsePartial, t.ParseSection and
// t.ParseString on t.Template
// The order of the calls are quite important - if you for example call
// t.ParseString before t.ParseSection, the mustache-sections will lose
// context
func (t *Template) Render() (string, error) {
body := t.Template
err := errors.New("")
body, err = t.ParsePartial(body)
if err != nil {
return "", err
}
body, err = t.ParseSection(body)
if err != nil {
return "", err
}
body, err = t.ParseString(body)
if err != nil {
return "", err
}
return body, nil
}
// RenderString will create a Template structure of the template and context
// parameters and then ask Template.Render to render it. It then returns the
// return value from Template.Render.
func RenderString(template string, context interface{}) string {
tmpl := Template{template, context}
body, err := tmpl.Render()
if err != nil {
log.Fatal(err)
}
return body
}
// RenderFile will look for a mustache-file in the templates directory of the
// current-working-directory, and if it finds it, it reads its content and
// passes that along with the context to RenderString. It will then take
// the result from RenderString and return that.
func RenderFile(filename string, context interface{}) string {
cwd := os.Getenv("CWD")
filepath := cwd + "templates/" + filename + ".mustache"
f, err := os.Open(filepath)
f.Close()
if err != nil {
log.Fatal(err)
}
template, err := ioutil.ReadFile(filepath)
if err != nil {
log.Fatal(err)
}
body := RenderString(string(template), context)
return body
}
// HTMLEscape replaces all applicable characters to HTML entities
func HTMLEscape(str string) string {
chars := [5][2]string{
{"&", "&"},
{"\"", """},
{"'", "'"},
{"<", "<"},
{">", ">"},
}
for _, n := range chars {
str = strings.Replace(str, n[0], n[1], -1)
}
return str
}