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    // MARK: - KeyedSubscriptFunction
0025    
0026    /**
0027    `KeyedSubscriptFunction` is used by the Mustache rendering engine whenever it
0028    has to resolve identifiers in expressions such as `{{ name }}` or
0029    `{{ user.name }}`. Subscript functions turn those identifiers into
0030    `MustacheBox`, the type that wraps rendered values.
0031    
0032    All types that expose keys to Mustache templates provide such a subscript
0033    function by conforming to the `MustacheBoxable` protocol. This is the case of
0034    built-in types such as NSObject, that uses `valueForKey:` in order to expose
0035    its properties; String, which exposes its "length"; collections, which expose
0036    keys like "count", "first", etc. etc.
0037        
0038        var box = Box("string")
0039        box = box["length"] // Evaluates the KeyedSubscriptFunction
0040        box.value           // 6
0041        
0042        box = Box(["a", "b", "c"])
0043        box = box["first"]  // Evaluates the KeyedSubscriptFunction
0044        box.value           // "a"
0045    
0046    Your can build boxes that hold a custom subscript function. This is a rather
0047    advanced usage, only supported with the low-level function
0048    `func Box(boolValue:value:keyedSubscript:filter:render:willRender:didRender:) -> MustacheBox`.
0049        
0050        // A KeyedSubscriptFunction that turns "key" into "KEY":
0051        let keyedSubscript: KeyedSubscriptFunction = { (key: String) -> MustacheBox in
0052            return Box(key.uppercaseString)
0053        }
0054    
0055        // Render "FOO & BAR"
0056        let template = try! Template(string: "{{foo}} & {{bar}}")
0057        let box = Box(keyedSubscript: keyedSubscript)
0058        try! template.render(box)
0059    
0060    
0061    ### Missing keys vs. missing values.
0062    
0063    `KeyedSubscriptFunction` returns a non-optional `MustacheBox`.
0064    
0065    In order to express "missing key", and have Mustache rendering engine dig deeper
0066    in the context stack in order to resolve a key, return the empty box `Box()`.
0067    
0068    In order to express "missing value", and prevent the rendering engine from
0069    digging deeper, return `Box(NSNull())`.
0070    */
0071    public typealias KeyedSubscriptFunction
Box.swift:1666
    keyedSubscript: KeyedSubscriptFunction? = nil,
MustacheBox.swift:416
        keyedSubscript: KeyedSubscriptFunction? = nil,
MustacheBox.swift:437
    let keyedSubscript: KeyedSubscriptFunction?
MustacheBox.swift:444
        keyedSubscript: KeyedSubscriptFunction? = nil,
