github.com/filosottile/go@v0.0.0-20170906193555-dbed9972d994/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  }