tmpl

package module
v0.0.0-...-d7284f6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 22, 2019 License: Apache-2.0 Imports: 10 Imported by: 0

README

tmpl

This library offers a better approach toward the management of Go's built-in templates.

The goal is to be able to configure a set of root templates, presumably for a website, and then be able to render overrides as needed.

Installing

Run

go get github.com/kurrik/tmpl

Include in your source:

import "github.com/kurrik/tmpl"

Godoc

See http://godoc.org/github.com/kurrik/tmpl

Testing

In the project root run:

go test

Using

Layout

Start by defining a root template which contains placeholders for all referenced sub-templates. In the example, one file is used to hold all these but they could easily be split out into multiple files.

templates/root/root.tmpl

<html>
  <head>{{template "head" .}}</head>
  <body>{{template "body" .}}</body>
</html>
{{define "head"}}<title>{{.Title}}</title>{{end}}
{{define "body"}}{{end}}

Then define overrides which will be selectively used. For example, here is a post template which overrides body:

templates/post.tmpl

{{define "body"}}
<div>
  <h2>{{.Title}}</h2>
  <p>{{timeformat .Date "UnixDate"}}</p>
  <p>{{.Body}}</p>
</div>
{{end}}

Note that it does not reside in the same directory as the root template, this allows us to parse the root template directory in a single command, and selectively use the post template override as needed.

Here's another body override which renders a list of posts:

templates/index.tmpl

{{define "body"}}
{{range .Posts}}
<div>
  <h2>{{.Title}}</h2>
  <p>{{timeformat .Date "UnixDate"}}</p>
  <p>{{textcontent .Body}}</p>
</div>
{{end}}
{{end}}
Rendering

To render templates call tmpl.NewTemplates and then parse the root template structure. Since the example organized the root template into a directory, this is as simple as calling AddTemplatesFromDir.

templates := tmpl.NewTemplates()
if err = templates.AddTemplatesFromDir("templates/root"); err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

Set up some sample data to render:

var (
	out   string
	err   error
)

post1 := map[string]interface{}{
	"Title": "Hello World",
	"Date":  time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
	"Body":  "<em>Hi!</em>",
}

post2 := map[string]interface{}{
	"Title": "Hello Again",
	"Date":  time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
	"Body":  "<em>Hi there!</em>",
}

posts := map[string]interface{}{
	"Title": "My Site",
	"Posts": []map[string]interface{}{
		post1,
		post2,
	},
}

Rendering templates is done by calling any of the RenderXXXX methods, passing in override templates as needed. Here is the call to render the index list of posts:

// Render the index.
if out, err = templates.RenderFile("templates/index.tmpl", posts); err != nil {
	fmt.Printf("Error: %v\n", err)
} else {
	fmt.Println("Index\n=============================")
	fmt.Println(out)
}

This produces:

Index
=============================
<html>
  <head><title>My Site</title></head>
  <body>

<div>
  <h2>Hello World</h2>
  <p>Tue Nov 10 23:00:00 UTC 2009</p>
  <p>Hi!</p>
</div>

<div>
  <h2>Hello Again</h2>
  <p>Wed Nov 11 00:00:00 UTC 2009</p>
  <p>Hi there!</p>
</div>

</body>
</html>

Here is the call to render the first post:

// Render a post.
if out, err = templates.RenderFile("templates/post.tmpl", post1); err != nil {
	fmt.Printf("Error: %v\n", err)
} else {
	fmt.Println("Post\n=============================")
	fmt.Println(out)
}

This produces:

Post
=============================
<html>
  <head><title>Hello World</title></head>
  <body>
<div>
  <h2>Hello World</h2>
  <p>Tue Nov 10 23:00:00 UTC 2009</p>
  <p><em>Hi!</em></p>
</div>
</body>
</html>

You may also render a template string with the RenderText method:

// Render an ad-hoc template.
if out, err = templates.RenderText(`{{define "body"}}{{.Title}}{{end}}`, post1); err != nil {
	fmt.Printf("Error: %v\n", err)
} else {
	fmt.Println("Ad-hoc\n=============================")
	fmt.Println(out)
}

This produces:

Ad-hoc
=============================
<html>
  <head><title>Hello World</title></head>
  <body>Hello World</body>
</html>
Functions

Some template functions are provided:

timeformat This function takes a time.Time value as its first argument and renders it according to a format string supplied as its second argument. If a string is passed which matches a predefined format defined in the time package, that format is used, otherwise it is treated as a literal format string:

{{timeformat .Date "UnixDate"}}
{{timeformat .Date "Mon Jan 02 15:04:05 -0700 2006"}}

textcontent This performs rudmentary stripping of HTML tags so that only text content is output. IMPORTANT! Do not use this method as a security measure - proper sanitization should be performed on untrusted input.

{{textcontent .Body}}

Documentation

Index

Constants

View Source
const TEMP_TEMPLATE_NAME = "xxx111xxx"

Variables

This section is empty.

Functions

This section is empty.

Types

type Templates

type Templates struct {
	// contains filtered or unexported fields
}

func NewTemplates

func NewTemplates() *Templates

func (*Templates) AddTemplate

func (ts *Templates) AddTemplate(text string) (err error)

Includes the contents of the supplied text in the root template.

func (*Templates) AddTemplateFromFile

func (ts *Templates) AddTemplateFromFile(path string) (err error)

Includes the contents of the supplied file in the root template.

func (*Templates) AddTemplateFromTemplate

func (ts *Templates) AddTemplateFromTemplate(tmpl *template.Template) (err error)

Includes the contents of the supplied parsed template in the root template.

func (*Templates) AddTemplatesFromDir

func (ts *Templates) AddTemplatesFromDir(path string) (err error)

Includes the contents of the supplied directory in the root template.

func (*Templates) Clone

func (ts *Templates) Clone() (*template.Template, error)

Produces a clone of the root template.

func (*Templates) MergeInto

func (ts *Templates) MergeInto(tmpl *template.Template) (out *template.Template, err error)

Merges the current templates into another standard template instance.

func (*Templates) NamedRender

func (ts *Templates) NamedRender(name string, data map[string]interface{}) (out string, err error)

Renders the root template without any overrides into the named template.

func (*Templates) NamedRenderTemplate

func (ts *Templates) NamedRenderTemplate(name string, tmpl *template.Template, data map[string]interface{}) (out string, err error)

Renders an existing parsed template.Template instance into the named template.

func (*Templates) NamedRenderText

func (ts *Templates) NamedRenderText(name string, text string, data map[string]interface{}) (out string, err error)

Overrides portions of the root template and renders the appropriate data into the named template.

func (*Templates) Render

func (ts *Templates) Render(data map[string]interface{}) (out string, err error)

Renders the root template without any overrides.

func (*Templates) RenderFile

func (ts *Templates) RenderFile(path string, data map[string]interface{}) (out string, err error)

Overrides portions of the root template with a file's contents and renders.

func (*Templates) RenderTemplate

func (ts *Templates) RenderTemplate(tmpl *template.Template, data map[string]interface{}) (out string, err error)

Renders an existing parsed template.Template instance.

func (*Templates) RenderText

func (ts *Templates) RenderText(text string, data map[string]interface{}) (out string, err error)

Overrides portions of the root template and renders the appropriate data.

func (*Templates) SetFilesystem

func (ts *Templates) SetFilesystem(fs fauxfile.Filesystem)

Allows overriding of the filesystem for unit tests.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL