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 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 // Here we demonstrate loading a set of templates from a directory. 42 func ExampleTemplate_glob() { 43 // Here we create a temporary directory and populate it with our sample 44 // template definition files; usually the template files would already 45 // exist in some location known to the program. 46 dir := createTestDir([]templateFile{ 47 // T0.tmpl is a plain template file that just invokes T1. 48 {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`}, 49 // T1.tmpl defines a template, T1 that invokes T2. 50 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, 51 // T2.tmpl defines a template T2. 52 {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, 53 }) 54 // Clean up after the test; another quirk of running as an example. 55 defer os.RemoveAll(dir) 56 57 // pattern is the glob pattern used to find all the template files. 58 pattern := filepath.Join(dir, "*.tmpl") 59 60 // Here starts the example proper. 61 // T0.tmpl is the first name matched, so it becomes the starting template, 62 // the value returned by ParseGlob. 63 tmpl := template.Must(template.ParseGlob(pattern)) 64 65 err := tmpl.Execute(os.Stdout, nil) 66 if err != nil { 67 log.Fatalf("template execution: %s", err) 68 } 69 // Output: 70 // T0 invokes T1: (T1 invokes T2: (This is T2)) 71 } 72 73 // This example demonstrates one way to share some templates 74 // and use them in different contexts. In this variant we add multiple driver 75 // templates by hand to an existing bundle of templates. 76 func ExampleTemplate_helpers() { 77 // Here we create a temporary directory and populate it with our sample 78 // template definition files; usually the template files would already 79 // exist in some location known to the program. 80 dir := createTestDir([]templateFile{ 81 // T1.tmpl defines a template, T1 that invokes T2. 82 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, 83 // T2.tmpl defines a template T2. 84 {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, 85 }) 86 // Clean up after the test; another quirk of running as an example. 87 defer os.RemoveAll(dir) 88 89 // pattern is the glob pattern used to find all the template files. 90 pattern := filepath.Join(dir, "*.tmpl") 91 92 // Here starts the example proper. 93 // Load the helpers. 94 templates := template.Must(template.ParseGlob(pattern)) 95 // Add one driver template to the bunch; we do this with an explicit template definition. 96 _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}") 97 if err != nil { 98 log.Fatal("parsing driver1: ", err) 99 } 100 // Add another driver template. 101 _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}") 102 if err != nil { 103 log.Fatal("parsing driver2: ", err) 104 } 105 // We load all the templates before execution. This package does not require 106 // that behavior but html/template's escaping does, so it's a good habit. 107 err = templates.ExecuteTemplate(os.Stdout, "driver1", nil) 108 if err != nil { 109 log.Fatalf("driver1 execution: %s", err) 110 } 111 err = templates.ExecuteTemplate(os.Stdout, "driver2", nil) 112 if err != nil { 113 log.Fatalf("driver2 execution: %s", err) 114 } 115 // Output: 116 // Driver 1 calls T1: (T1 invokes T2: (This is T2)) 117 // Driver 2 calls T2: (This is T2) 118 } 119 120 // This example demonstrates how to use one group of driver 121 // templates with distinct sets of helper templates. 122 func ExampleTemplate_share() { 123 // Here we create a temporary directory and populate it with our sample 124 // template definition files; usually the template files would already 125 // exist in some location known to the program. 126 dir := createTestDir([]templateFile{ 127 // T0.tmpl is a plain template file that just invokes T1. 128 {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"}, 129 // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined 130 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, 131 }) 132 // Clean up after the test; another quirk of running as an example. 133 defer os.RemoveAll(dir) 134 135 // pattern is the glob pattern used to find all the template files. 136 pattern := filepath.Join(dir, "*.tmpl") 137 138 // Here starts the example proper. 139 // Load the drivers. 140 drivers := template.Must(template.ParseGlob(pattern)) 141 142 // We must define an implementation of the T2 template. First we clone 143 // the drivers, then add a definition of T2 to the template name space. 144 145 // 1. Clone the helper set to create a new name space from which to run them. 146 first, err := drivers.Clone() 147 if err != nil { 148 log.Fatal("cloning helpers: ", err) 149 } 150 // 2. Define T2, version A, and parse it. 151 _, err = first.Parse("{{define `T2`}}T2, version A{{end}}") 152 if err != nil { 153 log.Fatal("parsing T2: ", err) 154 } 155 156 // Now repeat the whole thing, using a different version of T2. 157 // 1. Clone the drivers. 158 second, err := drivers.Clone() 159 if err != nil { 160 log.Fatal("cloning drivers: ", err) 161 } 162 // 2. Define T2, version B, and parse it. 163 _, err = second.Parse("{{define `T2`}}T2, version B{{end}}") 164 if err != nil { 165 log.Fatal("parsing T2: ", err) 166 } 167 168 // Execute the templates in the reverse order to verify the 169 // first is unaffected by the second. 170 err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second") 171 if err != nil { 172 log.Fatalf("second execution: %s", err) 173 } 174 err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first") 175 if err != nil { 176 log.Fatalf("first: execution: %s", err) 177 } 178 179 // Output: 180 // T0 (second version) invokes T1: (T1 invokes T2: (T2, version B)) 181 // T0 (first version) invokes T1: (T1 invokes T2: (T2, version A)) 182 } 183