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