| // Copyright 2016 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package template_test | |
| import ( | |
| "io" | |
| "log" | |
| "os" | |
| "path/filepath" | |
| "text/template" | |
| ) | |
| // templateFile defines the contents of a template to be stored in a file, for testing. | |
| type templateFile struct { | |
| name string | |
| contents string | |
| } | |
| func createTestDir(files []templateFile) string { | |
| dir, err := os.MkdirTemp("", "template") | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| for _, file := range files { | |
| f, err := os.Create(filepath.Join(dir, file.name)) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer f.Close() | |
| _, err = io.WriteString(f, file.contents) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| } | |
| return dir | |
| } | |
| // The following example is duplicated in text/template; keep them in sync. | |
| // Here we demonstrate loading a set of templates from a directory. | |
| func ExampleTemplate_glob() { | |
| // Here we create a temporary directory and populate it with our sample | |
| // template definition files; usually the template files would already | |
| // exist in some location known to the program. | |
| dir := createTestDir([]templateFile{ | |
| // T0.tmpl is a plain template file that just invokes T1. | |
| {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`}, | |
| // T1.tmpl defines a template, T1 that invokes T2. | |
| {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, | |
| // T2.tmpl defines a template T2. | |
| {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, | |
| }) | |
| // Clean up after the test; another quirk of running as an example. | |
| defer os.RemoveAll(dir) | |
| // pattern is the glob pattern used to find all the template files. | |
| pattern := filepath.Join(dir, "*.tmpl") | |
| // Here starts the example proper. | |
| // T0.tmpl is the first name matched, so it becomes the starting template, | |
| // the value returned by ParseGlob. | |
| tmpl := template.Must(template.ParseGlob(pattern)) | |
| err := tmpl.Execute(os.Stdout, nil) | |
| if err != nil { | |
| log.Fatalf("template execution: %s", err) | |
| } | |
| // Output: | |
| // T0 invokes T1: (T1 invokes T2: (This is T2)) | |
| } | |
| // Here we demonstrate loading a set of templates from files in different directories | |
| func ExampleTemplate_parsefiles() { | |
| // Here we create different temporary directories and populate them with our sample | |
| // template definition files; usually the template files would already | |
| // exist in some location known to the program. | |
| dir1 := createTestDir([]templateFile{ | |
| // T1.tmpl is a plain template file that just invokes T2. | |
| {"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`}, | |
| }) | |
| dir2 := createTestDir([]templateFile{ | |
| // T2.tmpl defines a template T2. | |
| {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, | |
| }) | |
| // Clean up after the test; another quirk of running as an example. | |
| defer func(dirs ...string) { | |
| for _, dir := range dirs { | |
| os.RemoveAll(dir) | |
| } | |
| }(dir1, dir2) | |
| // Here starts the example proper. | |
| // Let's just parse only dir1/T0 and dir2/T2 | |
| paths := []string{ | |
| filepath.Join(dir1, "T1.tmpl"), | |
| filepath.Join(dir2, "T2.tmpl"), | |
| } | |
| tmpl := template.Must(template.ParseFiles(paths...)) | |
| err := tmpl.Execute(os.Stdout, nil) | |
| if err != nil { | |
| log.Fatalf("template execution: %s", err) | |
| } | |
| // Output: | |
| // T1 invokes T2: (This is T2) | |
| } | |
| // The following example is duplicated in text/template; keep them in sync. | |
| // This example demonstrates one way to share some templates | |
| // and use them in different contexts. In this variant we add multiple driver | |
| // templates by hand to an existing bundle of templates. | |
| func ExampleTemplate_helpers() { | |
| // Here we create a temporary directory and populate it with our sample | |
| // template definition files; usually the template files would already | |
| // exist in some location known to the program. | |
| dir := createTestDir([]templateFile{ | |
| // T1.tmpl defines a template, T1 that invokes T2. | |
| {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, | |
| // T2.tmpl defines a template T2. | |
| {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, | |
| }) | |
| // Clean up after the test; another quirk of running as an example. | |
| defer os.RemoveAll(dir) | |
| // pattern is the glob pattern used to find all the template files. | |
| pattern := filepath.Join(dir, "*.tmpl") | |
| // Here starts the example proper. | |
| // Load the helpers. | |
| templates := template.Must(template.ParseGlob(pattern)) | |
| // Add one driver template to the bunch; we do this with an explicit template definition. | |
| _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}") | |
| if err != nil { | |
| log.Fatal("parsing driver1: ", err) | |
| } | |
| // Add another driver template. | |
| _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}") | |
| if err != nil { | |
| log.Fatal("parsing driver2: ", err) | |
| } | |
| // We load all the templates before execution. This package does not require | |
| // that behavior but html/template's escaping does, so it's a good habit. | |
| err = templates.ExecuteTemplate(os.Stdout, "driver1", nil) | |
| if err != nil { | |
| log.Fatalf("driver1 execution: %s", err) | |
| } | |
| err = templates.ExecuteTemplate(os.Stdout, "driver2", nil) | |
| if err != nil { | |
| log.Fatalf("driver2 execution: %s", err) | |
| } | |
| // Output: | |
| // Driver 1 calls T1: (T1 invokes T2: (This is T2)) | |
| // Driver 2 calls T2: (This is T2) | |
| } | |
| // The following example is duplicated in text/template; keep them in sync. | |
| // This example demonstrates how to use one group of driver | |
| // templates with distinct sets of helper templates. | |
| func ExampleTemplate_share() { | |
| // Here we create a temporary directory and populate it with our sample | |
| // template definition files; usually the template files would already | |
| // exist in some location known to the program. | |
| dir := createTestDir([]templateFile{ | |
| // T0.tmpl is a plain template file that just invokes T1. | |
| {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"}, | |
| // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined | |
| {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, | |
| }) | |
| // Clean up after the test; another quirk of running as an example. | |
| defer os.RemoveAll(dir) | |
| // pattern is the glob pattern used to find all the template files. | |
| pattern := filepath.Join(dir, "*.tmpl") | |
| // Here starts the example proper. | |
| // Load the drivers. | |
| drivers := template.Must(template.ParseGlob(pattern)) | |
| // We must define an implementation of the T2 template. First we clone | |
| // the drivers, then add a definition of T2 to the template name space. | |
| // 1. Clone the helper set to create a new name space from which to run them. | |
| first, err := drivers.Clone() | |
| if err != nil { | |
| log.Fatal("cloning helpers: ", err) | |
| } | |
| // 2. Define T2, version A, and parse it. | |
| _, err = first.Parse("{{define `T2`}}T2, version A{{end}}") | |
| if err != nil { | |
| log.Fatal("parsing T2: ", err) | |
| } | |
| // Now repeat the whole thing, using a different version of T2. | |
| // 1. Clone the drivers. | |
| second, err := drivers.Clone() | |
| if err != nil { | |
| log.Fatal("cloning drivers: ", err) | |
| } | |
| // 2. Define T2, version B, and parse it. | |
| _, err = second.Parse("{{define `T2`}}T2, version B{{end}}") | |
| if err != nil { | |
| log.Fatal("parsing T2: ", err) | |
| } | |
| // Execute the templates in the reverse order to verify the | |
| // first is unaffected by the second. | |
| err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second") | |
| if err != nil { | |
| log.Fatalf("second execution: %s", err) | |
| } | |
| err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first") | |
| if err != nil { | |
| log.Fatalf("first: execution: %s", err) | |
| } | |
| // Output: | |
| // T0 (second version) invokes T1: (T1 invokes T2: (T2, version B)) | |
| // T0 (first version) invokes T1: (T1 invokes T2: (T2, version A)) | |
| } | |