examplefiles_test.go (7726B)
1 // Copyright 2016 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 16 template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate" 17 ) 18 19 // templateFile defines the contents of a template to be stored in a file, for testing. 20 type templateFile struct { 21 name string 22 contents string 23 } 24 25 func createTestDir(files []templateFile) string { 26 dir, err := os.MkdirTemp("", "template") 27 if err != nil { 28 log.Fatal(err) 29 } 30 for _, file := range files { 31 f, err := os.Create(filepath.Join(dir, file.name)) 32 if err != nil { 33 log.Fatal(err) 34 } 35 defer f.Close() 36 _, err = io.WriteString(f, file.contents) 37 if err != nil { 38 log.Fatal(err) 39 } 40 } 41 return dir 42 } 43 44 // The following example is duplicated in text/template; keep them in sync. 45 46 // Here we demonstrate loading a set of templates from a directory. 47 func ExampleTemplate_glob() { 48 // Here we create a temporary directory and populate it with our sample 49 // template definition files; usually the template files would already 50 // exist in some location known to the program. 51 dir := createTestDir([]templateFile{ 52 // T0.tmpl is a plain template file that just invokes T1. 53 {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`}, 54 // T1.tmpl defines a template, T1 that invokes T2. 55 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, 56 // T2.tmpl defines a template T2. 57 {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, 58 }) 59 // Clean up after the test; another quirk of running as an example. 60 defer os.RemoveAll(dir) 61 62 // pattern is the glob pattern used to find all the template files. 63 pattern := filepath.Join(dir, "*.tmpl") 64 65 // Here starts the example proper. 66 // T0.tmpl is the first name matched, so it becomes the starting template, 67 // the value returned by ParseGlob. 68 tmpl := template.Must(template.ParseGlob(pattern)) 69 70 err := tmpl.Execute(os.Stdout, nil) 71 if err != nil { 72 log.Fatalf("template execution: %s", err) 73 } 74 // Output: 75 // T0 invokes T1: (T1 invokes T2: (This is T2)) 76 } 77 78 // Here we demonstrate loading a set of templates from files in different directories 79 func ExampleTemplate_parsefiles() { 80 // Here we create different temporary directories and populate them with our sample 81 // template definition files; usually the template files would already 82 // exist in some location known to the program. 83 dir1 := createTestDir([]templateFile{ 84 // T1.tmpl is a plain template file that just invokes T2. 85 {"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`}, 86 }) 87 88 dir2 := createTestDir([]templateFile{ 89 // T2.tmpl defines a template T2. 90 {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, 91 }) 92 93 // Clean up after the test; another quirk of running as an example. 94 defer func(dirs ...string) { 95 for _, dir := range dirs { 96 os.RemoveAll(dir) 97 } 98 }(dir1, dir2) 99 100 // Here starts the example proper. 101 // Let's just parse only dir1/T0 and dir2/T2 102 paths := []string{ 103 filepath.Join(dir1, "T1.tmpl"), 104 filepath.Join(dir2, "T2.tmpl"), 105 } 106 tmpl := template.Must(template.ParseFiles(paths...)) 107 108 err := tmpl.Execute(os.Stdout, nil) 109 if err != nil { 110 log.Fatalf("template execution: %s", err) 111 } 112 // Output: 113 // T1 invokes T2: (This is T2) 114 } 115 116 // The following example is duplicated in text/template; keep them in sync. 117 118 // This example demonstrates one way to share some templates 119 // and use them in different contexts. In this variant we add multiple driver 120 // templates by hand to an existing bundle of templates. 121 func ExampleTemplate_helpers() { 122 // Here we create a temporary directory and populate it with our sample 123 // template definition files; usually the template files would already 124 // exist in some location known to the program. 125 dir := createTestDir([]templateFile{ 126 // T1.tmpl defines a template, T1 that invokes T2. 127 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, 128 // T2.tmpl defines a template T2. 129 {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, 130 }) 131 // Clean up after the test; another quirk of running as an example. 132 defer os.RemoveAll(dir) 133 134 // pattern is the glob pattern used to find all the template files. 135 pattern := filepath.Join(dir, "*.tmpl") 136 137 // Here starts the example proper. 138 // Load the helpers. 139 templates := template.Must(template.ParseGlob(pattern)) 140 // Add one driver template to the bunch; we do this with an explicit template definition. 141 _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}") 142 if err != nil { 143 log.Fatal("parsing driver1: ", err) 144 } 145 // Add another driver template. 146 _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}") 147 if err != nil { 148 log.Fatal("parsing driver2: ", err) 149 } 150 // We load all the templates before execution. This package does not require 151 // that behavior but html/template's escaping does, so it's a good habit. 152 err = templates.ExecuteTemplate(os.Stdout, "driver1", nil) 153 if err != nil { 154 log.Fatalf("driver1 execution: %s", err) 155 } 156 err = templates.ExecuteTemplate(os.Stdout, "driver2", nil) 157 if err != nil { 158 log.Fatalf("driver2 execution: %s", err) 159 } 160 // Output: 161 // Driver 1 calls T1: (T1 invokes T2: (This is T2)) 162 // Driver 2 calls T2: (This is T2) 163 } 164 165 // The following example is duplicated in text/template; keep them in sync. 166 167 // This example demonstrates how to use one group of driver 168 // templates with distinct sets of helper templates. 169 func ExampleTemplate_share() { 170 // Here we create a temporary directory and populate it with our sample 171 // template definition files; usually the template files would already 172 // exist in some location known to the program. 173 dir := createTestDir([]templateFile{ 174 // T0.tmpl is a plain template file that just invokes T1. 175 {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"}, 176 // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined 177 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, 178 }) 179 // Clean up after the test; another quirk of running as an example. 180 defer os.RemoveAll(dir) 181 182 // pattern is the glob pattern used to find all the template files. 183 pattern := filepath.Join(dir, "*.tmpl") 184 185 // Here starts the example proper. 186 // Load the drivers. 187 drivers := template.Must(template.ParseGlob(pattern)) 188 189 // We must define an implementation of the T2 template. First we clone 190 // the drivers, then add a definition of T2 to the template name space. 191 192 // 1. Clone the helper set to create a new name space from which to run them. 193 first, err := drivers.Clone() 194 if err != nil { 195 log.Fatal("cloning helpers: ", err) 196 } 197 // 2. Define T2, version A, and parse it. 198 _, err = first.Parse("{{define `T2`}}T2, version A{{end}}") 199 if err != nil { 200 log.Fatal("parsing T2: ", err) 201 } 202 203 // Now repeat the whole thing, using a different version of T2. 204 // 1. Clone the drivers. 205 second, err := drivers.Clone() 206 if err != nil { 207 log.Fatal("cloning drivers: ", err) 208 } 209 // 2. Define T2, version B, and parse it. 210 _, err = second.Parse("{{define `T2`}}T2, version B{{end}}") 211 if err != nil { 212 log.Fatal("parsing T2: ", err) 213 } 214 215 // Execute the templates in the reverse order to verify the 216 // first is unaffected by the second. 217 err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second") 218 if err != nil { 219 log.Fatalf("second execution: %s", err) 220 } 221 err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first") 222 if err != nil { 223 log.Fatalf("first: execution: %s", err) 224 } 225 226 // Output: 227 // T0 (second version) invokes T1: (T1 invokes T2: (T2, version B)) 228 // T0 (first version) invokes T1: (T1 invokes T2: (T2, version A)) 229 }