Documentation
¶
Overview ¶
Package doublebrace provides a stdlib-only template.FuncMap for use with Go's text/template and html/template packages.
All functions follow Go stdlib argument order: the primary value is the first argument. This matches direct Go calls and avoids pipeline-optimized argument order confusion. Single-argument functions work naturally in pipelines regardless.
Usage ¶
import "github.com/client9/doublebrace"
t := template.New("page").Funcs(doublebrace.FuncMap())
To combine with your own functions:
fns := doublebrace.Merge(doublebrace.FuncMap(), template.FuncMap{
"myFunc": myFunc,
})
t := template.New("page").Funcs(fns)
Strings ¶
- lower(s) string — convert to lowercase
- upper(s) string — convert to uppercase
- trim(s) string — remove leading and trailing whitespace
- trimPrefix(s, prefix) string — remove prefix if present
- trimSuffix(s, suffix) string — remove suffix if present
- trimLeft(s, cutset) string — remove leading characters contained in cutset
- trimRight(s, cutset) string — remove trailing characters contained in cutset
- contains(s, substr) bool — report whether substr is within s
- hasPrefix(s, prefix) bool — report whether s begins with prefix
- hasSuffix(s, suffix) bool — report whether s ends with suffix
- count(s, substr) int — count non-overlapping instances of substr in s; "" counts runes+1
- replace(s, old, new [, n]) string — replace first occurrence of old with new; optional n sets limit (-1 replaces all)
- replaceAll(s, old, new) string — replace all occurrences of old with new
- repeat(s, n) string — return n copies of s concatenated
- split(s, sep) []string — split s into substrings separated by sep
- join(elems, sep) string — join elements with sep; elems must be []string
- fields(s) []string — split s on whitespace, discarding empty strings
- lenRunes(s) int — number of runes in s; unlike built-in len which counts bytes
- truncate(s, n) string — shorten to at most n runes; appends "…" if truncated
- firstUpper(s) string — uppercase first rune only; all other characters unchanged
Math ¶
All math functions accept any numeric type or numeric string as input. Results are float64; use printf for integer formatting.
- add(a, b) float64 — a + b
- sub(a, b) float64 — a - b
- mul(a, b) float64 — a * b
- div(a, b) float64 — a / b; error on zero divisor
- mod(a, b) float64 — floating-point remainder of a/b; error on zero divisor
- modBool(a, b) bool — report whether a is evenly divisible by b; useful for alternating rows
- abs(a) float64 — absolute value
- ceil(a) float64 — least integer value ≥ a
- floor(a) float64 — greatest integer value ≤ a
- round(a) float64 — nearest integer, rounding half away from zero
- pow(base, exp) float64 — base raised to exp
- min(args...) float64 — minimum value; accepts scalars, slices, or a mix
- max(args...) float64 — maximum value; accepts scalars, slices, or a mix
- clamp(val, min, max) float64 — constrain val to [min, max]
Encoding ¶
- jsonify(v) string — marshal v to JSON; useful for <script> data blocks
Cast ¶
Cast functions convert values between types. Useful when frontmatter values arrive as strings and numeric operations are needed.
- toInt(v) int — convert to int; floats are truncated toward zero
- toFloat(v) float64 — convert to float64
Time ¶
Time functions return time.Time values. Use Go's time.Time methods directly in templates for formatting and field access: {{.Date.Format "2006-01-02"}}, {{.Date.Year}}, {{.Date.Weekday}}, etc.
- now() time.Time — current local time; use {{now.UTC}} for UTC
- parseTime(layout, s) time.Time — parse s using Go reference-time layout
Path ¶
Path functions use forward slashes regardless of OS (suitable for URLs). They wrap the stdlib path package, not filepath.
- pathBase(p) string — last element of p; "foo/bar.html" → "bar.html"
- pathDir(p) string — all but last element; "foo/bar.html" → "foo"
- pathExt(p) string — file extension including dot; "bar.html" → ".html"
- pathJoin(elems...) string — join elements and clean the result
- pathClean(p) string — normalize: resolve . and .., remove double slashes
Safe Types ¶
These functions wrap string values in html/template typed aliases, preventing the template engine from escaping content that has already been sanitized. All accept string, []byte, any html/template typed value, or any type via fmt.Sprint. nil is an error.
- safeCSS(s) template.CSS — mark s safe for style attributes and <style> blocks
- safeHTML(s) template.HTML — mark s safe to render as raw HTML without escaping
- safeHTMLAttr(s) template.HTMLAttr — mark s safe as an HTML attribute name/value pair
- safeJS(s) template.JS — mark s safe for use inside <script> blocks
- safeJSStr(s) template.JSStr — mark s safe for interpolation inside JS string literals
- safeURL(s) template.URL — mark s safe for use in href/src/action attributes
URL Encoding ¶
- urlEncode(s) string — percent-encode for query strings; spaces become +
- urlPathEscape(s) string — percent-encode a single path segment; / is encoded too
Collections — Constructors ¶
- list(elems...) []any — create a slice from values: list "a" "b" "c"
- dict(k, v, ...) map[string]any — create a map from key-value pairs: dict "name" "Alice"
- seq(n) []int — integers 1..n (1-based)
- seq(start, end) []int — integers start..end inclusive
- seq(start, end, step) []int — with step; negative step counts down
Collections — Sequence Access ¶
These functions operate on any slice type or string. String operations are rune-aware: multi-byte characters are never split.
- first(v) any — first element of a slice, or first rune of a string
- last(v) any — last element of a slice, or last rune of a string
- take(v, n) any — first n elements of a slice, or first n runes of a string; negative n takes from the end
- drop(v, n) any — skip first n elements of a slice, or first n runes of a string; negative n removes from the end
Collections — Sequence Transformation ¶
- reverse(v) []any — new slice in reverse order
- compact(v) []any — remove consecutive duplicate elements; for full dedup: compact (sort $list)
- concat(slices...) []any — concatenate multiple slices into one
- sort(v [, key]) []any — type-aware sort: numeric types sort numerically, time.Time sorts chronologically, everything else sorts lexicographically; for []any the first non-nil element determines mode; key names a field for slice-of-maps (always lexicographic)
- sortNum(v [, key]) []any — numeric sort via float64 conversion; key names a field for slice-of-maps
- where(v, key, val) []any — filter slice of map[string]any where element[key] == val
For descending order compose with reverse: reverse (sort $pages "Title")
ISO 8601 date strings ("2006-01-02") sort correctly with lexicographic order.
Collections — Map Operations ¶
- keys(m) []string — sorted keys of a map[string]any
- values(m) []any — values of a map[string]any ordered by sorted keys
- merge(maps...) map[string]any — shallow merge; later maps win on key collision
Collections — General ¶
- in(v, val) bool — membership test: slice (element), map (key existence), string (substring)
- default(def, val) any — return val if non-zero, else def; zero: nil, false, 0, "", empty slice/map
- cond(ctrl, a, b) any — ternary: return a if ctrl is truthy, else b
Index ¶
- func Abs(a any) (float64, error)
- func Add(a, b any) (float64, error)
- func Ceil(a any) (float64, error)
- func Clamp(val, minVal, maxVal any) (float64, error)
- func Compact(v any) (any, error)
- func Concat(ins ...any) ([]any, error)
- func Cond(ctrl, a, b any) any
- func Default(def, val any) any
- func Dict(kvs ...any) (map[string]any, error)
- func Div(a, b any) (float64, error)
- func Drop(v any, n int) (any, error)
- func First(v any) (any, error)
- func FirstUpper(s string) string
- func Floor(a any) (float64, error)
- func FuncMap() template.FuncMap
- func In(v, val any) (bool, error)
- func Jsonify(v any) (string, error)
- func Keys(v any) ([]string, error)
- func Last(v any) (any, error)
- func LenRunes(s string) int
- func List(elems ...any) []any
- func Max(args ...any) (float64, error)
- func Merge(fms ...template.FuncMap) template.FuncMap
- func MergeMaps(mapsIn ...any) (map[string]any, error)
- func Min(args ...any) (float64, error)
- func Mod(a, b any) (float64, error)
- func ModBool(a, b any) (bool, error)
- func Mul(a, b any) (float64, error)
- func Now() time.Time
- func ParseTime(layout, s string) (time.Time, error)
- func PathBase(p string) string
- func PathClean(p string) string
- func PathDir(p string) string
- func PathExt(p string) string
- func PathJoin(elems ...string) string
- func Pow(base, exp any) (float64, error)
- func Replace(s, old, new string, n ...int) string
- func Reverse(v any) (any, error)
- func Round(a any) (float64, error)
- func SafeCSS(s any) (template.CSS, error)
- func SafeHTML(s any) (template.HTML, error)
- func SafeHTMLAttr(s any) (template.HTMLAttr, error)
- func SafeJS(s any) (template.JS, error)
- func SafeJSStr(s any) (template.JSStr, error)
- func SafeURL(s any) (template.URL, error)
- func Seq(args ...int) ([]int, error)
- func Sort(v any, key ...string) (any, error)
- func SortNum(v any, key ...string) (any, error)
- func Sub(a, b any) (float64, error)
- func Take(v any, n int) (any, error)
- func ToFloat(v any) (float64, error)
- func ToInt(v any) (int, error)
- func Truncate(s string, n int) string
- func URLEncode(s string) string
- func URLPathEscape(s string) string
- func Values(v any) ([]any, error)
- func Where(v any, key string, val any) (any, error)
Examples ¶
- Abs
- Add
- Ceil
- Clamp
- Compact
- Concat
- Cond
- Default
- Dict
- Div
- Drop
- Drop (Negative)
- Drop (String)
- First
- First (String)
- FirstUpper
- Floor
- FuncMap
- In (Map)
- In (Slice)
- In (String)
- Jsonify
- Jsonify (Slice)
- Keys
- Last
- Last (String)
- LenRunes
- List
- Max
- Merge
- MergeMaps
- Min
- Min (Slice)
- Mod
- ModBool
- Mul
- Now
- ParseTime
- PathBase
- PathClean
- PathDir
- PathExt
- PathJoin
- Pow
- Pow (Sqrt)
- Replace
- Replace (Count)
- Reverse
- Round
- SafeCSS
- SafeHTML
- SafeHTMLAttr
- SafeJS
- SafeJSStr
- SafeURL
- Seq
- Seq (Range)
- Seq (Step)
- Sort
- Sort (Numeric)
- Sort (Time)
- SortNum
- Sub
- Take
- Take (Negative)
- Take (String)
- ToFloat
- ToInt
- ToInt (Float)
- Truncate
- URLEncode
- URLPathEscape
- Values
- Where
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Abs ¶
Abs returns the absolute value of a.
abs -7 → 7 abs 3 → 3
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Abs(-7)
fmt.Println(v)
}
Output: 7
func Add ¶
Add returns a + b. Both arguments accept any numeric type or numeric string.
add 3 4 → 7 add 1.5 2 → 3.5
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Add(3, 4)
fmt.Println(v)
}
Output: 7
func Ceil ¶
Ceil returns the least integer value greater than or equal to a.
ceil 1.2 → 2 ceil 2.0 → 2
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Ceil(1.2)
fmt.Println(v)
}
Output: 2
func Clamp ¶
Clamp constrains val to the range [min, max]. If val < min, min is returned; if val > max, max is returned; otherwise val is returned unchanged. All arguments accept any numeric type or numeric string.
clamp 5 1 10 → 5 clamp 0 1 10 → 1 clamp 15 1 10 → 10
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
within, _ := doublebrace.Clamp(5, 1, 10)
below, _ := doublebrace.Clamp(0, 1, 10)
above, _ := doublebrace.Clamp(15, 1, 10)
fmt.Println(within, below, above)
}
Output: 5 1 10
func Compact ¶
Compact removes consecutive duplicate elements, identical to slices.Compact semantics. For full deduplication use: compact (sort $list)
compact []int{1, 1, 2, 3, 3, 1} → []any{1, 2, 3, 1}
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Compact([]any{1, 1, 2, 3, 3, 1})
fmt.Println(v)
}
Output: [1 2 3 1]
func Concat ¶
Concat concatenates multiple slices into a single []any.
concat (list 1 2) (list 3 4) → []any{1, 2, 3, 4}
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Concat([]int{1, 2}, []int{3, 4})
fmt.Println(v)
}
Output: [1 2 3 4]
func Cond ¶
Cond returns a if ctrl is truthy (non-zero), otherwise b.
cond true "yes" "no" → "yes" cond false "yes" "no" → "no" cond "" "yes" "no" → "no" cond 1 "yes" "no" → "yes"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.Cond(true, "yes", "no"))
fmt.Println(doublebrace.Cond(false, "yes", "no"))
fmt.Println(doublebrace.Cond(0, "yes", "no"))
}
Output: yes no no
func Default ¶
Default returns val if it is non-zero, otherwise def. Zero values: nil, false, 0, "", and empty slices/maps.
default "anon" "" → "anon" default "anon" "Alice" → "Alice" default 0 42 → 42
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.Default("anon", ""))
fmt.Println(doublebrace.Default("anon", "Alice"))
}
Output: anon Alice
func Dict ¶
Dict creates a map[string]any from alternating key-value arguments. Returns an error if the argument count is odd or a key is not a string.
dict "name" "Alice" "age" 30 → map[string]any{"name": "Alice", "age": 30}
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
m, _ := doublebrace.Dict("name", "Alice", "age", 30)
fmt.Println(m["name"], m["age"])
}
Output: Alice 30
func Div ¶
Div returns a / b. Returns an error on division by zero. Both arguments accept any numeric type or numeric string.
div 10 4 → 2.5
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Div(10, 4)
fmt.Println(v)
}
Output: 2.5
func Drop ¶
Drop skips the first n elements of a slice, or the first n runes of a string. If n is negative, it removes the last |n| elements or runes. If |n| exceeds the length an empty result is returned. Rune-aware for strings: multi-byte characters are not split.
drop []int{1, 2, 3, 4, 5} 2 → []any{3, 4, 5}
drop []int{1, 2, 3, 4, 5} -2 → []any{1, 2, 3}
drop "日本語" 1 → "本語"
drop "日本語" -1 → "日本"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Drop([]int{1, 2, 3, 4, 5}, 2)
fmt.Println(v)
}
Output: [3 4 5]
Example (Negative) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Drop([]int{1, 2, 3, 4, 5}, -2)
fmt.Println(v)
}
Output: [1 2 3]
Example (String) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Drop("hello", 2)
fmt.Println(v)
}
Output: llo
func First ¶
First returns the first element of a slice, or the first rune of a string.
first []int{1, 2, 3} → 1
first "café" → "c"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.First([]string{"a", "b", "c"})
fmt.Println(v)
}
Output: a
Example (String) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.First("café")
fmt.Println(v)
}
Output: c
func FirstUpper ¶
FirstUpper returns s with the first rune converted to its Unicode title case. All other characters are left unchanged. It is rune-safe: multi-byte leading characters such as "é" are handled correctly.
firstUpper "go" → "Go" firstUpper "hello world" → "Hello world" firstUpper "élan" → "Élan"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.FirstUpper("go"))
fmt.Println(doublebrace.FirstUpper("hello world"))
fmt.Println(doublebrace.FirstUpper("élan"))
}
Output: Go Hello world Élan
func Floor ¶
Floor returns the greatest integer value less than or equal to a.
floor 1.9 → 1 floor 2.0 → 2
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Floor(1.9)
fmt.Println(v)
}
Output: 1
func FuncMap ¶
FuncMap returns a template.FuncMap containing all standard functions. See the package documentation for the full list.
Example ¶
package main
import (
"html/template"
"github.com/client9/doublebrace"
)
func main() {
fm := doublebrace.FuncMap()
t := template.Must(template.New("").Funcs(fm).Parse(`{{upper "hello"}}`))
_ = t.Execute(nil, nil)
// (FuncMap registers all template functions; use with template.New().Funcs())
}
Output:
func In ¶
In reports whether val is present in v.
slice: element membership via reflect.DeepEqual
map[string]any: key existence (val must be string)
string: substring search (val must be string)
in (list "a" "b" "c") "b" → true in (dict "x" 1) "x" → true in "hello world" "world" → true
Example (Map) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
ok, _ := doublebrace.In(map[string]any{"x": 1}, "x")
fmt.Println(ok)
}
Output: true
Example (Slice) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
ok, _ := doublebrace.In([]string{"a", "b", "c"}, "b")
fmt.Println(ok)
}
Output: true
Example (String) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
ok, _ := doublebrace.In("hello world", "world")
fmt.Println(ok)
}
Output: true
func Jsonify ¶
Jsonify marshals v to a JSON string. Useful for embedding data in <script> blocks or data attributes.
jsonify (dict "name" "Alice" "age" 30) → {"age":30,"name":"Alice"}
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Jsonify(map[string]any{"name": "Alice", "age": 30})
fmt.Println(v)
}
Output: {"age":30,"name":"Alice"}
Example (Slice) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Jsonify([]string{"a", "b", "c"})
fmt.Println(v)
}
Output: ["a","b","c"]
func Keys ¶
Keys returns the keys of a map[string]any in sorted order.
keys map[string]any{"b": 2, "a": 1} → ["a" "b"]
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
m := map[string]any{"b": 2, "a": 1, "c": 3}
k, _ := doublebrace.Keys(m)
fmt.Println(k)
}
Output: [a b c]
func Last ¶
Last returns the last element of a slice, or the last rune of a string.
last []int{1, 2, 3} → 3
last "café" → "é"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Last([]string{"a", "b", "c"})
fmt.Println(v)
}
Output: c
Example (String) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Last("café")
fmt.Println(v)
}
Output: é
func LenRunes ¶
LenRunes returns the number of runes in s. Unlike the built-in len, which counts bytes, LenRunes counts characters — so multi-byte characters such as "é" or "日" each count as one.
lenRunes "café" → 4 lenRunes "日本語" → 3
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.LenRunes("café"))
fmt.Println(doublebrace.LenRunes("日本語"))
}
Output: 4 3
func List ¶
List creates a []any from the given values.
list "a" "b" "c" → []any{"a", "b", "c"}
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
s := doublebrace.List("a", "b", "c")
fmt.Println(s)
}
Output: [a b c]
func Max ¶
Max returns the largest value among the given numbers. Accepts one or more scalars, slices, or a mix; slices are flattened recursively.
Max(3, 1, 2) → 3
Max([]int{5, 2, 8}) → 8
Max([]int{5, 2}, 9, 1) → 9
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Max(3, 1, 4, 1, 5, 9)
fmt.Println(v)
}
Output: 9
func Merge ¶
Merge combines multiple template.FuncMaps into one new map. Later maps win on key collision, so user-defined functions override defaults:
fns := funcs.Merge(funcs.FuncMap(), template.FuncMap{"myFunc": myFunc})
Example ¶
package main
import (
"html/template"
"github.com/client9/doublebrace"
)
func main() {
custom := template.FuncMap{
"greet": func(name string) string { return "Hello, " + name + "!" },
}
fm := doublebrace.Merge(doublebrace.FuncMap(), custom)
t := template.Must(template.New("").Funcs(fm).Parse(`{{greet "World"}}`))
_ = t.Execute(nil, nil)
// (Merge combines FuncMaps; later maps win on key collision)
}
Output:
func MergeMaps ¶
MergeMaps combines map[string]any maps into a new map. Later maps win on key collision. Registered as "merge" in the template FuncMap.
merge (dict "a" 1 "b" 2) (dict "b" 99 "c" 3) → {"a":1, "b":99, "c":3}
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
a := map[string]any{"x": 1, "y": 2}
b := map[string]any{"y": 99, "z": 3}
m, _ := doublebrace.MergeMaps(a, b)
fmt.Println(m["x"], m["y"], m["z"])
}
Output: 1 99 3
func Min ¶
Min returns the smallest value among the given numbers. Accepts one or more scalars, slices, or a mix; slices are flattened recursively.
Min(3, 1, 2) → 1
Min([]int{5, 2, 8}) → 2
Min([]int{5, 2}, 1, 9) → 1
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Min(3, 1, 4, 1, 5, 9)
fmt.Println(v)
}
Output: 1
Example (Slice) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Min([]int{7, 2, 8})
fmt.Println(v)
}
Output: 2
func Mod ¶
Mod returns the floating-point remainder of a / b (math.Mod). Returns an error on division by zero. Both arguments accept any numeric type or numeric string.
mod 10 3 → 1
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Mod(10, 3)
fmt.Println(v)
}
Output: 1
func ModBool ¶
ModBool reports whether a is evenly divisible by b (a mod b == 0). Useful for alternating row styles: {{if modBool $i 2}}even{{end}}
ModBool(4, 2) → true ModBool(5, 2) → false
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
even, _ := doublebrace.ModBool(4, 2)
odd, _ := doublebrace.ModBool(5, 2)
fmt.Println(even, odd)
}
Output: true false
func Mul ¶
Mul returns a * b. Both arguments accept any numeric type or numeric string.
mul 3 4 → 12
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Mul(3, 4)
fmt.Println(v)
}
Output: 12
func Now ¶
Now returns the current local time. The returned time.Time value supports method calls in templates: {{now.Year}}, {{now.Format "2006-01-02"}}, etc.
Example ¶
package main
import (
"github.com/client9/doublebrace"
)
func main() {
t := doublebrace.Now()
_ = t
// Returns current local time as time.Time.
// In templates: {{now.Year}}, {{now.Format "2006-01-02"}}
}
Output:
func ParseTime ¶
ParseTime parses a formatted string and returns the time.Time value it represents. The layout defines the format using Go's reference time: Mon Jan 2 15:04:05 MST 2006.
parseTime "2006-01-02" "2024-03-15" → 2024-03-15 00:00:00 +0000 UTC
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
t, _ := doublebrace.ParseTime("2006-01-02", "2024-03-15")
fmt.Println(t.Format("January 2, 2006"))
}
Output: March 15, 2024
func PathBase ¶
PathBase returns the last element of a slash-separated path. Trailing slashes are removed before extracting the last element.
pathBase "/a/b/c.html" → "c.html" pathBase "/a/b/" → "b"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.PathBase("/a/b/c.html"))
fmt.Println(doublebrace.PathBase("/a/b/"))
}
Output: c.html b
func PathClean ¶
PathClean returns the shortest equivalent path by applying lexical rules.
pathClean "/a/b/../c" → "/a/c" pathClean "a//b" → "a/b"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.PathClean("/a/b/../c"))
fmt.Println(doublebrace.PathClean("a//b"))
}
Output: /a/c a/b
func PathDir ¶
PathDir returns all but the last element of a slash-separated path.
pathDir "/a/b/c.html" → "/a/b" pathDir "/a/b/" → "/a/b"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.PathDir("/a/b/c.html"))
}
Output: /a/b
func PathExt ¶
PathExt returns the file extension of the last element of a path, including the leading dot. Returns "" if there is no extension.
pathExt "index.html" → ".html" pathExt "Makefile" → ""
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.PathExt("index.html"))
fmt.Println(doublebrace.PathExt("Makefile"))
}
Output: .html
func PathJoin ¶
PathJoin joins path elements with slashes and cleans the result.
pathJoin "/a" "b" "c.html" → "/a/b/c.html"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.PathJoin("/a", "b", "c.html"))
}
Output: /a/b/c.html
func Pow ¶
Pow returns base raised to the power of exp.
Pow(2, 10) → 1024 Pow(9, 0.5) → 3 (square root)
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Pow(2, 10)
fmt.Println(v)
}
Output: 1024
Example (Sqrt) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Pow(9, 0.5)
fmt.Println(v)
}
Output: 3
func Replace ¶
Replace returns a copy of s with occurrences of old replaced by new. The optional n argument limits the number of replacements; if omitted, only the first occurrence is replaced. Use replaceAll to replace all.
replace "aabbaa" "a" "x" → "xabbaa" replace "aabbaa" "a" "x" 3 → "xxbbxa" replace "aabbaa" "a" "x" -1 → "xxbbxx"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.Replace("aabbaa", "a", "x"))
}
Output: xabbaa
Example (Count) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.Replace("aabbaa", "a", "x", -1))
}
Output: xxbbxx
func Reverse ¶
Reverse returns a new slice with the elements in reverse order.
reverse []int{1, 2, 3} → []any{3, 2, 1}
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Reverse([]int{1, 2, 3})
fmt.Println(v)
}
Output: [3 2 1]
func Round ¶
Round returns the nearest integer, rounding half away from zero.
round 1.4 → 1 round 1.5 → 2
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
lo, _ := doublebrace.Round(1.4)
hi, _ := doublebrace.Round(1.5)
fmt.Println(lo, hi)
}
Output: 1 2
func SafeCSS ¶
SafeCSS converts s to template.CSS, marking it safe for use in style attributes and <style> blocks without escaping.
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.SafeCSS("color: red")
fmt.Println(v)
}
Output: color: red
func SafeHTML ¶
SafeHTML converts s to template.HTML, marking it safe to render as raw HTML without escaping. Use only with trusted content.
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.SafeHTML("<b>bold</b>")
fmt.Println(v)
}
Output: <b>bold</b>
func SafeHTMLAttr ¶
SafeHTMLAttr converts s to template.HTMLAttr, marking it safe for use as an HTML attribute (name and value pair) without escaping.
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.SafeHTMLAttr(`class="hero"`)
fmt.Println(v)
}
Output: class="hero"
func SafeJS ¶
SafeJS converts s to template.JS, marking it safe for use inside <script> blocks without escaping.
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.SafeJS("alert('hi')")
fmt.Println(v)
}
Output: alert('hi')
func SafeJSStr ¶
SafeJSStr converts s to template.JSStr, marking it safe for interpolation inside a JavaScript string literal without escaping.
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.SafeJSStr(`hello\nworld`)
fmt.Println(v)
}
Output: hello\nworld
func SafeURL ¶
SafeURL converts s to template.URL, marking it safe for use in URL attributes (href, src, action, etc.) without escaping.
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.SafeURL("https://example.com/path?q=1")
fmt.Println(v)
}
Output: https://example.com/path?q=1
func Seq ¶
Seq returns a slice of integers. Counting is 1-based by default.
seq 5 → [1 2 3 4 5] seq 3 7 → [3 4 5 6 7] seq 1 10 2 → [1 3 5 7 9] seq 5 1 -1 → [5 4 3 2 1]
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
s, _ := doublebrace.Seq(5)
fmt.Println(s)
}
Output: [1 2 3 4 5]
Example (Range) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
s, _ := doublebrace.Seq(3, 7)
fmt.Println(s)
}
Output: [3 4 5 6 7]
Example (Step) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
s, _ := doublebrace.Seq(1, 9, 2)
fmt.Println(s)
}
Output: [1 3 5 7 9]
func Sort ¶
Sort returns a new slice sorted by type:
- numeric types (int, float64, etc.) sort numerically
- time.Time values sort chronologically
- everything else sorts lexicographically (string comparison)
For []any, the first non-nil element determines the sort mode. An optional key names a field for slice-of-maps sorting (always lexicographic). For descending order, compose with reverse. ISO 8601 date strings ("2006-01-02") sort correctly lexicographically.
sort (list "banana" "apple" "cherry") → ["apple" "banana" "cherry"] sort (list 10 2 30) → [2 10 30] sort $pages "Title" → pages A→Z by Title field
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Sort([]string{"banana", "apple", "cherry"})
fmt.Println(v)
}
Output: [apple banana cherry]
Example (Numeric) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Sort([]int{10, 2, 30, 5})
fmt.Println(v)
}
Output: [2 5 10 30]
Example (Time) ¶
package main
import (
"fmt"
"time"
"github.com/client9/doublebrace"
)
func main() {
t1 := time.Date(2024, 3, 1, 0, 0, 0, 0, time.UTC)
t2 := time.Date(2023, 12, 31, 0, 0, 0, 0, time.UTC)
v, _ := doublebrace.Sort([]time.Time{t1, t2})
fmt.Println(v.([]any)[0].(time.Time).Format("2006-01-02"))
}
Output: 2023-12-31
func SortNum ¶
SortNum returns a new slice sorted numerically using toFloat64 conversion. An optional key names a field for slice-of-maps sorting. For descending order, compose with reverse.
sortNum (list "10" "9" "2") → ["2" "9" "10"] sortNum $pages "Year" → pages sorted by Year field, ascending
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.SortNum([]string{"10", "9", "2"})
fmt.Println(v)
}
Output: [2 9 10]
func Sub ¶
Sub returns a - b. Both arguments accept any numeric type or numeric string.
sub 10 3 → 7
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Sub(10, 3)
fmt.Println(v)
}
Output: 7
func Take ¶
Take returns the first n elements of a slice, or the first n runes of a string. If n is negative, it returns the last |n| elements or runes. If |n| exceeds the length the full input is returned. Rune-aware for strings: multi-byte characters are not split.
take []int{1, 2, 3, 4, 5} 3 → []any{1, 2, 3}
take []int{1, 2, 3, 4, 5} -2 → []any{4, 5}
take "日本語" 2 → "日本"
take "日本語" -1 → "語"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Take([]int{1, 2, 3, 4, 5}, 3)
fmt.Println(v)
}
Output: [1 2 3]
Example (Negative) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Take([]int{1, 2, 3, 4, 5}, -2)
fmt.Println(v)
}
Output: [4 5]
Example (String) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.Take("日本語", 2)
fmt.Println(v)
}
Output: 日本
func ToFloat ¶
ToFloat converts v to float64. Numeric types are converted directly. Numeric strings are parsed with strconv.ParseFloat.
toFloat 42 → 42 toFloat "3.14" → 3.14
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.ToFloat("3.14")
fmt.Println(v)
}
Output: 3.14
func ToInt ¶
ToInt converts v to int. Numeric types are converted directly (floats are truncated toward zero). Numeric strings are parsed with strconv.Atoi.
toInt 42 → 42 toInt 3.9 → 3 toInt "17" → 17
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.ToInt("42")
fmt.Println(v)
}
Output: 42
Example (Float) ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
v, _ := doublebrace.ToInt(3.9)
fmt.Println(v)
}
Output: 3
func Truncate ¶
Truncate shortens s to at most n runes. If s is longer it is cut and an ellipsis ("…") is appended. n includes the ellipsis, so the result is always at most n runes long.
truncate "hello world" 8 → "hello w…" truncate "hi" 8 → "hi"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.Truncate("hello world", 8))
fmt.Println(doublebrace.Truncate("hi", 8))
}
Output: hello w… hi
func URLEncode ¶
URLEncode escapes a string so it can be safely placed in a URL query parameter, encoding spaces as "+" and special characters as "%XX".
urlEncode "hello world" → "hello+world" urlEncode "a=1&b=2" → "a%3D1%26b%3D2"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.URLEncode("hello world"))
fmt.Println(doublebrace.URLEncode("a=1&b=2"))
}
Output: hello+world a%3D1%26b%3D2
func URLPathEscape ¶
URLPathEscape escapes a string so it can be safely placed in a URL path segment, encoding spaces and reserved characters as "%XX" (spaces become "%20", not "+").
urlPathEscape "hello world" → "hello%20world" urlPathEscape "a/b" → "a%2Fb"
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
fmt.Println(doublebrace.URLPathEscape("hello world"))
fmt.Println(doublebrace.URLPathEscape("a/b"))
}
Output: hello%20world a%2Fb
func Values ¶
Values returns the values of a map[string]any in key-sorted order.
values map[string]any{"b": 2, "a": 1} → [1 2]
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
m := map[string]any{"b": 2, "a": 1}
v, _ := doublebrace.Values(m)
fmt.Println(v)
}
Output: [1 2]
func Where ¶
Where filters a slice of map[string]any by field equality. Only elements where element[key] == val are included in the result.
where $pages "Draft" false → pages where Draft == false where $pages "Section" "blog" → pages in the blog section
Example ¶
package main
import (
"fmt"
"github.com/client9/doublebrace"
)
func main() {
pages := []any{
map[string]any{"Title": "Post A", "Draft": false},
map[string]any{"Title": "Post B", "Draft": true},
map[string]any{"Title": "Post C", "Draft": false},
}
v, _ := doublebrace.Where(pages, "Draft", false)
fmt.Println(len(v.([]any)))
}
Output: 2
Types ¶
This section is empty.