examplefiles_test.go 6.1 KB

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