-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tplfunc.go
125 lines (110 loc) · 2.48 KB
/
tplfunc.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
package tplfunc
import (
"fmt"
"reflect"
"strings"
"text/template"
"time"
"zgo.at/zstd/ztime"
)
// Add a new template function.
func Add(name string, f any) { FuncMap[name] = f }
// FuncMap contains all the template functions.
var FuncMap = template.FuncMap{
// Math
"int": Int,
"sum": Sum,
"sub": Sub,
"mult": Mult,
"div": Div,
"round": Round,
"abs": Abs,
"is_inf": IsInf,
"min": Min,
"max": Max,
// Strings
"substr": Substr,
"elide": Elide,
"has_prefix": HasPrefix,
"has_suffix": HasSuffix,
"join": strings.Join,
"ucfirst": UCFirst,
"cat": Cat,
// Misc
"deref": Deref,
"if2": If2,
"map": Map,
"contains": Contains,
"before": Before,
"after": After,
// Formatting
"json": JSON,
"json_pretty": JSONPretty,
"number": Number,
"large_number": LargeNumber,
"time": Time,
"duration": Duration,
"size": Size,
"slug": Slug,
}
// Deref dereferences a pointer.
func Deref(s any) any {
v := reflect.ValueOf(s)
for v.Kind() == reflect.Ptr {
if v.IsNil() {
return reflect.New(reflect.TypeOf(s).Elem()).Interface()
}
v = v.Elem()
}
return v.Interface()
}
// If2 returns yes if cond is true, and no otherwise.
func If2(cond bool, yes any, no ...any) any {
if cond {
return yes
}
switch len(no) {
case 0:
return ""
case 1:
return no[0]
default:
panic("if2: too many parameters")
}
}
// Map creates a map
func Map(values ...any) map[string]any {
if len(values)%2 != 0 {
panic("map: need key/value")
}
dict := make(map[string]any, len(values)/2)
for i := 0; i < len(values); i += 2 {
key, ok := values[i].(string)
if !ok {
panic(fmt.Sprintf("map: key must be a string: %T: %#[1]v", key))
}
dict[key] = values[i+1]
}
return dict
}
// Contains reports if the slice contains the element value find.
func Contains(slice any, find any) bool {
// Can't use type parameters with text/template :-/
sliceV, findV := reflect.ValueOf(slice), reflect.ValueOf(find)
if !sliceV.IsValid() {
return false
}
if findV.Type() != sliceV.Type().Elem() {
panic(fmt.Sprintf("mismatched types: %s and %s", sliceV.Type(), findV.Type()))
}
for i, l := 0, sliceV.Len(); i < l; i++ {
if sliceV.Index(i).Equal(findV) {
return true
}
}
return false
}
// t is before tt.
func Before(t time.Time, tt string) bool { return t.Before(ztime.FromString(tt)) }
// t is after tt.
func After(t time.Time, tt string) bool { return t.After(ztime.FromString(tt)) }