0001 // The MIT License 0002 // 0003 // Copyright (c) 2015 Gwendal Roué 0004 // 0005 // Permission is hereby granted, free of charge, to any person obtaining a copy 0006 // of this software and associated documentation files (the "Software"), to deal 0007 // in the Software without restriction, including without limitation the rights 0008 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0009 // copies of the Software, and to permit persons to whom the Software is 0010 // furnished to do so, subject to the following conditions: 0011 // 0012 // The above copyright notice and this permission notice shall be included in 0013 // all copies or substantial portions of the Software. 0014 // 0015 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0016 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0017 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0018 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0019 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 0020 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 0021 // THE SOFTWARE. 0022 0023 /** 0024 Template instances render Mustache templates. 0025 */ 0026 final public class Template{ 0027 0028 // ========================================================================= 0029 // MARK: - Loading templates 0030 0031 /** 0032 Parses a template string, and returns a template. 0033 0034 - parameter string: The template string. 0035 - parameter error: If there is an error loading or parsing template and 0036 partials, throws an error that describes the problem. 0037 - returns: A new Template. 0038 */ 0039 public convenience init(string: String) throws { 0040 let repository = TemplateRepository() 0041 let templateAST = try repository.templateAST(string: string) 0042 self.init(repository: repository, templateAST: templateAST, baseContext: repository.configuration.baseContext) 0043 } 0044 0045 // ========================================================================= 0046 // MARK: - Rendering Templates 0047 0048 /** 0049 Renders a template with a context stack initialized with the provided box 0050 on top of the templates's base context. 0051 0052 - parameter box: A boxed value used for evaluating Mustache tags. 0053 - parameter error: If there is an error rendering the tag, throws an error 0054 that describes the problem. 0055 - returns: The rendered string. 0056 */ 0057 public func render(box: MustacheBox = Box()) throws -> String { 0058 let rendering = try render(baseContext.extendedContext(box)) 0059 return rendering.string 0060 } 0061 0062 /** 0063 Returns the rendering of the receiver, evaluating mustache tags from values 0064 stored in the given context stack. 0065 0066 This method does not return a String, but a Rendering value that wraps both 0067 the rendered string and its content type (HTML or Text). It is intended to 0068 be used when you perform custom rendering in a `RenderFunction`. 0069 0070 - parameter context: A context stack 0071 - parameter error: If there is an error rendering the tag, throws an 0072 error that describes the problem. 0073 - returns: The template rendering. 0074 0075 See also: 0076 0077 - RenderFunction 0078 - Template.contentType 0079 */ 0080 public func render
TemplateGenerator.swift:32 extension Template : CustomDebugStringConvertible {Template.swift:219 extension Template : MustacheBoxable {TemplateRepository.swift:188 public func template(string string: String) throws -> Template {TemplateRepository.swift:190 return Template(repository: self, templateAST: templateAST, baseContext: lockedConfiguration.baseContext)TemplateRepository.swift:212 public func template(named name: String) throws -> Template {TemplateRepository.swift:214 return Template(repository: self, templateAST: templateAST, baseContext: lockedConfiguration.baseContext)(context: Context) throws -> Rendering { 0081 let renderingEngine = RenderingEngine(templateAST: templateAST, context: context) 0082 return try renderingEngine.render() 0083 } 0084 0085 /** 0086 The content type of the template and of its renderings. 0087 0088 See `Configuration.contentType` for a full discussion of the content type of 0089 templates. 0090 */ 0091 public var contentType: ContentType { 0092 return templateAST.contentType 0093 } 0094 0095 0096 // ========================================================================= 0097 // MARK: - Configuring Templates 0098 0099 /** 0100 The template's base context: all renderings start from this context. 0101 0102 Its default value comes from the configuration of the template 0103 repository this template comes from. 0104 0105 You can set the base context to some custom context, or extend it with the 0106 `extendBaseContext` and `registerInBaseContext` methods. 0107 0108 // Renders "bar" 0109 let template = try! Template(string: "{{foo}}") 0110 template.baseContext = Context(Box(["foo": "bar"])) 0111 try! template.render() 0112 0113 See also: 0114 0115 - extendBaseContext 0116 - registerInBaseContext 0117 */ 0118 public var baseContext
CoreFunctions.swift:516 return try template.render(info.context)CoreFunctions.swift:632 return try template.render(info.context)Template.swift:58 let rendering = try render(baseContext.extendedContext(box))Template.swift:288 return try self.render(info.context): Context 0119 0120 /** 0121 Extends the base context with the provided boxed value. All renderings will 0122 start from this extended context. 0123 0124 // Renders "bar" 0125 let template = try! Template(string: "{{foo}}") 0126 template.extendBaseContext(Box(["foo": "bar"])) 0127 try! template.render() 0128 0129 See also: 0130 0131 - baseContext 0132 - registerInBaseContext 0133 - Context.extendedContext 0134 */ 0135 public func extendBaseContext(box: MustacheBox) { 0136 baseContext = baseContext.extendedContext(box) 0137 } 0138 0139 /** 0140 Registers a key in the base context. All renderings will be able to access 0141 the provided box through this key. 0142 0143 Registered keys are looked up first when evaluating Mustache tags. 0144 0145 // Renders "bar" 0146 let template = try! Template(string: "{{foo}}") 0147 template.registerInBaseContext("foo", Box("bar")) 0148 try! template.render() 0149 0150 // Renders "bar" again, because the registered key "foo" has priority. 0151 try! template.render(Box(["foo": "qux"])) 0152 0153 See also: 0154 0155 - baseContext 0156 - extendBaseContext 0157 - Context.contextWithRegisteredKey 0158 */ 0159 public func registerInBaseContext(key: String, _ box: MustacheBox) { 0160 baseContext = baseContext.contextWithRegisteredKey(key, box: box) 0161 } 0162 0163 0164 // ========================================================================= 0165 // MARK: - Accessing Sibling Templates 0166 0167 /** 0168 The template repository that issued the receiver. 0169 0170 All templates belong a template repository: 0171 0172 - Templates returned by `init(string:)` have a template 0173 repository that can not load any template or partial by name. 0174 0175 - Templates returned by `init(path:encoding:)` have a template 0176 repository that loads templates and partials stored in the directory of 0177 the receiver, with the same file extension. 0178 0179 - Templates returned by `init(URL:encoding:)` have a template 0180 repository that loads templates and partials stored in the directory of 0181 the receiver, with the same file extension. 0182 0183 - Templates returned by `init(named:bundle:templateExtension:encoding:)` 0184 have a template repository that loads templates and partials stored as 0185 resources in the specified bundle. 0186 0187 - Templates returned by `TemplateRepository.template(named:)` and 0188 `TemplateRepository.template(string:)` belong to the invoked 0189 repository. 0190 0191 See also: 0192 0193 - TemplateRepository 0194 - init(string:) 0195 - init(path:) 0196 - init(URL:) 0197 - init(named:bundle:templateExtension:encoding:) 0198 */ 0199 public let repository
Template.swift:58 let rendering = try render(baseContext.extendedContext(box))Template.swift:136 baseContext = baseContext.extendedContext(box)Template.swift:136 baseContext = baseContext.extendedContext(box)Template.swift:160 baseContext = baseContext.contextWithRegisteredKey(key, box: box)Template.swift:160 baseContext = baseContext.contextWithRegisteredKey(key, box: box)Template.swift:210 self.baseContext = baseContext: TemplateRepository 0200 0201 0202 // ========================================================================= 0203 // MARK: - Not public 0204 0205 let templateAST
Template.swift:208 self.repository = repository: TemplateAST 0206 0207 init
TemplateGenerator.swift:35 let string = TemplateGenerator().stringFromTemplateAST(templateAST)Template.swift:81 let renderingEngine = RenderingEngine(templateAST: templateAST, context: context)Template.swift:92 return templateAST.contentTypeTemplate.swift:209 self.templateAST = templateASTTemplate.swift:274 parentTemplateAST: self.templateAST)Template.swift:279 templateAST: TemplateAST(nodes: [partialOverrideNode], contentType: self.templateAST.contentType),(repository: TemplateRepository, templateAST: TemplateAST, baseContext: Context) { 0208 self.repository = repository 0209 self.templateAST = templateAST 0210 self.baseContext = baseContext 0211 } 0212 0213 } 0214 0215 0216 // ========================================================================= 0217 // MARK: - MustacheBoxable 0218 0219 extension Template : MustacheBoxable { 0220 0221 /** 0222 `Template` adopts the `MustacheBoxable` protocol so that it can feed 0223 Mustache templates. 0224 0225 You should not directly call the `mustacheBox` property. Always use the 0226 `Box()` function instead: 0227 0228 template.mustacheBox // Valid, but discouraged 0229 Box(template) // Preferred 0230 0231 0232 A template renders just like a partial tag: 0233 0234 - `{{template}}` renders like an embedded partial tag `{{>partial}}` that 0235 would refer to the same template. 0236 0237 - `{{#template}}...{{/template}}` renders like a partial override tag 0238 `{{<partial}}...{{/partial}}` that would refer to the same template. 0239 0240 The difference is that `{{>partial}}` is a hard-coded template name, when 0241 `{{template}}` is a template that you can choose at runtime. 0242 0243 0244 For example: 0245 0246 let template = try! Template(string: "<a href='{{url}}'>{{firstName}} {{lastName}}</a>") 0247 let data = [ 0248 "firstName": Box("Salvador"), 0249 "lastName": Box("Dali"), 0250 "url": Box("/people/123"), 0251 "template": Box(template) 0252 ] 0253 0254 // <a href='/people/123'>Salvador Dali</a> 0255 try! Template(string: "{{template}}").render(Box(data)) 0256 0257 Note that templates whose contentType is Text are HTML-escaped when they are 0258 included in an HTML template. 0259 */ 0260 public var mustacheBox: MustacheBox { 0261 return MustacheBox( 0262 value: self, 0263 render: { (info) in 0264 switch info.tag { 0265 case let sectionTag as SectionTag: 0266 // {{# template }}...{{/ template }} behaves just like {{< partial }}...{{/ partial }} 0267 // 0268 // Let's render the template, overriding blocks with the content 0269 // of the section. 0270 // 0271 // Overriding requires an PartialOverrideNode: 0272 let partialOverrideNode = TemplateASTNode.partialOverride( 0273 childTemplateAST: sectionTag.innerTemplateAST, 0274 parentTemplateAST: self.templateAST) 0275 0276 // Only RenderingEngine knows how to render PartialOverrideNode. 0277 // So wrap the node into a TemplateAST, and render. 0278 let renderingEngine = RenderingEngine( 0279 templateAST: TemplateAST(nodes: [partialOverrideNode], contentType: self.templateAST.contentType), 0280 context: info.context) 0281 return try renderingEngine.render() 0282 default: 0283 // Assume Variable tag 0284 // 0285 // {{ template }} behaves just like {{> partial }} 0286 // 0287 // Let's simply render the template: 0288 return try self.render(info.context) 0289 } 0290 }) 0291 } 0292 } 0293
Template.swift:42 self.init(repository: repository, templateAST: templateAST, baseContext: repository.configuration.baseContext)TemplateRepository.swift:190 return Template(repository: self, templateAST: templateAST, baseContext: lockedConfiguration.baseContext)TemplateRepository.swift:214 return Template(repository: self, templateAST: templateAST, baseContext: lockedConfiguration.baseContext)