= (key: String) -> MustacheBox 0072 0073 0074 // ============================================================================= 0075 // MARK: - FilterFunction 0076 0077 /** 0078 `FilterFunction` is the core type that lets GRMustache evaluate filtered 0079 expressions such as `{{ uppercase(string) }}`. 0080 0081 To build a filter, you use the `Filter()` function. It takes a function as an 0082 argument. For example: 0083 0084 let increment = Filter { (x: Int?) in 0085 return Box(x! + 1) 0086 } 0087 0088 To let a template use a filter, register it: 0089 0090 let template = try! Template(string: "{{increment(x)}}") 0091 template.registerInBaseContext("increment", Box(increment)) 0092 0093 // "2" 0094 try! template.render(Box(["x": 1])) 0095 0096 `Filter()` can take several types of functions, depending on the type of filter 0097 you want to build. The example above processes `Int` values. There are three 0098 types of filters: 0099 0100 - Values filters: 0101 0102 - `(MustacheBox) throws -> MustacheBox` 0103 - `(T?) throws -> MustacheBox` (Generic) 0104 - `([MustacheBox]) throws -> MustacheBox` (Multiple arguments) 0105 0106 - Pre-rendering filters: 0107 0108 - `(Rendering) throws -> Rendering` 0109 0110 - Custom rendering filters: 0111 0112 - `(MustacheBox, RenderingInfo) throws -> Rendering` 0113 - `(T?, RenderingInfo) throws -> Rendering` (Generic) 0114 0115 See the documentation of the `Filter()` functions. 0116 */ 0117 public typealias FilterFunction
Box.swift:1322
public func Box(filter filter: FilterFunction) -> MustacheBox {
Box.swift:1667
    filter: FilterFunction? = nil,
CoreFunctions.swift:144
public func Filter(filter: (MustacheBox) throws -> MustacheBox) -> FilterFunction {
CoreFunctions.swift:178
public func Filter<T>(filter: (T?) throws -> MustacheBox) -> FilterFunction {
CoreFunctions.swift:210
public func VariadicFilter(filter: ([MustacheBox]) throws -> MustacheBox) -> FilterFunction {
CoreFunctions.swift:219
    func partialFilter(filter: ([MustacheBox]) throws -> MustacheBox, arguments: [MustacheBox]) -> FilterFunction {
CoreFunctions.swift:264
public func Filter(filter: (Rendering) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:295
public func Filter(filter: (MustacheBox, RenderingInfo) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:342
public func Filter<T>(filter: (T?, RenderingInfo) throws -> Rendering) -> FilterFunction {
MustacheBox.swift:160
    public let filter: FilterFunction?
MustacheBox.swift:417
        filter: FilterFunction? = nil,
MustacheBox.swift:445
        filter: FilterFunction? = nil,
= (box: MustacheBox, partialApplication: Bool) throws -> MustacheBox 0118 0119 0120 // ----------------------------------------------------------------------------- 0121 // MARK: - Values Filters 0122 0123 /** 0124 Builds a filter that takes a single argument. 0125 0126 For example, here is the trivial `identity` filter: 0127 0128 let identity = Filter { (box: MustacheBox) in 0129 return box 0130 } 0131 0132 let template = try! Template(string: "{{identity(a)}}, {{identity(b)}}") 0133 template.registerInBaseContext("identity", Box(identity)) 0134 0135 // "foo, 1" 0136 try! template.render(Box(["a": "foo", "b": 1])) 0137 0138 If the template provides more than one argument, the filter returns a 0139 MustacheError of type RenderError. 0140 0141 - parameter filter: A function `(MustacheBox) throws -> MustacheBox`. 0142 - returns: A FilterFunction. 0143 */ 0144 public func Filter
EachFilter.swift:23
let EachFilter = Filter { (box: MustacheBox) -> MustacheBox in
CoreFunctions.swift:296
    return Filter { (box: MustacheBox) in
(filter: (MustacheBox) throws -> MustacheBox) -> FilterFunction { 0145 return { (box: MustacheBox, partialApplication: Bool) in 0146 guard !partialApplication else { 0147 // This is a single-argument filter: we do not wait for another one. 0148 throw MustacheError(kind: .RenderError, message: "Too many arguments") 0149 } 0150 return try filter(box) 0151 } 0152 } 0153 0154 /** 0155 Builds a filter that takes a single argument of type `T?`. 0156 0157 For example: 0158 0159 let increment = Filter { (x: Int?) in 0160 return Box(x! + 1) 0161 } 0162 0163 let template = try! Template(string: "{{increment(x)}}") 0164 template.registerInBaseContext("increment", Box(increment)) 0165 0166 // "2" 0167 try! template.render(Box(["x": 1])) 0168 0169 The argument is converted to `T` using the built-in `as?` operator before being 0170 given to the filter. 0171 0172 If the template provides more than one argument, the filter returns a 0173 MustacheError of type RenderError. 0174 0175 - parameter filter: A function `(T?) throws -> MustacheBox`. 0176 - returns: A FilterFunction. 0177 */ 0178 public func Filter
CoreFunctions.swift:343
    return Filter { (t: T?) in
<T>(filter: (T?) throws -> MustacheBox) -> FilterFunction { 0179 return { (box: MustacheBox, partialApplication: Bool) in 0180 guard !partialApplication else { 0181 // This is a single-argument filter: we do not wait for another one. 0182 throw MustacheError(kind: .RenderError, message: "Too many arguments") 0183 } 0184 return try filter(box.value as? T) 0185 } 0186 } 0187 0188 /** 0189 Returns a filter than accepts any number of arguments. 0190 0191 For example: 0192 0193 // `sum(x, ...)` evaluates to the sum of provided integers 0194 let sum = VariadicFilter { (boxes: [MustacheBox]) in 0195 // Extract integers out of input boxes, assuming zero for non numeric values 0196 let integers = boxes.map { (box) in (box.value as? Int) ?? 0 } 0197 let sum = integers.reduce(0, combine: +) 0198 return Box(sum) 0199 } 0200 0201 let template = try! Template(string: "{{ sum(a,b,c) }}") 0202 template.registerInBaseContext("sum", Box(sum)) 0203 0204 // Renders "6" 0205 try! template.render(Box(["a": 1, "b": 2, "c": 3])) 0206 0207 - parameter filter: A function `([MustacheBox]) throws -> MustacheBox`. 0208 - returns: A FilterFunction. 0209 */ 0210 public func VariadicFilter
ZipFilter.swift:23
let ZipFilter = VariadicFilter { (boxes) in
(filter: ([MustacheBox]) throws -> MustacheBox) -> FilterFunction { 0211 0212 // f(a,b,c) is implemented as f(a)(b)(c). 0213 // 0214 // f(a) returns another filter, which returns another filter, which 0215 // eventually computes the final result. 0216 // 0217 // It is the partialApplication flag the tells when it's time to return the 0218 // final result. 0219 func partialFilter(filter: ([MustacheBox]) throws -> MustacheBox, arguments: [MustacheBox]) -> FilterFunction { 0220 return { (nextArgument: MustacheBox, partialApplication: Bool) in 0221 let arguments = arguments + [nextArgument] 0222 if partialApplication { 0223 // Wait for another argument 0224 return Box(filter: partialFilter(filter, arguments: arguments)) 0225 } else { 0226 // No more argument: compute final value 0227 return try filter(arguments) 0228 } 0229 } 0230 } 0231 0232 return partialFilter(filter, arguments: []) 0233 } 0234 0235 0236 // ----------------------------------------------------------------------------- 0237 // MARK: - Pre-Rendering Filters 0238 0239 /** 0240 Builds a filter that performs post rendering. 0241 0242 `Rendering` is a type that wraps a rendered String, and its content type (HTML 0243 or Text). This filter turns a rendering in another one: 0244 0245 // twice filter renders its argument twice: 0246 let twice = Filter { (rendering: Rendering) in 0247 return Rendering(rendering.string + rendering.string, rendering.contentType) 0248 } 0249 0250 let template = try! Template(string: "{{ twice(x) }}") 0251 template.registerInBaseContext("twice", Box(twice)) 0252 0253 // Renders "foofoo", "123123" 0254 try! template.render(Box(["x": "foo"])) 0255 try! template.render(Box(["x": 123])) 0256 0257 When this filter is executed, eventual HTML-escaping performed by the rendering 0258 engine has not happened yet: the rendering argument may contain raw text. This 0259 allows you to chain pre-rendering filters without mangling HTML entities. 0260 0261 - parameter filter: A function `(Rendering) throws -> Rendering`. 0262 - returns: A FilterFunction. 0263 */ 0264 public func Filter
HTMLEscapeHelper.swift:33
            filter: Filter(filter),
JavascriptEscapeHelper.swift:33
            filter: Filter(filter),
(filter: (Rendering) throws -> Rendering) -> FilterFunction { 0265 return { (box: MustacheBox, partialApplication: Bool) in 0266 guard !partialApplication else { 0267 // This is a single-argument filter: we do not wait for another one. 0268 throw MustacheError(kind: .RenderError, message: "Too many arguments") 0269 } 0270 // Box a RenderFunction 0271 return Box { (info: RenderingInfo) in 0272 let rendering = try box.render(info: info) 0273 return try filter(rendering) 0274 } 0275 } 0276 } 0277 0278 0279 // ----------------------------------------------------------------------------- 0280 // MARK: - Custom Rendering Filters 0281 0282 /** 0283 Builds a filter that takes a single argument and performs custom rendering. 0284 0285 See the documentation of the `RenderFunction` type for a detailed discussion of 0286 the `RenderingInfo` and `Rendering` types. 0287 0288 For an example of such a filter, see the documentation of 0289 `func Filter<T>(filter: (T?, RenderingInfo) throws -> Rendering) -> FilterFunction`. 0290 This example processes `T?` instead of `MustacheBox`, but the idea is the same. 0291 0292 - parameter filter: A function `(MustacheBox, RenderingInfo) throws -> Rendering`. 0293 - returns: A FilterFunction. 0294 */ 0295 public func Filter(filter: (MustacheBox, RenderingInfo) throws -> Rendering) -> FilterFunction { 0296 return Filter { (box: MustacheBox) in 0297 // Box a RenderFunction 0298 return Box { (info: RenderingInfo) in 0299 return try filter(box, info) 0300 } 0301 } 0302 } 0303 0304 /** 0305 Builds a filter that takes a single argument of type `T?` and performs custom 0306 rendering. 0307 0308 For example: 0309 0310 // {{# pluralize(count) }}...{{/ }} renders the plural form of the section 0311 // content if the `count` argument is greater than 1. 0312 let pluralize = Filter { (count: Int?, info: RenderingInfo) in 0313 0314 // Pluralize the inner content of the section tag: 0315 var string = info.tag.innerTemplateString 0316 if count > 1 { 0317 string += "s" // naive pluralization 0318 } 0319 0320 return Rendering(string) 0321 } 0322 0323 let template = try! Template(string: "I have {{ cats.count }} {{# pluralize(cats.count) }}cat{{/ }}.") 0324 template.registerInBaseContext("pluralize", Box(pluralize)) 0325 0326 // Renders "I have 3 cats." 0327 let data = ["cats": ["Kitty", "Pussy", "Melba"]] 0328 try! template.render(Box(data)) 0329 0330 The argument is converted to `T` using the built-in `as?` operator before being 0331 given to the filter. 0332 0333 If the template provides more than one argument, the filter returns a 0334 MustacheError of type RenderError. 0335 0336 See the documentation of the `RenderFunction` type for a detailed discussion of 0337 the `RenderingInfo` and `Rendering` types. 0338 0339 - parameter filter: A function `(T?, RenderingInfo) throws -> Rendering`. 0340 - returns: A FilterFunction. 0341 */ 0342 public func Filter<T>(filter: (T?, RenderingInfo) throws -> Rendering) -> FilterFunction { 0343 return Filter { (t: T?) in 0344 // Box a RenderFunction 0345 return Box { (info: RenderingInfo) in 0346 return try filter(t, info) 0347 } 0348 } 0349 } 0350 0351 0352 // ============================================================================= 0353 // MARK: - RenderFunction 0354 0355 /** 0356 `RenderFunction` is used by the Mustache rendering engine when it renders a 0357 variable tag (`{{name}}` or `{{{body}}}`) or a section tag 0358 (`{{#name}}...{{/name}}`). 0359 0360 0361 ### Output: `Rendering` 0362 0363 The return type of `RenderFunction` is `Rendering`, a type that wraps a rendered 0364 String, and its ContentType (HTML or Text). 0365 0366 Text renderings are HTML-escaped, except for `{{{triple}}}` mustache tags, and 0367 Text templates (see `Configuration.contentType` for a full discussion of the 0368 content type of templates). 0369 0370 For example: 0371 0372 let HTML: RenderFunction = { (_) in 0373 return Rendering("<HTML>", .HTML) 0374 } 0375 let text: RenderFunction = { (_) in 0376 return Rendering("<text>") // default content type is text 0377 } 0378 0379 // Renders "<HTML>, &lt;text&gt;" 0380 let template = try! Template(string: "{{HTML}}, {{text}}") 0381 let data = ["HTML": Box(HTML), "text": Box(text)] 0382 let rendering = try! template.render(Box(data)) 0383 0384 0385 ### Input: `RenderingInfo` 0386 0387 The `info` argument contains a `RenderingInfo` which provides information 0388 about the requested rendering: 0389 0390 - `info.context: Context` is the context stack which contains the rendered data. 0391 0392 - `info.tag: Tag` is the tag to render. 0393 0394 - `info.tag.type: TagType` is the type of the tag (variable or section). You can 0395 use this type to have a different rendering for variable and section tags. 0396 0397 - `info.tag.innerTemplateString: String` is the inner content of the tag, 0398 unrendered. For the section tag `{{# person }}Hello {{ name }}!{{/ person }}`, 0399 it is `Hello {{ name }}!`. 0400 0401 - `info.tag.render: (Context) throws -> Rendering` is a 0402 function that renders the inner content of the tag, given a context stack. 0403 For example, the section tag `{{# person }}Hello {{ name }}!{{/ person }}` 0404 would render `Hello Arthur!`, assuming the provided context stack provides 0405 "Arthur" for the key "name". 0406 0407 0408 ### Example 0409 0410 As an example, let's write a `RenderFunction` which performs the default 0411 rendering of a value: 0412 0413 - `{{ value }}` and `{{{ value }}}` renders the built-in Swift String 0414 Interpolation of the value: our render function will return a `Rendering` with 0415 content type Text when the rendered tag is a variable tag. The Text content 0416 type makes sure that the returned string will be HTML-escaped if needed. 0417 0418 - `{{# value }}...{{/ value }}` pushes the value on the top of the context 0419 stack, and renders the inner content of section tags. 0420 0421 The default rendering thus reads: 0422 0423 let value = ... // Some value 0424 let renderValue: RenderFunction = { (info: RenderingInfo) throws in 0425 0426 // Default rendering depends on the tag type: 0427 switch info.tag.type { 0428 0429 case .Variable: 0430 // {{ value }} and {{{ value }}} 0431 0432 // Return the built-in Swift String Interpolation of the value: 0433 return Rendering("\(value)", .Text) 0434 0435 case .Section: 0436 // {{# value }}...{{/ value }} 0437 0438 // Push the value on the top of the context stack: 0439 let context = info.context.extendedContext(Box(value)) 0440 0441 // Renders the inner content of the section tag: 0442 return try info.tag.render(context) 0443 } 0444 } 0445 0446 let template = try! Template(string: "{{value}}") 0447 let rendering = try! template.render(Box(["value": Box(renderValue)])) 0448 0449 - parameter info: A RenderingInfo. 0450 - parameter error: If there is a problem in the rendering, throws an error 0451 that describes the problem. 0452 - returns: A Rendering. 0453 */ 0454 public typealias RenderFunction
EachFilter.swift:44
            let customRenderFunction: RenderFunction = { info in
EachFilter.swift:77
            let customRenderFunction: RenderFunction = { info in
ZipFilter.swift:47
    var renderFunctions: [RenderFunction] = []
ZipFilter.swift:76
        let renderFunction: RenderFunction = { (info) -> Rendering in
Box.swift:1343
public func Box(render render: RenderFunction) -> MustacheBox {
Box.swift:1668
    render: RenderFunction? = nil,
CoreFunctions.swift:499
public func Lambda(lambda: String -> String) -> RenderFunction {
CoreFunctions.swift:616
public func Lambda(lambda: () -> String) -> RenderFunction {
MustacheBox.swift:157
    public private(set) var render: RenderFunction
MustacheBox.swift:418
        render: RenderFunction? = nil,
MustacheBox.swift:446
        render: RenderFunction? = nil,
= (info: RenderingInfo) throws -> Rendering 0455 0456 0457 // ----------------------------------------------------------------------------- 0458 // MARK: - Mustache lambdas 0459 0460 /** 0461 Builds a `RenderFunction` which conforms to the "lambda" defined by the 0462 Mustache specification (see https://github.com/mustache/spec/blob/v1.1.2/specs/%7Elambdas.yml). 0463 0464 The `lambda` parameter is a function which takes the unrendered context of a 0465 section, and returns a String. The returned `RenderFunction` renders this string 0466 against the current delimiters. 0467 0468 For example: 0469 0470 let template = try! Template(string: "{{#bold}}{{name}} has a Mustache!{{/bold}}") 0471 0472 let bold = Lambda { (string) in "<b>\(string)</b>" } 0473 let data = [ 0474 "name": Box("Clark Gable"), 0475 "bold": Box(bold)] 0476 0477 // Renders "<b>Clark Gable has a Mustache.</b>" 0478 let rendering = try! template.render(Box(data)) 0479 0480 **Warning**: the returned String is *parsed* each time the lambda is executed. 0481 In the example above, this is inefficient because the inner content of the 0482 bolded section has already been parsed with its template. You may prefer the raw 0483 `RenderFunction` type, capable of an equivalent and faster implementation: 0484 0485 let bold: RenderFunction = { (info: RenderingInfo) in 0486 let rendering = try info.tag.render(info.context) 0487 return Rendering("<b>\(rendering.string)</b>", rendering.contentType) 0488 } 0489 let data = [ 0490 "name": Box("Clark Gable"), 0491 "bold": Box(bold)] 0492 0493 // Renders "<b>Lionel Richie has a Mustache.</b>" 0494 let rendering = try! template.render(Box(data)) 0495 0496 - parameter lambda: A `String -> String` function. 0497 - returns: A RenderFunction. 0498 */ 0499 public func Lambda(lambda: String -> String) -> RenderFunction { 0500 return { (info: RenderingInfo) in 0501 switch info.tag.type { 0502 case .Variable: 0503 // {{ lambda }} 0504 return Rendering("(Lambda)") 0505 case .Section: 0506 // {{# lambda }}...{{/ lambda }} 0507 // 0508 // https://github.com/mustache/spec/blob/83b0721610a4e11832e83df19c73ace3289972b9/specs/%7Elambdas.yml#L117 0509 // > Lambdas used for sections should parse with the current delimiters 0510 0511 let templateRepository = TemplateRepository() 0512 templateRepository.configuration.tagDelimiterPair = info.tag.tagDelimiterPair 0513 0514 let templateString = lambda(info.tag.innerTemplateString) 0515 let template = try templateRepository.template(string: templateString) 0516 return try template.render(info.context) 0517 0518 // IMPLEMENTATION NOTE 0519 // 0520 // This lambda implementation is unable of two things: 0521 // 0522 // - process partial tags correctly, because it uses a 0523 // TemplateRepository that does not know how to load partials. 0524 // - honor the current content type. 0525 // 0526 // This partial problem is a tricky one to solve. A `{{>partial}}` 0527 // tag loads the "partial" template which is sibling of the 0528 // currently rendered template. 0529 // 0530 // Imagine the following template hierarchy: 0531 // 0532 // - /a.mustache: {{#lambda}}...{{/lambda}}...{{>dir/b}} 0533 // - /x.mustache: ... 0534 // - /dir/b.mustache: {{#lambda}}...{{/lambda}} 0535 // - /dir/x.mustache: ... 0536 // 0537 // If the lambda returns `{{>x}}` then rendering the `a.mustache` 0538 // template should trigger the inclusion of both `/x.mustache` and 0539 // `/dir/x.mustache`. 0540 // 0541 // Given the current state of GRMustache types, achieving proper 0542 // lambda would require: 0543 // 0544 // - a template repository 0545 // - a TemplateID 0546 // - a property `Tag.contentType` 0547 // - a method `TemplateRepository.template(string:contentType:tagDelimiterPair:baseTemplateID:)` 0548 // 0549 // Code would read something like: 0550 // 0551 // let templateString = lambda(info.tag.innerTemplateString) 0552 // let templateRepository = info.tag.templateRepository 0553 // let templateID = info.tag.templateID 0554 // let contentType = info.tag.contentType 0555 // let template = try templateRepository.template( 0556 // string: templateString, 0557 // contentType: contentType 0558 // tagDelimiterPair: info.tag.tagDelimiterPair, 0559 // baseTemplateID: templateID) 0560 // return try template.render(info.context) 0561 // 0562 // Should we ever implement this, beware the retain cycle between 0563 // tags and template repositories (which own tags through their 0564 // cached templateASTs). 0565 // 0566 // -------- 0567 // 0568 // Lambda spec requires Lambda { ">" } to render "&gt". 0569 // 0570 // What should Lambda { "<{{>partial}}>" } render when partial 0571 // contains "<>"? "&lt;<>&gt;" ???? 0572 } 0573 } 0574 } 0575 0576 0577 /** 0578 Builds a `RenderFunction` which conforms to the "lambda" defined by the 0579 Mustache specification (see https://github.com/mustache/spec/blob/v1.1.2/specs/%7Elambdas.yml). 0580 0581 The `lambda` parameter is a function without any argument that returns a String. 0582 The returned `RenderFunction` renders this string against the default `{{` and 0583 `}}` delimiters. 0584 0585 For example: 0586 0587 let template = try! Template(string: "{{fullName}} has a Mustache.") 0588 0589 let fullName = Lambda { "{{firstName}} {{lastName}}" } 0590 let data = [ 0591 "firstName": Box("Lionel"), 0592 "lastName": Box("Richie"), 0593 "fullName": Box(fullName)] 0594 0595 // Renders "Lionel Richie has a Mustache." 0596 let rendering = try! template.render(Box(data)) 0597 0598 **Warning**: the returned String is *parsed* each time the lambda is executed. 0599 In the example above, this is inefficient because the same 0600 `"{{firstName}} {{lastName}}"` would be parsed several times. You may prefer 0601 using a Template instead of a lambda (see the documentation of 0602 `Template.mustacheBox` for more information): 0603 0604 let fullName = try! Template(string:"{{firstName}} {{lastName}}") 0605 let data = [ 0606 "firstName": Box("Lionel"), 0607 "lastName": Box("Richie"), 0608 "fullName": Box(fullName)] 0609 0610 // Renders "Lionel Richie has a Mustache." 0611 let rendering = try! template.render(Box(data)) 0612 0613 - parameter lambda: A `() -> String` function. 0614 - returns: A RenderFunction. 0615 */ 0616 public func Lambda
CoreFunctions.swift:688
            let context = info.context.extendedContext(Box(render: Lambda(lambda)))
(lambda: () -> String) -> RenderFunction { 0617 return { (info: RenderingInfo) in 0618 switch info.tag.type { 0619 case .Variable: 0620 // {{ lambda }} 0621 // 0622 // https://github.com/mustache/spec/blob/83b0721610a4e11832e83df19c73ace3289972b9/specs/%7Elambdas.yml#L73 0623 // > Lambda results should be appropriately escaped 0624 // 0625 // Let's render a text template: 0626 0627 let templateRepository = TemplateRepository() 0628 templateRepository.configuration.contentType = .Text 0629 0630 let templateString = lambda() 0631 let template = try templateRepository.template(string: templateString) 0632 return try template.render(info.context) 0633 0634 // IMPLEMENTATION NOTE 0635 // 0636 // This lambda implementation is unable to process partial tags 0637 // correctly: it uses a TemplateRepository that does not know how 0638 // to load partials. 0639 // 0640 // This problem is a tricky one to solve. The `{{>partial}}` tag 0641 // loads the "partial" template which is sibling of the currently 0642 // rendered template. 0643 // 0644 // Imagine the following template hierarchy: 0645 // 0646 // - /a.mustache: {{lambda}}...{{>dir/b}} 0647 // - /x.mustache: ... 0648 // - /dir/b.mustache: {{lambda}} 0649 // - /dir/x.mustache: ... 0650 // 0651 // If the lambda returns `{{>x}}` then rendering the `a.mustache` 0652 // template should trigger the inclusion of both `/x.mustache` and 0653 // `/dir/x.mustache`. 0654 // 0655 // Given the current state of GRMustache types, achieving this 0656 // feature would require: 0657 // 0658 // - a template repository 0659 // - a TemplateID 0660 // - a method `TemplateRepository.template(string:contentType:tagDelimiterPair:baseTemplateID:)` 0661 // 0662 // Code would read something like: 0663 // 0664 // let templateString = lambda(info.tag.innerTemplateString) 0665 // let templateRepository = info.tag.templateRepository 0666 // let templateID = info.tag.templateID 0667 // let template = try templateRepository.template( 0668 // string: templateString, 0669 // contentType: .Text, 0670 // tagDelimiterPair: ("{{", "}}), 0671 // baseTemplateID: templateID) 0672 // return try template.render(info.context) 0673 // 0674 // Should we ever implement this, beware the retain cycle between 0675 // tags and template repositories (which own tags through their 0676 // cached templateASTs). 0677 // 0678 // -------- 0679 // 0680 // Lambda spec requires Lambda { ">" } to render "&gt". 0681 // 0682 // What should Lambda { "<{{>partial}}>" } render when partial 0683 // contains "<>"? "&lt;<>&gt;" ???? 0684 case .Section: 0685 // {{# lambda }}...{{/ lambda }} 0686 // 0687 // Behave as a true object, and render the section. 0688 let context = info.context.extendedContext(Box(render: Lambda(lambda))) 0689 return try info.tag.render(context) 0690 } 0691 } 0692 } 0693 0694 0695 /** 0696 `Rendering` is a type that wraps a rendered String, and its content type (HTML 0697 or Text). 0698 0699 See `RenderFunction` and `FilterFunction` for more information. 0700 */ 0701 public struct Rendering
HTMLEscapeHelper.swift:40
    private func filter(rendering: Rendering) throws -> Rendering {
HTMLEscapeHelper.swift:40
    private func filter(rendering: Rendering) throws -> Rendering {
HTMLEscapeHelper.swift:41
        return Rendering(escapeHTML(rendering.string), rendering.contentType)
HTMLEscapeHelper.swift:55
            return Box(render: { (info: RenderingInfo) -> Rendering in
JavascriptEscapeHelper.swift:40
    private func filter(rendering: Rendering) throws -> Rendering {
JavascriptEscapeHelper.swift:40
    private func filter(rendering: Rendering) throws -> Rendering {
JavascriptEscapeHelper.swift:41
        return Rendering(JavascriptEscapeHelper.escapeJavascript(rendering.string), rendering.contentType)
JavascriptEscapeHelper.swift:54
            return Box(render: { (info: RenderingInfo) -> Rendering in
ZipFilter.swift:76
        let renderFunction: RenderFunction = { (info) -> Rendering in
Box.swift:182
                    return Rendering("\(self ? 1 : 0)") // Behave like [NSNumber numberWithBool:]
Box.swift:239
                    return Rendering("\(self)")
Box.swift:296
                    return Rendering("\(self)")
Box.swift:353
                    return Rendering("\(self)")
Box.swift:824
    private func renderItems(info: RenderingInfo, @noescape box: (Generator.Element) -> MustacheBox) throws -> Rendering {
Box.swift:873
            return Rendering(buffer, contentType)
CoreFunctions.swift:264
public func Filter(filter: (Rendering) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:264
public func Filter(filter: (Rendering) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:295
public func Filter(filter: (MustacheBox, RenderingInfo) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:342
public func Filter<T>(filter: (T?, RenderingInfo) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:454
public typealias RenderFunction = (info: RenderingInfo) throws -> Rendering
CoreFunctions.swift:504
            return Rendering("(Lambda)")
CoreFunctions.swift:726
extension Rendering : CustomDebugStringConvertible {
MustacheBox.swift:472
            self.render = { (_) in return Rendering("") }
MustacheBox.swift:483
                        return Rendering("\(value)", .Text)
MustacheBox.swift:485
                        return Rendering("", .Text)
RenderingEngine.swift:31
    func render() throws -> Rendering {
RenderingEngine.swift:34
        return Rendering(buffer, templateAST.contentType)
RenderingEngine.swift:157
        let rendering: Rendering
RenderingEngine.swift:176
                    rendering = Rendering("")
Template.swift:80
    public func render(context: Context) throws -> Rendering {
SectionTag.swift:47
    func render(context: Context) throws -> Rendering {
Tag.swift:147
    func render(context: Context) throws -> Rendering
VariableTag.swift:46
    func render(context: Context) throws -> Rendering {
VariableTag.swift:47
        return Rendering("", contentType)
{ 0702 0703 /// The rendered string 0704 public let string
HTMLEscapeHelper.swift:41
        return Rendering(escapeHTML(rendering.string), rendering.contentType)
JavascriptEscapeHelper.swift:41
        return Rendering(JavascriptEscapeHelper.escapeJavascript(rendering.string), rendering.contentType)
Box.swift:852
                buffer += boxRendering.string
Box.swift:857
                buffer += boxRendering.string
CoreFunctions.swift:721
        self.string = string
CoreFunctions.swift:737
        return "Rendering(\(contentTypeString):\(string.debugDescription))"
RenderingEngine.swift:75
                buffer.appendContentsOf(escapeHTML(rendering.string))
RenderingEngine.swift:77
                buffer.appendContentsOf(rendering.string)
RenderingEngine.swift:192
            string = escapeHTML(rendering.string)
RenderingEngine.swift:194
            string = rendering.string
Template.swift:59
        return rendering.string
: String 0705 0706 /// The content type of the rendering 0707 public let contentType
HTMLEscapeHelper.swift:41
        return Rendering(escapeHTML(rendering.string), rendering.contentType)
JavascriptEscapeHelper.swift:41
        return Rendering(JavascriptEscapeHelper.escapeJavascript(rendering.string), rendering.contentType)
Box.swift:851
                contentType = boxRendering.contentType
Box.swift:854
            else if contentType == boxRendering.contentType
CoreFunctions.swift:722
        self.contentType = contentType
CoreFunctions.swift:730
        switch contentType {
RenderingEngine.swift:73
            switch (targetContentType, rendering.contentType) {
RenderingEngine.swift:190
        switch (templateAST.contentType!, rendering.contentType, escapesHTML) {
: ContentType 0708 0709 /** 0710 Builds a Rendering with a String and a ContentType. 0711 0712 Rendering("foo") // Defaults to Text 0713 Rendering("foo", .Text) 0714 Rendering("foo", .HTML) 0715 0716 - parameter string: A string. 0717 - parameter contentType: A content type. 0718 - returns: A Rendering. 0719 */ 0720 public init
HTMLEscapeHelper.swift:41
        return Rendering(escapeHTML(rendering.string), rendering.contentType)
JavascriptEscapeHelper.swift:41
        return Rendering(JavascriptEscapeHelper.escapeJavascript(rendering.string), rendering.contentType)
Box.swift:182
                    return Rendering("\(self ? 1 : 0)") // Behave like [NSNumber numberWithBool:]
Box.swift:239
                    return Rendering("\(self)")
Box.swift:296
                    return Rendering("\(self)")
Box.swift:353
                    return Rendering("\(self)")
Box.swift:873
            return Rendering(buffer, contentType)
CoreFunctions.swift:504
            return Rendering("(Lambda)")
MustacheBox.swift:472
            self.render = { (_) in return Rendering("") }
MustacheBox.swift:483
                        return Rendering("\(value)", .Text)
MustacheBox.swift:485
                        return Rendering("", .Text)
RenderingEngine.swift:34
        return Rendering(buffer, templateAST.contentType)
RenderingEngine.swift:176
                    rendering = Rendering("")
VariableTag.swift:47
        return Rendering("", contentType)
(_ string: String, _ contentType: ContentType = .Text) { 0721 self.string = string 0722 self.contentType = contentType 0723 } 0724 } 0725 0726 extension Rendering : CustomDebugStringConvertible { 0727 /// A textual representation of `self`, suitable for debugging. 0728 public var debugDescription: String { 0729 var contentTypeString: String 0730 switch contentType { 0731 case .HTML: 0732 contentTypeString = "HTML" 0733 case .Text: 0734 contentTypeString = "Text" 0735 } 0736 0737 return "Rendering(\(contentTypeString):\(string.debugDescription))" 0738 } 0739 } 0740 0741 0742 /** 0743 `RenderingInfo` provides information about a rendering. 0744 0745 See `RenderFunction` for more information. 0746 */ 0747 public struct RenderingInfo
HTMLEscapeHelper.swift:55
            return Box(render: { (info: RenderingInfo) -> Rendering in
JavascriptEscapeHelper.swift:54
            return Box(render: { (info: RenderingInfo) -> Rendering in
Box.swift:178
            render: { (info: RenderingInfo) in
Box.swift:235
            render: { (info: RenderingInfo) in
Box.swift:292
            render: { (info: RenderingInfo) in
Box.swift:349
            render: { (info: RenderingInfo) in
Box.swift:824
    private func renderItems(info: RenderingInfo, @noescape box: (Generator.Element) -> MustacheBox) throws -> Rendering {
Box.swift:935
            render: { (info: RenderingInfo) in
Box.swift:991
            render: { (info: RenderingInfo) in
CoreFunctions.swift:271
        return Box { (info: RenderingInfo) in
CoreFunctions.swift:295
public func Filter(filter: (MustacheBox, RenderingInfo) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:298
        return Box { (info: RenderingInfo) in
CoreFunctions.swift:342
public func Filter<T>(filter: (T?, RenderingInfo) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:345
        return Box { (info: RenderingInfo) in
CoreFunctions.swift:454
public typealias RenderFunction = (info: RenderingInfo) throws -> Rendering
CoreFunctions.swift:500
    return { (info: RenderingInfo) in
CoreFunctions.swift:617
    return { (info: RenderingInfo) in
MustacheBox.swift:474
            self.render = { [unowned self] (info: RenderingInfo) in
RenderingEngine.swift:161
                let info = RenderingInfo(tag: tag, context: context, enumerationItem: false)
RenderingEngine.swift:168
                    let info = RenderingInfo(tag: tag, context: context, enumerationItem: false)
{ 0748 0749 /// The currently rendered tag. 0750 public let tag
ZipFilter.swift:78
            return try info.tag.render(context)
Box.swift:179
                switch info.tag.type {
Box.swift:186
                        return try info.tag.render(info.context.extendedContext(Box(boolValue: self)))
Box.swift:195
                        return try info.tag.render(info.context)
Box.swift:236
                switch info.tag.type {
Box.swift:243
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:252
                        return try info.tag.render(info.context)
Box.swift:293
                switch info.tag.type {
Box.swift:300
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:309
                        return try info.tag.render(info.context)
Box.swift:350
                switch info.tag.type {
Box.swift:357
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:366
                        return try info.tag.render(info.context)
Box.swift:895
            return try info.tag.render(info.context)
Box.swift:938
                    return try info.tag.render(info.context.extendedContext(self.mustacheBoxWithSetValue(value, box: box)))
Box.swift:994
                    return try info.tag.render(info.context.extendedContext(self.mustacheBoxWithArrayValue(value, box: box)))
CoreFunctions.swift:501
        switch info.tag.type {
CoreFunctions.swift:512
            templateRepository.configuration.tagDelimiterPair = info.tag.tagDelimiterPair
CoreFunctions.swift:514
            let templateString = lambda(info.tag.innerTemplateString)
CoreFunctions.swift:618
        switch info.tag.type {
CoreFunctions.swift:689
            return try info.tag.render(context)
MustacheBox.swift:477
                switch info.tag.type {
MustacheBox.swift:494
                    return try info.tag.render(context)
Template.swift:264
                switch info.tag {
: Tag 0751 0752 /// The current context stack. 0753 public var context
EachFilter.swift:55
                info.context = info.context.extendedContext(Box(boxable: position))
EachFilter.swift:55
                info.context = info.context.extendedContext(Box(boxable: position))
EachFilter.swift:87
                info.context = info.context.extendedContext(Box(boxable: position))
EachFilter.swift:87
                info.context = info.context.extendedContext(Box(boxable: position))
ZipFilter.swift:77
            var context = zippedBoxes.reduce(info.context) { (context, box) in context.extendedContext(box) }
Box.swift:186
                        return try info.tag.render(info.context.extendedContext(Box(boolValue: self)))
Box.swift:195
                        return try info.tag.render(info.context)
Box.swift:243
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:252
                        return try info.tag.render(info.context)
Box.swift:300
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:309
                        return try info.tag.render(info.context)
Box.swift:357
                        return try info.tag.render(info.context.extendedContext(Box(value: self)))
Box.swift:366
                        return try info.tag.render(info.context)
Box.swift:895
            return try info.tag.render(info.context)
Box.swift:938
                    return try info.tag.render(info.context.extendedContext(self.mustacheBoxWithSetValue(value, box: box)))
Box.swift:994
                    return try info.tag.render(info.context.extendedContext(self.mustacheBoxWithArrayValue(value, box: box)))
CoreFunctions.swift:516
            return try template.render(info.context)
CoreFunctions.swift:632
            return try template.render(info.context)
CoreFunctions.swift:688
            let context = info.context.extendedContext(Box(render: Lambda(lambda)))
MustacheBox.swift:491
                    let context = info.context.extendedContext(self)
Template.swift:280
                        context: info.context)
Template.swift:288
                    return try self.render(info.context)
: Context 0754 0755 // If true, the rendering is part of an enumeration. Some values don't 0756 // render the same whenever they render as an enumeration item, or alone: 0757 // {{# values }}...{{/ values }} vs. {{# value }}...{{/ value }}. 0758 // 0759 // This is the case of Int, UInt, Double, Bool: they enter the context 0760 // stack when used in an iteration, and do not enter the context stack when 0761 // used as a boolean (see https://github.com/groue/GRMustache/issues/83). 0762 // 0763 // This is also the case of collections: they enter the context stack when 0764 // used as an item of a collection, and enumerate their items when used as 0765 // a collection. 0766 var enumerationItem
Box.swift:184
                    if info.enumerationItem {
Box.swift:241
                    if info.enumerationItem {
Box.swift:298
                    if info.enumerationItem {
Box.swift:355
                    if info.enumerationItem {
Box.swift:844
        info.enumerationItem = true
Box.swift:936
                if info.enumerationItem {
Box.swift:992
                if info.enumerationItem {
: Bool 0767 } 0768 0769 0770 // ============================================================================= 0771 // MARK: - WillRenderFunction 0772 0773 /** 0774 Once a `WillRenderFunction` has entered the context stack, it is called just 0775 before tags are about to render, and has the opportunity to replace the value 0776 they are about to render. 0777 0778 let logTags: WillRenderFunction = { (tag: Tag, box: MustacheBox) in 0779 print("\(tag) will render \(box.value!)") 0780 return box 0781 } 0782 0783 // By entering the base context of the template, the logTags function 0784 // will be notified of all tags. 0785 let template = try! Template(string: "{{# user }}{{ firstName }} {{ lastName }}{{/ user }}") 0786 template.extendBaseContext(Box(logTags)) 0787 0788 // Prints: 0789 // {{# user }} at line 1 will render { firstName = Errol; lastName = Flynn; } 0790 // {{ firstName }} at line 1 will render Errol 0791 // {{ lastName }} at line 1 will render Flynn 0792 let data = ["user": ["firstName": "Errol", "lastName": "Flynn"]] 0793 try! template.render(Box(data)) 0794 0795 `WillRenderFunction` don't have to enter the base context of a template to 0796 perform: they can enter the context stack just like any other value, by being 0797 attached to a section. In this case, they are only notified of tags inside that 0798 section. 0799 0800 let template = try! Template(string: "{{# user }}{{ firstName }} {{# spy }}{{ lastName }}{{/ spy }}{{/ user }}") 0801 0802 // Prints: 0803 // {{ lastName }} at line 1 will render Flynn 0804 let data = [ 0805 "user": Box(["firstName": "Errol", "lastName": "Flynn"]), 0806 "spy": Box(logTags) 0807 ] 0808 try! template.render(Box(data)) 0809 */ 0810 public typealias WillRenderFunction
Box.swift:1375
public func Box(willRender willRender: WillRenderFunction) -> MustacheBox {
Box.swift:1669
    willRender: WillRenderFunction? = nil,
Context.swift:222
    var willRenderStack: [WillRenderFunction] {
MustacheBox.swift:163
    public let willRender: WillRenderFunction?
MustacheBox.swift:419
        willRender: WillRenderFunction? = nil,
MustacheBox.swift:447
        willRender: WillRenderFunction? = nil,
= (tag: Tag, box: MustacheBox) -> MustacheBox 0811 0812 0813 // ============================================================================= 0814 // MARK: - DidRenderFunction 0815 0816 /** 0817 Once a DidRenderFunction has entered the context stack, it is called just 0818 after tags have been rendered. 0819 0820 let logRenderings: DidRenderFunction = { (tag: Tag, box: MustacheBox, string: String?) in 0821 println("\(tag) did render \(box.value!) as `\(string!)`") 0822 } 0823 0824 // By entering the base context of the template, the logRenderings function 0825 // will be notified of all tags. 0826 let template = try! Template(string: "{{# user }}{{ firstName }} {{ lastName }}{{/ user }}") 0827 template.extendBaseContext(Box(logRenderings)) 0828 0829 // Renders "Errol Flynn" 0830 // 0831 // Prints: 0832 // {{ firstName }} at line 1 did render Errol as `Errol` 0833 // {{ lastName }} at line 1 did render Flynn as `Flynn` 0834 // {{# user }} at line 1 did render { firstName = Errol; lastName = Flynn; } as `Errol Flynn` 0835 let data = ["user": ["firstName": "Errol", "lastName": "Flynn"]] 0836 try! template.render(Box(data)) 0837 0838 DidRender functions don't have to enter the base context of a template to 0839 perform: they can enter the context stack just like any other value, by being 0840 attached to a section. In this case, they are only notified of tags inside that 0841 section. 0842 0843 let template = try! Template(string: "{{# user }}{{ firstName }} {{# spy }}{{ lastName }}{{/ spy }}{{/ user }}") 0844 0845 // Renders "Errol Flynn" 0846 // 0847 // Prints: 0848 // {{ lastName }} at line 1 did render Flynn as `Flynn` 0849 let data = [ 0850 "user": Box(["firstName": "Errol", "lastName": "Flynn"]), 0851 "spy": Box(logRenderings) 0852 ] 0853 try! template.render(Box(data)) 0854 0855 The string argument of DidRenderFunction is optional: it is nil if and only if 0856 the tag could not render because of a rendering error. 0857 0858 See also: 0859 0860 - WillRenderFunction 0861 */ 0862 public typealias DidRenderFunction
Box.swift:1408
public func Box(didRender didRender: DidRenderFunction) -> MustacheBox {
Box.swift:1670
    didRender: DidRenderFunction? = nil) -> MustacheBox
Context.swift:237
    var didRenderStack: [DidRenderFunction] {
MustacheBox.swift:166
    public let didRender: DidRenderFunction?
MustacheBox.swift:420
        didRender: DidRenderFunction? = nil)
MustacheBox.swift:448
        didRender: DidRenderFunction? = nil)
= (tag: Tag, box: MustacheBox, string: String?) -> Void 0863 0864 0865