-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathhelpers.go
144 lines (129 loc) · 3.98 KB
/
helpers.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
package velvet
import (
"encoding/json"
"fmt"
"html/template"
"reflect"
"strconv"
"strings"
"sync"
"github.com/markbates/inflect"
"github.com/pkg/errors"
)
// Helpers contains all of the default helpers for velvet.
// These will be available to all templates. You should add
// any custom global helpers to this list.
var Helpers = HelperMap{
moot: &sync.Mutex{},
}
func init() {
Helpers.Add("if", ifHelper)
Helpers.Add("unless", unlessHelper)
Helpers.Add("each", eachHelper)
Helpers.Add("eq", equalHelper)
Helpers.Add("equal", equalHelper)
Helpers.Add("neq", notEqualHelper)
Helpers.Add("notequal", notEqualHelper)
Helpers.Add("json", toJSONHelper)
Helpers.Add("js_escape", template.JSEscapeString)
Helpers.Add("html_escape", template.HTMLEscapeString)
Helpers.Add("upcase", strings.ToUpper)
Helpers.Add("downcase", strings.ToLower)
Helpers.Add("content_for", contentForHelper)
Helpers.Add("content_of", contentOfHelper)
Helpers.Add("markdown", markdownHelper)
Helpers.Add("len", lenHelper)
Helpers.Add("debug", debugHelper)
Helpers.Add("inspect", inspectHelper)
Helpers.AddMany(inflect.Helpers)
}
// HelperContext is an optional context that can be passed
// as the last argument to helper functions.
type HelperContext struct {
Context *Context
Args []interface{}
evalVisitor *evalVisitor
}
// Block executes the block of template associated with
// the helper, think the block inside of an "if" or "each"
// statement.
func (h HelperContext) Block() (string, error) {
return h.BlockWith(h.Context)
}
// BlockWith executes the block of template associated with
// the helper, think the block inside of an "if" or "each"
// statement. It takes a new context with which to evaluate
// the block.
func (h HelperContext) BlockWith(ctx *Context) (string, error) {
nev := newEvalVisitor(h.evalVisitor.template, ctx)
nev.blockParams = h.evalVisitor.blockParams
dd := nev.VisitProgram(h.evalVisitor.curBlock.Program)
switch tp := dd.(type) {
case string:
return tp, nil
case error:
return "", errors.WithStack(tp)
case nil:
return "", nil
default:
return "", errors.WithStack(errors.Errorf("unknown return value %T %+v", dd, dd))
}
}
// ElseBlock executes the "inverse" block of template associated with
// the helper, think the "else" block of an "if" or "each"
// statement.
func (h HelperContext) ElseBlock() (string, error) {
return h.ElseBlockWith(h.Context)
}
// ElseBlockWith executes the "inverse" block of template associated with
// the helper, think the "else" block of an "if" or "each"
// statement. It takes a new context with which to evaluate
// the block.
func (h HelperContext) ElseBlockWith(ctx *Context) (string, error) {
if h.evalVisitor.curBlock.Inverse == nil {
return "", nil
}
nev := newEvalVisitor(h.evalVisitor.template, ctx)
nev.blockParams = h.evalVisitor.blockParams
dd := nev.VisitProgram(h.evalVisitor.curBlock.Inverse)
switch tp := dd.(type) {
case string:
return tp, nil
case error:
return "", errors.WithStack(tp)
case nil:
return "", nil
default:
return "", errors.WithStack(errors.Errorf("unknown return value %T %+v", dd, dd))
}
}
// Helpers returns a HelperMap containing all of the known helpers
func (h HelperContext) Helpers() *HelperMap {
return &h.evalVisitor.template.Helpers
}
// Get is a convenience method that calls the underlying Context.
func (h HelperContext) Get(key string) interface{} {
return h.Context.Get(key)
}
// toJSONHelper converts an interface into a string.
func toJSONHelper(v interface{}) (template.HTML, error) {
b, err := json.Marshal(v)
if err != nil {
return "", errors.WithStack(err)
}
return template.HTML(b), nil
}
func lenHelper(v interface{}) string {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
return strconv.Itoa(rv.Len())
}
// Debug by verbosely printing out using 'pre' tags.
func debugHelper(v interface{}) template.HTML {
return template.HTML(fmt.Sprintf("<pre>%+v</pre>", v))
}
func inspectHelper(v interface{}) string {
return fmt.Sprintf("%+v", v)
}