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