Documentation ¶
Overview ¶
Template engine that only has named placeholders – nothing more.
Package goxic implements the fractal[qb] toxic template engine concept for the Go programming language. For details on the idea behind the toxic template engine see
https://fractalqb.de/toxic/index.html
Short version is: A Template is nothing but static parts (text) interspersed with placeholders. Placeholders have a unique name and may appear several times withn a template. One cannot generate output from a template only. Before output can be generated – "emitted" in goxic – all placeholders have to be bound to some Content. The bindings are held by a separate object of type BounT (short for "bound template"). This way a single template can be used many times with different bindings. A bound template itself is Content. – Be aware of infinite recursion!
One can build a template through the Template API of the goxic packed. Though quite easy it is not very convenient to build templates this way. It is considered to be more common to build a template by parsing it from a file. The package provides a quite general Parser that also supports nesting of templates. Finally one can create new templates from bound templates where not every placeholder has been bound to content, i.e. to Fixate a BounT. This way one can build coarse grained templates from smaller ones without loosing efficiency.
Index ¶
- Constants
- func IdName(nm string) string
- func IndexMap(imap any, t *Template, complete bool, mapNames func(string) string) error
- func IndexMaps(ts map[string]*Template, complete bool, mapNames func(string) string, ...) error
- func InitIndexMap(imap any, tmpl *Template, mapNames func(string) string) (phCount int, err error)
- func Must(n int64, err error) int64
- func PrepTrimWS(line string) (trimmed string)
- func RenameExists(err error) bool
- func RenameUnknown(err error) bool
- func StripPath(ph string) string
- type BounT
- func (bt *BounT) Bind(cnt Content, phIdxs ...int) (anonymous int)
- func (bt *BounT) BindIfName(cnt Content, name string)
- func (bt *BounT) BindMatch(cnt Content, pattern *regexp.Regexp)
- func (bt *BounT) BindName(cnt Content, name string) error
- func (bt *BounT) BindTemplates(ts map[string]*Template, selectOnly bool, phSelect map[string]string)
- func (bt *BounT) Fill(data any, overwrite bool) (missed int, err error)
- func (bt *BounT) Fixate() (*Template, error)
- func (bt *BounT) HasUnbound(unbound map[string]PhIdxs) (res bool)
- func (bt *BounT) String() string
- func (bt *BounT) Template() *Template
- func (bt *BounT) Wrap(wrapper ContentXformer)
- func (bt *BounT) WriteTo(wr io.Writer) (res int64, err error)
- type Content
- type ContentXformer
- type ContentXformers
- type DuplicateTemplates
- type EscGoTmpl
- type IdxMapParser
- type Parser
- type PhIdxs
- type PhWriteMode
- type Template
- func (t *Template) AddFix(fixFragment []byte) *Template
- func (t *Template) AddStr(str string) *Template
- func (t *Template) FixAt(idx int) []byte
- func (t *Template) FixCount() int
- func (t *Template) FlattenPhs(merge bool) error
- func (t *Template) ForeachPh(r func(name string, idxs []int))
- func (t *Template) NewBounT(reuse *BounT) *BounT
- func (t *Template) NewInitBounT(cnt Content, reuse *BounT) *BounT
- func (t *Template) Pack() (self *Template)
- func (t *Template) Ph(name string) *Template
- func (t *Template) PhAt(idx int) string
- func (t *Template) PhCount() int
- func (t *Template) PhIdxs(name string) []int
- func (t *Template) PhModeAt(idx int) PhWriteMode
- func (t *Template) PhWrap(name string, wrapper ContentXformer) *Template
- func (t *Template) PhWrite(name string, mode PhWriteMode) *Template
- func (t *Template) PhWriteWrap(name string, wrMode PhWriteMode, wrapper ContentXformer) *Template
- func (t *Template) Phs() []string
- func (t *Template) RenamePh(current, newName string, merge bool) error
- func (t *Template) RenamePhs(current, newNames []string, merge bool) error
- func (t *Template) Static() []byte
- func (t *Template) StaticWith(fill Content) ([]byte, error)
- func (t *Template) Wrap(wrapper ContentXformer, idxs ...int)
- func (t *Template) WrapAt(idx int) ContentXformer
- func (t *Template) Write(wr io.Writer, fmtPh func(name string, mode PhWriteMode) string) (err error)
- func (t *Template) XformPhs(merge bool, x func(string) string) error
Examples ¶
Constants ¶
const ( BftMarker = "$" BftPathSep = "." )
const Empty empty = 0
Constant Empty can be use as empty Content, i.e. nothing will be emitted as output.
const NameSep = ':'
const PathSep = '/'
Variables ¶
This section is empty.
Functions ¶
func InitIndexMap ¶
func PrepTrimWS ¶
func RenameExists ¶
func RenameUnknown ¶
Types ¶
type BounT ¶
type BounT struct {
// contains filtered or unexported fields
}
BounT keeps the placeholder bindings for one specific Template. Use Template's NewBounT or NewInitBounT methods to create such a binding object.
Example ¶
tmpl := NewTemplate(""). Ph("foo"). AddStr("<thisisfix1>"). Ph("foo"). AddStr("<thisisfix2>"). Ph("bar") bnt := tmpl.NewBounT(nil) bnt.BindName(gxc.P("FOO"), "foo") bnt.BindName(gxc.P("BAR"), "bar") bnt.WriteTo(os.Stdout)
Output: FOO<thisisfix1>FOO<thisisfix2>BAR
func (*BounT) Bind ¶
Bind returns the number of "anonymous binds", i.e. placeholders with empty names that got a binding.
func (*BounT) BindIfName ¶
BindName binds the content cnt to the placeholders by name. If no placeholder with name exists nothings is bound.
func (*BounT) BindName ¶
BindName binds the content cnt to the placeholders by name. If no placeholder with name exists an error is returned.
func (*BounT) BindTemplates ¶ added in v0.11.0
func (bt *BounT) BindTemplates(ts map[string]*Template, selectOnly bool, phSelect map[string]string)
BindTemplates fills the placeholders of bt with new BounTs created for the respective templates from ts.
func (*BounT) Fill ¶
Fill the placeholders using the bind from template (BFT) feature. The BFT feature allows template authors to specify a 'path' that reaches into the Go data object passed to Fill, i.e. the binding is determined by the template not the program. BFT uses a special notation for placeholder names to achieve this. TODO …
Example ¶
package main import ( "fmt" "os" ) type bftAddr struct { Street string No int } type bftData struct { Name string Addrs []bftAddr } func main() { tmpl := NewTemplate("bft example"). AddStr("Name: ").Ph("$Name"). AddStr("\nLast Address: ").Ph("$Addrs.-1.Street"). AddStr(" ").Ph("$%05d Addrs.-1.No") data := bftData{ Name: "John Doe", Addrs: []bftAddr{ bftAddr{Street: "Cansas Lane", No: 1}, bftAddr{Street: "Yellow-Brick-Road", No: 33}, }, } bt := tmpl.NewBounT(nil) miss, err := bt.Fill(data, true) if err != nil { panic(err) } if miss != 0 { fmt.Printf("missed %d placeholders\n", miss) } _, err = bt.WriteTo(os.Stdout) if err != nil { fmt.Println(err) } }
Output: Name: John Doe Last Address: Yellow-Brick-Road 00033
func (*BounT) HasUnbound ¶
HasUnbound checks if there are placehoders that are not yet bound to content. When a map is passed to HasUnbound all placeholder names are put into the map along with the indices of the yet unbound placeholders.
func (*BounT) Wrap ¶
func (bt *BounT) Wrap(wrapper ContentXformer)
Wrap all bound content into the transformer 'wrapper'.
type ContentXformer ¶ added in v0.11.0
func CXFChain ¶ added in v0.11.0
func CXFChain(cxs ...ContentXformer) ContentXformer
CntXChain creates a content transformer from a list of content transgformers applying them in the order they were passed in cxs.
type ContentXformers ¶ added in v0.11.0
type ContentXformers = map[string]ContentXformer
type DuplicateTemplates ¶
func (DuplicateTemplates) Error ¶
func (err DuplicateTemplates) Error() string
type IdxMapParser ¶ added in v0.12.0
func (IdxMapParser) ParseFile ¶ added in v0.12.0
func (p IdxMapParser) ParseFile(templateFile, rootName string, complete bool, maps ...any) error
func (IdxMapParser) ParseString ¶ added in v0.12.0
func (p IdxMapParser) ParseString(s, rootName string, complete bool, maps ...any) error
type Parser ¶
type Parser struct { // String that starts an inline placeholder StartInlinePh string // String that terminates an inline placeholder EndInlinePh string // Regular expression that matches a block placeholder line BlockPh *regexp.Regexp // Index of the submatch with the placeholder's name PhNameSubmatch int // Index of the submatch for the marker with the preceding line break marker PhPreBrkSubmatch int // Index of the submatch for the marker with the following line break marker PhPostBrkSubmatch int // Regular expression that matches the start of a sub-template StartSubTemplate *regexp.Regexp StartNameSubmatch int StartPreBrkSubmatch int // Regular expression that matches the end of a sub-template EndSubTemplate *regexp.Regexp EndNameSubmatch int EndPostBrkSubmatch int Endl string PrepLine func([]byte) []byte // When not nil, placeholders of the form <name>\<tag> will get the content // wrapper CXFMap[<tag>] for the placeholder <name>. CXFMap map[string]ContentXformer }
Example ¶
rd := strings.NewReader(`1st line of TL template <!-- >>> subt1 >>> --> 1st line of subt1 <!-- >>> sub1ph <<< --> <!-- <<< subt1 <<< \--> last line of TL template `) p := newTestParser() ts := make(map[string]*Template) if err := p.Parse(rd, "", ts); err != nil { fmt.Printf("parsing failed: %s\n", err) } else { tlt := ts[""] if _, err := tlt.NewBounT(nil).WriteTo(os.Stdout); err != nil { fmt.Println(err) } sbt := ts["subt1"] sbbt := sbt.NewBounT(nil) sbbt.BindName(gxc.P("SUB1PH"), "sub1ph") if _, err := sbbt.WriteTo(os.Stdout); err != nil { fmt.Println(err) } }
Output: 1st line of TL template last line of TL template 1st line of subt1 SUB1PH
Example (Cxf_off) ¶
rd := strings.NewReader("<html>`foo\\xml`</html>") p := newTestParser() ts := make(map[string]*Template) err := p.Parse(rd, "cxf_off", ts) if err != nil { fmt.Println(err) } bt := ts[""].NewBounT(nil) bt.BindName(gxc.P("THIS"), "foo\\xml") bt.WriteTo(os.Stdout)
Output: <html>THIS</html>
Example (Cxf_ok) ¶
rd := strings.NewReader("<html>`foo\\xml` and `bar`</html>") p := newTestParser() p.CXFMap = map[string]ContentXformer{ "xml": gxc.StringWrapper("<[", "]>"), } ts := make(map[string]*Template) err := p.Parse(rd, "cxf_ok", ts) if err != nil { fmt.Println(err) } bt := ts[""].NewBounT(nil) bt.BindName(gxc.P("THIS"), "foo") bt.BindName(gxc.P("THAT"), "bar") bt.BindName(gxc.P("DINGENS"), "baz") bt.WriteTo(os.Stdout)
Output: <html><[THIS]> and THAT</html>
type PhWriteMode ¶ added in v0.11.0
type PhWriteMode int
const ( PhWriteInline PhWriteMode = 1 PhWriteBlock PhWriteMode = 2 PhStripPreBrk PhWriteMode = (1 << 2) PhStripPostBrk PhWriteMode = (1 << 3) )
func (PhWriteMode) All ¶ added in v0.11.0
func (pwm PhWriteMode) All(test PhWriteMode) bool
type Template ¶
type Template struct { Name string // contains filtered or unexported fields }
Template holds a sequence of fixed (dstatic) content fragment that have to be emitted verbatim. These fragments are intermixed with named placeholders. The content to fill in the placeholders generally is computed dynamically. A placeholder can appear several times in different posotions within a template. A template can start or end either with a placeholder or with fixed content.
To bind cotent to placeholders one first has to crate a bound template (BounT) to hold the bindings. When all placeholders ar bound the resulting content can be emitted.
func MergedTemplates ¶
func MergedTemplates( into *Template, ts map[string]*Template, selectOnly bool, phSelect map[string]string, ) (*Template, error)
MergeTemplates binds temlpates into the template into accoriding to ph names
func NewTemplate ¶
func (*Template) AddFix ¶
AddFix adds a new piece of static content to the end of the template. Note that static context is merged to preceeding static content as long as no placholder was added before.
func (*Template) FixAt ¶
FixAt returns the piece of static content with the index idx (indices are zero-based).
func (*Template) FixCount ¶
FixCount returns the number of pieces of static content in the template.
func (*Template) FlattenPhs ¶
func (*Template) NewBounT ¶
NewBounT initializes a new binding objekt for template t. When nil is passed a new BounT object is allocated on the heap. Otherwise the passed BounT object is reused.
func (*Template) NewInitBounT ¶
NewInitBounT first uses NewBounT to initialize a BounT object for temlate t. All placeholders are then initially bound to content cnt.
func (*Template) Pack ¶
Pack compacts memory used for the fix parts and the placeholder indices to improve locality. This may also release unused memory when the fix parts are slices into some bigger and otherwise unused piece of memory.
func (*Template) PhAt ¶
PlaceholderAt returns the placeholder that will be emitted between static content idx-1 and static content idx. Note that PlaceholderAt(0) will be emitted before the first piece of static content. This placeholder is optional.
func (*Template) PhCount ¶ added in v0.9.2
PlaceholderNum returns the number of placeholders defined in the template.
func (*Template) PhIdxs ¶
PlaceholderIdxs returns the positions in which one placeholder will be emitted. Note that placeholder index 0 is – if define – emitted before the first piece of fixed content.
func (*Template) PhModeAt ¶ added in v0.11.0
func (t *Template) PhModeAt(idx int) PhWriteMode
func (*Template) PhWrite ¶ added in v0.11.0
func (t *Template) PhWrite(name string, mode PhWriteMode) *Template
func (*Template) PhWriteWrap ¶ added in v0.11.0
func (t *Template) PhWriteWrap(name string, wrMode PhWriteMode, wrapper ContentXformer) *Template
func (*Template) Phs ¶
Placeholders returns all placeholders – more precisely placeholder names – defined in the template.
func (*Template) RenamePh ¶
RenamePh renames the current placeholder to a new name. If merge is true the current placeholder will be renamed even if a placeholder with the newName already exists. Otherwise an error is retrned. Renaming a placeholder that does not exists also result in an error.
func (*Template) RenamePhs ¶
RenamePhs renames each placeholder current[i] to have the name newNames[i] afterwards.
This is different from RenamePh(current[i],newName[i],merge).
func (*Template) Static ¶
Static returns the fixed part as byte slice if there are no placeholders. Otherwise, i.e. the template is not static, it returns nil.
func (*Template) Wrap ¶
func (t *Template) Wrap(wrapper ContentXformer, idxs ...int)
Example ¶
tmpl := NewTemplate("embrace").AddStr("foo").Ph("bar").AddStr("baz") tmpl.Wrap(gxc.StringWrapper("<[", "]>"), tmpl.PhIdxs("bar")...) bt := tmpl.NewInitBounT(gxc.P("BAR"), nil) bt.WriteTo(os.Stdout)
Output: foo<[BAR]>baz
func (*Template) WrapAt ¶
func (t *Template) WrapAt(idx int) ContentXformer
func (*Template) Write ¶
func (t *Template) Write(wr io.Writer, fmtPh func(name string, mode PhWriteMode) string) (err error)
Example ¶
t := NewTemplate("Write Example") t.AddStr("line ").Ph("p1").AddStr(" 1\n"). AddStr("line ").Ph("p2").AddStr("\n2\n"). AddStr("line\n").Ph("p3").AddStr(" 3\n"). AddStr("line\n").Ph("p4").AddStr("\n4") t.Write(os.Stdout, func(name string, mode PhWriteMode) string { if !mode.All(PhWriteBlock) { return fmt.Sprintf("<%s>", name) } var sb strings.Builder sb.WriteByte('#') if mode.All(PhStripPreBrk) { sb.WriteByte('\\') } fmt.Fprintf(&sb, " >>> %s <<<", name) if mode.All(PhStripPostBrk) { sb.WriteString(" \\") } return sb.String() })
Output: line <p1> 1 line <p2> 2 line <p3> 3 line # >>> p4 <<< 4
func (*Template) XformPhs ¶
Example ¶
tmpl := NewTemplate("rename") tmpl.AddStr("AB") tmpl.Ph("a") tmpl.AddStr("CD") tmpl.Ph("b") tmpl.AddStr("EF") tmpl.Ph("c") tmpl.AddStr("GH") tmpl.Ph("d") tmpl.AddStr("IJ") tmpl.XformPhs(true, func(pi string) string { switch pi { case "a": return "d" case "d": return "a" default: return "b" } }) bt := tmpl.NewBounT(nil) bt.BindName(gxc.P("<A>"), "a") bt.BindName(gxc.P("<B>"), "b") bt.BindName(gxc.P("<D>"), "d") bt.WriteTo(os.Stdout)
Output: AB<D>CD<B>EF<B>GH<A>IJ