mirror of https://github.com/gohugoio/hugo
227 lines
7.5 KiB
Go
227 lines
7.5 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package template_test
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
|
|
)
|
|
|
|
// templateFile defines the contents of a template to be stored in a file, for testing.
|
|
type templateFile struct {
|
|
name string
|
|
contents string
|
|
}
|
|
|
|
func createTestDir(files []templateFile) string {
|
|
dir, err := os.MkdirTemp("", "template")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
for _, file := range files {
|
|
f, err := os.Create(filepath.Join(dir, file.name))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
_, err = io.WriteString(f, file.contents)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
return dir
|
|
}
|
|
|
|
// The following example is duplicated in text/template; keep them in sync.
|
|
|
|
// Here we demonstrate loading a set of templates from a directory.
|
|
func ExampleTemplate_glob() {
|
|
// Here we create a temporary directory and populate it with our sample
|
|
// template definition files; usually the template files would already
|
|
// exist in some location known to the program.
|
|
dir := createTestDir([]templateFile{
|
|
// T0.tmpl is a plain template file that just invokes T1.
|
|
{"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
|
|
// T1.tmpl defines a template, T1 that invokes T2.
|
|
{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
|
|
// T2.tmpl defines a template T2.
|
|
{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
|
|
})
|
|
// Clean up after the test; another quirk of running as an example.
|
|
defer os.RemoveAll(dir)
|
|
|
|
// pattern is the glob pattern used to find all the template files.
|
|
pattern := filepath.Join(dir, "*.tmpl")
|
|
|
|
// Here starts the example proper.
|
|
// T0.tmpl is the first name matched, so it becomes the starting template,
|
|
// the value returned by ParseGlob.
|
|
tmpl := template.Must(template.ParseGlob(pattern))
|
|
|
|
err := tmpl.Execute(os.Stdout, nil)
|
|
if err != nil {
|
|
log.Fatalf("template execution: %s", err)
|
|
}
|
|
// Output:
|
|
// T0 invokes T1: (T1 invokes T2: (This is T2))
|
|
}
|
|
|
|
// Here we demonstrate loading a set of templates from files in different directories
|
|
func ExampleTemplate_parsefiles() {
|
|
// Here we create different temporary directories and populate them with our sample
|
|
// template definition files; usually the template files would already
|
|
// exist in some location known to the program.
|
|
dir1 := createTestDir([]templateFile{
|
|
// T1.tmpl is a plain template file that just invokes T2.
|
|
{"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`},
|
|
})
|
|
|
|
dir2 := createTestDir([]templateFile{
|
|
// T2.tmpl defines a template T2.
|
|
{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
|
|
})
|
|
|
|
// Clean up after the test; another quirk of running as an example.
|
|
defer func(dirs ...string) {
|
|
for _, dir := range dirs {
|
|
os.RemoveAll(dir)
|
|
}
|
|
}(dir1, dir2)
|
|
|
|
// Here starts the example proper.
|
|
// Let's just parse only dir1/T0 and dir2/T2
|
|
paths := []string{
|
|
filepath.Join(dir1, "T1.tmpl"),
|
|
filepath.Join(dir2, "T2.tmpl"),
|
|
}
|
|
tmpl := template.Must(template.ParseFiles(paths...))
|
|
|
|
err := tmpl.Execute(os.Stdout, nil)
|
|
if err != nil {
|
|
log.Fatalf("template execution: %s", err)
|
|
}
|
|
// Output:
|
|
// T1 invokes T2: (This is T2)
|
|
}
|
|
|
|
// The following example is duplicated in text/template; keep them in sync.
|
|
|
|
// This example demonstrates one way to share some templates
|
|
// and use them in different contexts. In this variant we add multiple driver
|
|
// templates by hand to an existing bundle of templates.
|
|
func ExampleTemplate_helpers() {
|
|
// Here we create a temporary directory and populate it with our sample
|
|
// template definition files; usually the template files would already
|
|
// exist in some location known to the program.
|
|
dir := createTestDir([]templateFile{
|
|
// T1.tmpl defines a template, T1 that invokes T2.
|
|
{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
|
|
// T2.tmpl defines a template T2.
|
|
{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
|
|
})
|
|
// Clean up after the test; another quirk of running as an example.
|
|
defer os.RemoveAll(dir)
|
|
|
|
// pattern is the glob pattern used to find all the template files.
|
|
pattern := filepath.Join(dir, "*.tmpl")
|
|
|
|
// Here starts the example proper.
|
|
// Load the helpers.
|
|
templates := template.Must(template.ParseGlob(pattern))
|
|
// Add one driver template to the bunch; we do this with an explicit template definition.
|
|
_, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
|
|
if err != nil {
|
|
log.Fatal("parsing driver1: ", err)
|
|
}
|
|
// Add another driver template.
|
|
_, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
|
|
if err != nil {
|
|
log.Fatal("parsing driver2: ", err)
|
|
}
|
|
// We load all the templates before execution. This package does not require
|
|
// that behavior but html/template's escaping does, so it's a good habit.
|
|
err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
|
|
if err != nil {
|
|
log.Fatalf("driver1 execution: %s", err)
|
|
}
|
|
err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
|
|
if err != nil {
|
|
log.Fatalf("driver2 execution: %s", err)
|
|
}
|
|
// Output:
|
|
// Driver 1 calls T1: (T1 invokes T2: (This is T2))
|
|
// Driver 2 calls T2: (This is T2)
|
|
}
|
|
|
|
// The following example is duplicated in text/template; keep them in sync.
|
|
|
|
// This example demonstrates how to use one group of driver
|
|
// templates with distinct sets of helper templates.
|
|
func ExampleTemplate_share() {
|
|
// Here we create a temporary directory and populate it with our sample
|
|
// template definition files; usually the template files would already
|
|
// exist in some location known to the program.
|
|
dir := createTestDir([]templateFile{
|
|
// T0.tmpl is a plain template file that just invokes T1.
|
|
{"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
|
|
// T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
|
|
{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
|
|
})
|
|
// Clean up after the test; another quirk of running as an example.
|
|
defer os.RemoveAll(dir)
|
|
|
|
// pattern is the glob pattern used to find all the template files.
|
|
pattern := filepath.Join(dir, "*.tmpl")
|
|
|
|
// Here starts the example proper.
|
|
// Load the drivers.
|
|
drivers := template.Must(template.ParseGlob(pattern))
|
|
|
|
// We must define an implementation of the T2 template. First we clone
|
|
// the drivers, then add a definition of T2 to the template name space.
|
|
|
|
// 1. Clone the helper set to create a new name space from which to run them.
|
|
first, err := drivers.Clone()
|
|
if err != nil {
|
|
log.Fatal("cloning helpers: ", err)
|
|
}
|
|
// 2. Define T2, version A, and parse it.
|
|
_, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
|
|
if err != nil {
|
|
log.Fatal("parsing T2: ", err)
|
|
}
|
|
|
|
// Now repeat the whole thing, using a different version of T2.
|
|
// 1. Clone the drivers.
|
|
second, err := drivers.Clone()
|
|
if err != nil {
|
|
log.Fatal("cloning drivers: ", err)
|
|
}
|
|
// 2. Define T2, version B, and parse it.
|
|
_, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
|
|
if err != nil {
|
|
log.Fatal("parsing T2: ", err)
|
|
}
|
|
|
|
// Execute the templates in the reverse order to verify the
|
|
// first is unaffected by the second.
|
|
err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
|
|
if err != nil {
|
|
log.Fatalf("second execution: %s", err)
|
|
}
|
|
err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
|
|
if err != nil {
|
|
log.Fatalf("first: execution: %s", err)
|
|
}
|
|
|
|
// Output:
|
|
// T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
|
|
// T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))
|
|
}
|