examplefiles_test.go (6274B)
1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 //go:build go1.13
6 // +build go1.13
7
8 package template_test
9
10 import (
11 "io"
12 "log"
13 "os"
14 "path/filepath"
15 "text/template"
16 )
17
18 // templateFile defines the contents of a template to be stored in a file, for testing.
19 type templateFile struct {
20 name string
21 contents string
22 }
23
24 func createTestDir(files []templateFile) string {
25 dir, err := os.MkdirTemp("", "template")
26 if err != nil {
27 log.Fatal(err)
28 }
29 for _, file := range files {
30 f, err := os.Create(filepath.Join(dir, file.name))
31 if err != nil {
32 log.Fatal(err)
33 }
34 defer f.Close()
35 _, err = io.WriteString(f, file.contents)
36 if err != nil {
37 log.Fatal(err)
38 }
39 }
40 return dir
41 }
42
43 // Here we demonstrate loading a set of templates from a directory.
44 func ExampleTemplate_glob() {
45 // Here we create a temporary directory and populate it with our sample
46 // template definition files; usually the template files would already
47 // exist in some location known to the program.
48 dir := createTestDir([]templateFile{
49 // T0.tmpl is a plain template file that just invokes T1.
50 {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
51 // T1.tmpl defines a template, T1 that invokes T2.
52 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
53 // T2.tmpl defines a template T2.
54 {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
55 })
56 // Clean up after the test; another quirk of running as an example.
57 defer os.RemoveAll(dir)
58
59 // pattern is the glob pattern used to find all the template files.
60 pattern := filepath.Join(dir, "*.tmpl")
61
62 // Here starts the example proper.
63 // T0.tmpl is the first name matched, so it becomes the starting template,
64 // the value returned by ParseGlob.
65 tmpl := template.Must(template.ParseGlob(pattern))
66
67 err := tmpl.Execute(os.Stdout, nil)
68 if err != nil {
69 log.Fatalf("template execution: %s", err)
70 }
71 // Output:
72 // T0 invokes T1: (T1 invokes T2: (This is T2))
73 }
74
75 // This example demonstrates one way to share some templates
76 // and use them in different contexts. In this variant we add multiple driver
77 // templates by hand to an existing bundle of templates.
78 func ExampleTemplate_helpers() {
79 // Here we create a temporary directory and populate it with our sample
80 // template definition files; usually the template files would already
81 // exist in some location known to the program.
82 dir := createTestDir([]templateFile{
83 // T1.tmpl defines a template, T1 that invokes T2.
84 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
85 // T2.tmpl defines a template T2.
86 {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
87 })
88 // Clean up after the test; another quirk of running as an example.
89 defer os.RemoveAll(dir)
90
91 // pattern is the glob pattern used to find all the template files.
92 pattern := filepath.Join(dir, "*.tmpl")
93
94 // Here starts the example proper.
95 // Load the helpers.
96 templates := template.Must(template.ParseGlob(pattern))
97 // Add one driver template to the bunch; we do this with an explicit template definition.
98 _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
99 if err != nil {
100 log.Fatal("parsing driver1: ", err)
101 }
102 // Add another driver template.
103 _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
104 if err != nil {
105 log.Fatal("parsing driver2: ", err)
106 }
107 // We load all the templates before execution. This package does not require
108 // that behavior but html/template's escaping does, so it's a good habit.
109 err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
110 if err != nil {
111 log.Fatalf("driver1 execution: %s", err)
112 }
113 err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
114 if err != nil {
115 log.Fatalf("driver2 execution: %s", err)
116 }
117 // Output:
118 // Driver 1 calls T1: (T1 invokes T2: (This is T2))
119 // Driver 2 calls T2: (This is T2)
120 }
121
122 // This example demonstrates how to use one group of driver
123 // templates with distinct sets of helper templates.
124 func ExampleTemplate_share() {
125 // Here we create a temporary directory and populate it with our sample
126 // template definition files; usually the template files would already
127 // exist in some location known to the program.
128 dir := createTestDir([]templateFile{
129 // T0.tmpl is a plain template file that just invokes T1.
130 {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
131 // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
132 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
133 })
134 // Clean up after the test; another quirk of running as an example.
135 defer os.RemoveAll(dir)
136
137 // pattern is the glob pattern used to find all the template files.
138 pattern := filepath.Join(dir, "*.tmpl")
139
140 // Here starts the example proper.
141 // Load the drivers.
142 drivers := template.Must(template.ParseGlob(pattern))
143
144 // We must define an implementation of the T2 template. First we clone
145 // the drivers, then add a definition of T2 to the template name space.
146
147 // 1. Clone the helper set to create a new name space from which to run them.
148 first, err := drivers.Clone()
149 if err != nil {
150 log.Fatal("cloning helpers: ", err)
151 }
152 // 2. Define T2, version A, and parse it.
153 _, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
154 if err != nil {
155 log.Fatal("parsing T2: ", err)
156 }
157
158 // Now repeat the whole thing, using a different version of T2.
159 // 1. Clone the drivers.
160 second, err := drivers.Clone()
161 if err != nil {
162 log.Fatal("cloning drivers: ", err)
163 }
164 // 2. Define T2, version B, and parse it.
165 _, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
166 if err != nil {
167 log.Fatal("parsing T2: ", err)
168 }
169
170 // Execute the templates in the reverse order to verify the
171 // first is unaffected by the second.
172 err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
173 if err != nil {
174 log.Fatalf("second execution: %s", err)
175 }
176 err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
177 if err != nil {
178 log.Fatalf("first: execution: %s", err)
179 }
180
181 // Output:
182 // T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
183 // T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))
184 }