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