Files
go_goutils/tplx/funcs.go
brent saner 006cf39fa1 v1.15.0
ADDED:
* tplx, for one-shotting/shortcutting templating
2025-12-23 17:26:50 -05:00

236 lines
5.5 KiB
Go

package tplx
import (
`bytes`
htmlTpl `html/template`
txtTpl `text/template`
)
// MustTplStrToStr wraps [TplStrToStr] but will panic on a non-nil error instead of returning it.
func MustTplStrToStr(tplStr string, typ tplType, obj any) (s string) {
var err error
if s, err = TplStrToStr(tplStr, typ, obj); err != nil {
panic(err)
}
return
}
// MustTplToStr wraps [TplToStr] but will panic on error instead of returning it.
func MustTplToStr[T Template](tpl T, obj any) (s string) {
var err error
if s, err = TplToStr(tpl, obj); err != nil {
panic(err)
}
return
}
// MustTplToStrWith wraps [TplToStrWith] but will panic on error instead of returning it.
func MustTplToStrWith[T Template](tpl T, tplNm string, obj any) (s string) {
var err error
if s, err = TplToStrWith(tpl, tplNm, obj); err != nil {
panic(err)
}
return
}
/*
TplStrToStr takes in a template string, a template type (see i.e. [TplTypeText], [TplTypeHtml]),
and an object and renders to a string.
This is obviously quite inflexible - there's no way to provide a [text/template.FuncMap]/[html/template.FuncMap],
for instance, but if more advanced template features aren't needed then this might just do the trick.
If you need something more flexible, see [TplToStr] instead.
*/
func TplStrToStr(tplStr string, typ tplType, obj any) (out string, err error) {
var ttpl *txtTpl.Template
var htpl *htmlTpl.Template
var buf *bytes.Buffer = new(bytes.Buffer)
switch typ {
case TplTypeText:
if ttpl, err = txtTpl.New("").Parse(tplStr); err != nil {
return
}
if err = ttpl.Execute(buf, obj); err != nil {
return
}
case TplTypeHtml:
if htpl, err = htmlTpl.New("").Parse(tplStr); err != nil {
return
}
if err = htpl.Execute(buf, obj); err != nil {
return
}
default:
err = ErrInvalidTplType
return
}
out = buf.String()
return
}
/*
TplToStr takes in an [html/template] or [text/template] and an object and executes it.
PLEASE NOTE that it is expected that `tpl` has already had at least one template string `.Parse()`'d in.
If you haven't used generics in Golang yet, this function would be used via something like the following complete example
for both a [text/template.Template] (import-aliased as `txtT.Template`) and
an [html/template.Template] (import-aliased as `htmlT.Template`).
import (
"fmt"
"log"
txtT "text/template"
htmlT "html/template"
`r00t2.io/goutils/tplx`
)
type (
S struct {
Name string
}
)
var (
tTpl *txtT.Template
hTpl *htmlT.Template
)
const tTplStr string = "Greetings, {{ .Name }}!\n"
const hTplStr string = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello, {{ .Name }}!</title>
</head>
<body>
<p>Hello, {{ .Name }}. Good to see you.</p>
</body>
</html>
`
func main() {
var err error
var s string
var o *S
o = &S{
Name: "Bob",
}
// A text template.
if tTpl, err = txtT.
New("my_txt_template").
Parse(tTplStr); err != nil {
log.Panicf("Failed to parse text template string '%s': %v\n", tTplStr, err)
}
if s, err = tplx.TplToStr[*txtT.Template](tTpl, o); err != nil {
log.Panicf("Failed to render text template to string: %v\n", err)
}
fmt.Println(s)
// An HTML template.
if hTpl, err = htmlT.
New("index.html").
Parse(hTplStr); err != nil {
log.Panicf("Failed to parse HTML template string '%s': %v\n", hTplStr, err)
}
if s, err = tplx.TplToStr[*htmlT.Template](hTpl, o); err != nil {
log.Panicf("Failed to render HTML template to string: %v\n", err)
}
fmt.Println(s)
}
Additionally, because this function uses a union type [Template],
you can even leave the type indicator off.
For example:
// ...
if s, err = tplx.TplToStr(tTpl, o); err != nil {
log.Panicf("Failed to render text template to string: %v\n", err)
}
// ...
if s, err = tplx.TplToStr(hTpl, o); err != nil {
log.Panicf("Failed to render HTML template to string: %v\n", err)
}
// ...
However, this is not recommended for readability purposes - including
the type indicator indicates (heh heh) to others reading your code
what type `tTpl` and `hTpl` are without needing to cross-reference
their declaration/assignment/definition.
For more information on generics in Golang, see:
* The introductory [blog post]
* The official [tutorial]
* The syntax [reference doc]
* The (community-maintained/unofficial) [Go by Example: Generics]
[blog post]: https://go.dev/blog/intro-generics
[tutorial]: https://go.dev/doc/tutorial/generics
[reference doc]: https://go.dev/ref/spec#Instantiations
[Go by Example: Generics]: https://gobyexample.com/generics
*/
func TplToStr[T Template](tpl T, obj any) (out string, err error) {
var buf *bytes.Buffer = new(bytes.Buffer)
if err = tpl.Execute(buf, obj); err != nil {
return
}
out = buf.String()
return
}
/*
TplToStrWith functions the exact same as [TplToStr] but allows you to specify the
template entry point (template name) named `nm`.
For example (see [TplToStr] for a full example):
// ...
var tplNm string = "index.html"
if s, err = tplx.TplToStrWith(tTpl, tplNm, o); err != nil {
log.Panicf("Failed to render HTML template '%s' to string: %v\n", tplNm, err)
}
// ...
would call the equivalent of:
// ...
if err = tpl.ExecuteTemplate(<internal buffer>, tplNm, o); err != nil {
// ...
}
*/
func TplToStrWith[T Template](tpl T, tplNm string, obj any) (out string, err error) {
var buf *bytes.Buffer = new(bytes.Buffer)
if err = tpl.ExecuteTemplate(buf, tplNm, obj); err != nil {
return
}
out = buf.String()
return
}