OLD | NEW |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package template | 5 package template |
6 | 6 |
7 import ( | 7 import ( |
| 8 "bytes" |
8 "fmt" | 9 "fmt" |
9 "io" | |
10 "reflect" | 10 "reflect" |
11 "text/template/parse" | 11 "text/template/parse" |
12 ) | 12 ) |
13 | 13 |
14 // Set holds a set of related templates that can refer to one another by name. | 14 // common holds the information shared by related templates. |
15 // The zero value represents an empty set. | 15 type common struct { |
16 // A template may be a member of multiple sets. | 16 » tmpl map[string]*Template |
17 type Set struct { | 17 » // We use two maps, one for parsing and one for execution. |
18 » tmpl map[string]*Template | 18 » // This separation makes the API cleaner since it doesn't |
19 » trees map[string]*parse.Tree // maintained by parse package | 19 » // expose reflection to the client. |
| 20 » parseFuncs FuncMap |
| 21 » execFuncs map[string]reflect.Value |
| 22 } |
| 23 |
| 24 // Template is the representation of a parsed template. The *parse.Tree |
| 25 // field is exported only for use by html/template and should be treated |
| 26 // as unexported by all other clients. |
| 27 type Template struct { |
| 28 » name string |
| 29 » *parse.Tree |
| 30 » *common |
20 leftDelim string | 31 leftDelim string |
21 rightDelim string | 32 rightDelim string |
22 » parseFuncs FuncMap | 33 } |
23 » execFuncs map[string]reflect.Value | 34 |
24 } | 35 // New allocates a new template with the given name. |
25 | 36 func New(name string) *Template { |
26 func (s *Set) init() { | 37 » return &Template{ |
27 » if s.tmpl == nil { | 38 » » name: name, |
28 » » s.tmpl = make(map[string]*Template) | 39 » } |
29 » » s.parseFuncs = make(FuncMap) | 40 } |
30 » » s.execFuncs = make(map[string]reflect.Value) | 41 |
31 » } | 42 // Name returns the name of the template. |
32 } | 43 func (t *Template) Name() string { |
33 | 44 » return t.name |
34 // Delims sets the action delimiters, to be used in a subsequent | 45 } |
35 // parse, to the specified strings. | 46 |
36 // An empty delimiter stands for the corresponding default: {{ or }}. | 47 // New allocates a new template associated with the given one and with the same |
37 // The return value is the set, so calls can be chained. | 48 // delimiters. The association, which is transitive, allows one template to |
38 func (s *Set) Delims(left, right string) *Set { | 49 // invoke another with a {{template}} action. |
39 » s.leftDelim = left | 50 func (t *Template) New(name string) *Template { |
40 » s.rightDelim = right | 51 » t.init() |
41 » return s | 52 » return &Template{ |
42 } | 53 » » name: name, |
43 | 54 » » common: t.common, |
44 // Funcs adds the elements of the argument map to the set's function map. It | 55 » » leftDelim: t.leftDelim, |
45 // panics if a value in the map is not a function with appropriate return | 56 » » rightDelim: t.rightDelim, |
46 // type. | 57 » } |
47 // The return value is the set, so calls can be chained. | 58 } |
48 func (s *Set) Funcs(funcMap FuncMap) *Set { | 59 |
49 » s.init() | 60 func (t *Template) init() { |
50 » addValueFuncs(s.execFuncs, funcMap) | 61 » if t.common == nil { |
51 » addFuncs(s.parseFuncs, funcMap) | 62 » » t.common = new(common) |
52 » return s | 63 » » t.tmpl = make(map[string]*Template) |
53 } | 64 » » t.parseFuncs = make(FuncMap) |
54 | 65 » » t.execFuncs = make(map[string]reflect.Value) |
55 // Add adds the argument templates to the set. It panics if two templates | 66 » } |
56 // with the same name are added or if a template is already a member of | 67 } |
57 // a set. | 68 |
58 // The return value is the set, so calls can be chained. | 69 // Clone returns a duplicate of the template, including all associated |
59 func (s *Set) Add(templates ...*Template) *Set { | 70 // templates. The actual representation is not copied, but the name space of |
60 » for _, t := range templates { | 71 // associated templates is, so further calls to Parse in the copy will add |
61 » » if err := s.add(t); err != nil { | 72 // templates to the copy but not to the original. Clone can be used to prepare |
62 » » » panic(err) | 73 // common templates and use them with variant definitions for other templates by |
63 » » } | 74 // adding the variants after the clone is made. |
64 » } | 75 func (t *Template) Clone() *Template { |
65 » return s | 76 » nt := t.copy() |
66 } | 77 » nt.init() |
67 | 78 » for k, v := range t.tmpl { |
68 // add adds the argument template to the set. | 79 » » // The associated templates share nt's common structure. |
69 func (s *Set) add(t *Template) error { | 80 » » tmpl := v.copy() |
70 » s.init() | 81 » » tmpl.common = nt.common |
71 » if t.set != nil { | 82 » » nt.tmpl[k] = tmpl |
72 » » return fmt.Errorf("template: %q already in a set", t.name) | 83 » } |
73 » } | 84 » for k, v := range t.parseFuncs { |
74 » if _, ok := s.tmpl[t.name]; ok { | 85 » » nt.parseFuncs[k] = v |
75 » » return fmt.Errorf("template: %q already defined in set", t.name) | 86 » } |
76 » } | 87 » for k, v := range t.execFuncs { |
77 » s.tmpl[t.name] = t | 88 » » nt.execFuncs[k] = v |
78 » t.set = s | 89 » } |
79 » return nil | 90 » return nt |
80 } | 91 } |
81 | 92 |
82 // Template returns the template with the given name in the set, | 93 // copy returns a shallow copy of t, with common set to nil. |
| 94 func (t *Template) copy() *Template { |
| 95 » nt := New(t.name) |
| 96 » nt.Tree = t.Tree |
| 97 » nt.leftDelim = t.leftDelim |
| 98 » nt.rightDelim = t.rightDelim |
| 99 » return nt |
| 100 } |
| 101 |
| 102 // Templates returns a slice of the templates associated with t, including t |
| 103 // itself. |
| 104 func (t *Template) Templates() []*Template { |
| 105 » // Return a slice so we don't expose the map. |
| 106 » m := make([]*Template, 0, len(t.tmpl)) |
| 107 » for _, v := range t.tmpl { |
| 108 » » m = append(m, v) |
| 109 » } |
| 110 » return m |
| 111 } |
| 112 |
| 113 // Delims sets the action delimiters to the specified strings, to be used in |
| 114 // subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template |
| 115 // definitions will inherit the settings. An empty delimiter stands for the |
| 116 // corresponding default: {{ or }}. |
| 117 // The return value is the template, so calls can be chained. |
| 118 func (t *Template) Delims(left, right string) *Template { |
| 119 » t.leftDelim = left |
| 120 » t.rightDelim = right |
| 121 » return t |
| 122 } |
| 123 |
| 124 // Funcs adds the elements of the argument map to the template's function map. |
| 125 // It panics if a value in the map is not a function with appropriate return |
| 126 // type. However, it is legal to overwrite elements of the map. The return |
| 127 // value is the template, so calls can be chained. |
| 128 func (t *Template) Funcs(funcMap FuncMap) *Template { |
| 129 » t.init() |
| 130 » addValueFuncs(t.execFuncs, funcMap) |
| 131 » addFuncs(t.parseFuncs, funcMap) |
| 132 » return t |
| 133 } |
| 134 |
| 135 // Template returns the template with the given name that is associated with t, |
83 // or nil if there is no such template. | 136 // or nil if there is no such template. |
84 func (s *Set) Template(name string) *Template { | 137 func (t *Template) Template(name string) *Template { |
85 » return s.tmpl[name] | 138 » return t.tmpl[name] |
86 } | 139 } |
87 | 140 |
88 // FuncMap returns the set's function map. | 141 // Parse parses a string into a template. Nested template definitions will be |
89 func (s *Set) FuncMap() FuncMap { | 142 // associated with the top-level template t. Parse may be called multiple times |
90 » return s.parseFuncs | 143 // to parse definitions of templates to associate with t. It is an error if a |
91 } | 144 // resulting template is non-empty (contains content other than template |
92 | 145 // definitions) and would replace a non-empty template with the same name. |
93 // Execute applies the named template to the specified data object, writing | 146 // (In multiple calls to Parse with the same receiver template, only one call |
94 // the output to wr. | 147 // can contain text other than space, comments, and template definitions.) |
95 func (s *Set) Execute(wr io.Writer, name string, data interface{}) error { | 148 func (t *Template) Parse(text string) (*Template, error) { |
96 » tmpl := s.tmpl[name] | 149 » t.init() |
97 » if tmpl == nil { | 150 » trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.par
seFuncs, builtins) |
98 » » return fmt.Errorf("template: no template %q in set", name) | |
99 » } | |
100 » return tmpl.Execute(wr, data) | |
101 } | |
102 | |
103 // Parse parses a string into a set of named templates. Parse may be called | |
104 // multiple times for a given set, adding the templates defined in the string | |
105 // to the set. It is an error if a template has a name already defined in the s
et. | |
106 func (s *Set) Parse(text string) (*Set, error) { | |
107 » // TODO: "ROOT" is just a placeholder while we rejig the API. | |
108 » trees, err := parse.Parse("ROOT", text, s.leftDelim, s.rightDelim, s.par
seFuncs, builtins) | |
109 if err != nil { | 151 if err != nil { |
110 return nil, err | 152 return nil, err |
111 } | 153 } |
112 » s.init() | 154 » // Add the newly parsed trees, including the one for t, into our common
structure. |
113 for name, tree := range trees { | 155 for name, tree := range trees { |
114 » » tmpl := New(name) | 156 » » // If the name we parsed is the name of this template, overwrite
this template. |
| 157 » » // The associate method checks it's not a redefinition. |
| 158 » » tmpl := t |
| 159 » » if name != t.name { |
| 160 » » » tmpl = t.New(name) |
| 161 » » } |
| 162 » » // Even if t == tmpl, we need to install it in the common.tmpl m
ap. |
| 163 » » if err := t.associate(tmpl); err != nil { |
| 164 » » » return nil, err |
| 165 » » } |
115 tmpl.Tree = tree | 166 tmpl.Tree = tree |
116 » » err = s.add(tmpl) | 167 » » tmpl.leftDelim = t.leftDelim |
117 » » if err != nil { | 168 » » tmpl.rightDelim = t.rightDelim |
118 » » » return s, err | 169 » } |
119 » » } | 170 » return t, nil |
120 » } | 171 } |
121 » return s, nil | 172 |
122 } | 173 // associate installs the new template into the group of templates associated |
| 174 // with t. It is an error to reuse a name except to overwrite an empty |
| 175 // template. The two are already known to share the common structure. |
| 176 func (t *Template) associate(new *Template) error { |
| 177 » if new.common != t.common { |
| 178 » » panic("internal error: associate not common") |
| 179 » } |
| 180 » name := new.name |
| 181 » if old := t.tmpl[name]; old != nil { |
| 182 » » oldIsEmpty := isEmpty(old.Root) |
| 183 » » newIsEmpty := isEmpty(new.Root) |
| 184 » » if !oldIsEmpty && !newIsEmpty { |
| 185 » » » return fmt.Errorf("template: redefinition of template %q
", name) |
| 186 » » } |
| 187 » » if newIsEmpty { |
| 188 » » » // Whether old is empty or not, new is empty; no reason
to replace old. |
| 189 » » » return nil |
| 190 » » } |
| 191 » } |
| 192 » t.tmpl[name] = new |
| 193 » return nil |
| 194 } |
| 195 |
| 196 // isEmpty reports whether this tree (node) is empty of everything but space. |
| 197 func isEmpty(n parse.Node) bool { |
| 198 » switch n := n.(type) { |
| 199 » case *parse.ActionNode: |
| 200 » case *parse.IfNode: |
| 201 » case *parse.ListNode: |
| 202 » » for _, node := range n.Nodes { |
| 203 » » » if !isEmpty(node) { |
| 204 » » » » return false |
| 205 » » » } |
| 206 » » } |
| 207 » » return true |
| 208 » case *parse.RangeNode: |
| 209 » case *parse.TemplateNode: |
| 210 » case *parse.TextNode: |
| 211 » » return len(bytes.TrimSpace(n.Text)) == 0 |
| 212 » case *parse.WithNode: |
| 213 » default: |
| 214 » » panic("unknown node: " + n.String()) |
| 215 » } |
| 216 » return false |
| 217 } |
OLD | NEW |