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 }