...

Source file src/html/template/examplefiles_test.go

Documentation: html/template

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

View as plain text