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    Mustache templates don't eat raw values: they eat values boxed in `MustacheBox`.
0025    
0026    To box something in a `MustacheBox`, you use one variant of the `Box()`
0027    function. It comes in several variants so that nearly anything can be boxed and
0028    feed templates:
0029    
0030    - Basic Swift values:
0031    
0032            template.render(Box("foo"))
0033    
0034    - Dictionaries & collections:
0035    
0036            template.render(Box(["numbers": [1,2,3]]))
0037    
0038    - Custom types via the `MustacheBoxable` protocol:
0039        
0040            extension User: MustacheBoxable { ... }
0041            template.render(Box(user))
0042    
0043    - Functions such as `FilterFunction`, `RenderFunction`, `WillRenderFunction` and
0044      `DidRenderFunction`:
0045    
0046            let square = Filter { (x: Int?) in Box(x! * x!) }
0047            template.registerInBaseContext("square", Box(square))
0048    
0049    **Warning**: the fact that `MustacheBox` is a subclass of NSObject is an
0050    implementation detail that is enforced by the Swift 2 language itself. This may
0051    change in the future: do not rely on it.
0052    */
0053    final public class MustacheBox
Configuration.swift:240
    public mutating func extendBaseContext(box: MustacheBox) {
Configuration.swift:287
    public mutating func registerInBaseContext(key: String, _ box: MustacheBox) {
EachFilter.swift:23
let EachFilter = Filter { (box: MustacheBox) -> MustacheBox in
EachFilter.swift:23
let EachFilter = Filter { (box: MustacheBox) -> MustacheBox in
EachFilter.swift:43
        let transformedBoxes = dictionary.enumerate().map { (index: Int, element: (key: String, box: MustacheBox)) -> MustacheBox in
EachFilter.swift:43
        let transformedBoxes = dictionary.enumerate().map { (index: Int, element: (key: String, box: MustacheBox)) -> MustacheBox in
EachFilter.swift:48
                var position: [String: MustacheBox] = [:]
EachFilter.swift:76
        let transformedBoxes = boxes.enumerate().map { (index: Int, box: MustacheBox) -> MustacheBox in
EachFilter.swift:76
        let transformedBoxes = boxes.enumerate().map { (index: Int, box: MustacheBox) -> MustacheBox in
EachFilter.swift:81
                var position: [String: MustacheBox] = [:]
HTMLEscapeHelper.swift:28
        return MustacheBox(
HTMLEscapeHelper.swift:25
    var mustacheBox: MustacheBox {
HTMLEscapeHelper.swift:49
    private func willRender(tag: Tag, box: MustacheBox) -> MustacheBox {
HTMLEscapeHelper.swift:49
    private func willRender(tag: Tag, box: MustacheBox) -> MustacheBox {
JavascriptEscapeHelper.swift:28
        return MustacheBox(
JavascriptEscapeHelper.swift:25
    var mustacheBox: MustacheBox {
JavascriptEscapeHelper.swift:49
    private func willRender(tag: Tag, box: MustacheBox) -> MustacheBox {
JavascriptEscapeHelper.swift:49
    private func willRender(tag: Tag, box: MustacheBox) -> MustacheBox {
Logger.swift:75
            return MustacheBox(
Logger.swift:74
        public var mustacheBox: MustacheBox {
ZipFilter.swift:30
    var zippedGenerators: [AnyGenerator<MustacheBox>] = []
ZipFilter.swift:57
        var zippedBoxes: [MustacheBox] = []
Box.swift:126
    var mustacheBox: MustacheBox { get }
Box.swift:136
extension MustacheBox {
Box.swift:142
    public var mustacheBox: MustacheBox {
Box.swift:175
        return MustacheBox(
Box.swift:174
    public var mustacheBox: MustacheBox {
Box.swift:232
        return MustacheBox(
Box.swift:231
    public var mustacheBox: MustacheBox {
Box.swift:289
        return MustacheBox(
Box.swift:288
    public var mustacheBox: MustacheBox {
Box.swift:346
        return MustacheBox(
Box.swift:345
    public var mustacheBox: MustacheBox {
Box.swift:414
        return MustacheBox(
Box.swift:413
    public var mustacheBox: MustacheBox {
Box.swift:480
    public var mustacheBox: MustacheBox {
Box.swift:500
    public var mustacheBox: MustacheBox {
Box.swift:573
        var dictionaryValue: [String: MustacheBox] = [:]
Box.swift:576
                if let v = value as? MustacheBox {
Box.swift:593
        return MustacheBox(
Box.swift:594
            converter: MustacheBox.Converter(dictionaryValue: dict),
Box.swift:572
    public var mustacheBox: MustacheBox {
Box.swift:610
public func Box(boxable boxable: MustacheBoxable?) -> MustacheBox {
Box.swift:738
private func BoxAnyObject(object: AnyObject?) -> MustacheBox {
Box.swift:824
    private func renderItems(info: RenderingInfo, @noescape box: (Generator.Element) -> MustacheBox) throws -> Rendering {
Box.swift:916
    private func mustacheBoxWithSetValue(value: Any?, box: (Generator.Element) -> MustacheBox) -> MustacheBox {
Box.swift:916
    private func mustacheBoxWithSetValue(value: Any?, box: (Generator.Element) -> MustacheBox) -> MustacheBox {
Box.swift:917
        return MustacheBox(
Box.swift:918
            converter: MustacheBox.Converter(arrayValue: self.map({ box($0) })),
Box.swift:966
    private func mustacheBoxWithArrayValue(value: Any?, box: (Generator.Element) -> MustacheBox) -> MustacheBox {
Box.swift:966
    private func mustacheBoxWithArrayValue(value: Any?, box: (Generator.Element) -> MustacheBox) -> MustacheBox {
Box.swift:967
        return MustacheBox(
Box.swift:968
            converter: MustacheBox.Converter(arrayValue: self.map({ box($0) })),
Box.swift:1047
public func Box<C: CollectionType where C.Generator.Element: MustacheBoxable, C.Index.Distance == Int>(set set: C?) -> MustacheBox {
Box.swift:1098
public func Box<C: CollectionType where C.Generator.Element: MustacheBoxable, C.Index: BidirectionalIndexType, C.Index.Distance == Int>(array array: C?) -> MustacheBox {
Box.swift:1149
public func Box<C: CollectionType, T where C.Generator.Element == Optional<T>, T: MustacheBoxable, C.Index: BidirectionalIndexType, C.Index.Distance == Int>(array array: C?) -> MustacheBox {
Box.swift:1210
public func Box<T: MustacheBoxable>(dictionary dictionary: [String: T]?) -> MustacheBox {
Box.swift:1212
        return MustacheBox(
Box.swift:1213
            converter: MustacheBox.Converter(
Box.swift:1214
                dictionaryValue: dictionary.reduce([String: MustacheBox](), combine: { (b, item: (key: String, value: T)) in
Box.swift:1276
public func Box<T: MustacheBoxable>(optionalDictionary dictionary: [String: T?]?) -> MustacheBox {
Box.swift:1278
        return MustacheBox(
Box.swift:1279
            converter: MustacheBox.Converter(
Box.swift:1280
                dictionaryValue: dictionary.reduce([String: MustacheBox](), combine: { (b, item: (key: String, value: T?)) in
Box.swift:1322
public func Box(filter filter: FilterFunction) -> MustacheBox {
Box.swift:1323
    return MustacheBox(filter: filter)
Box.swift:1343
public func Box(render render: RenderFunction) -> MustacheBox {
Box.swift:1344
    return MustacheBox(render: render)
Box.swift:1375
public func Box(willRender willRender: WillRenderFunction) -> MustacheBox {
Box.swift:1376
    return MustacheBox(willRender: willRender)
Box.swift:1408
public func Box(didRender didRender: DidRenderFunction) -> MustacheBox {
Box.swift:1409
    return MustacheBox(didRender: didRender)
Box.swift:1670
    didRender: DidRenderFunction? = nil) -> MustacheBox
Box.swift:1673
    return MustacheBox(
Context.swift:74
    public convenience init(_ box: MustacheBox) {
Context.swift:86
    public convenience init(registeredKey key: String, box: MustacheBox) {
Context.swift:102
    public func extendedContext(box: MustacheBox) -> Context {
Context.swift:115
    public func contextWithRegisteredKey(key: String, box: MustacheBox) -> Context {
Context.swift:128
    public var topBox: MustacheBox {
Context.swift:163
    public func mustacheBoxForKey(key: String) -> MustacheBox {
Context.swift:201
    public func mustacheBoxForExpression(string: String) throws -> MustacheBox {
Context.swift:215
        case Box(box: MustacheBox, parent: Context)
CoreFunctions.swift:71
public typealias KeyedSubscriptFunction = (key: String) -> MustacheBox
CoreFunctions.swift:117
public typealias FilterFunction = (box: MustacheBox, partialApplication: Bool) throws -> MustacheBox
CoreFunctions.swift:117
public typealias FilterFunction = (box: MustacheBox, partialApplication: Bool) throws -> MustacheBox
CoreFunctions.swift:144
public func Filter(filter: (MustacheBox) throws -> MustacheBox) -> FilterFunction {
CoreFunctions.swift:144
public func Filter(filter: (MustacheBox) throws -> MustacheBox) -> FilterFunction {
CoreFunctions.swift:145
    return { (box: MustacheBox, partialApplication: Bool) in
CoreFunctions.swift:178
public func Filter<T>(filter: (T?) throws -> MustacheBox) -> FilterFunction {
CoreFunctions.swift:179
    return { (box: MustacheBox, partialApplication: Bool) in
CoreFunctions.swift:210
public func VariadicFilter(filter: ([MustacheBox]) 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:219
    func partialFilter(filter: ([MustacheBox]) throws -> MustacheBox, arguments: [MustacheBox]) -> FilterFunction {
CoreFunctions.swift:219
    func partialFilter(filter: ([MustacheBox]) throws -> MustacheBox, arguments: [MustacheBox]) -> FilterFunction {
CoreFunctions.swift:220
        return { (nextArgument: MustacheBox, partialApplication: Bool) in
CoreFunctions.swift:265
    return { (box: MustacheBox, partialApplication: Bool) in
CoreFunctions.swift:295
public func Filter(filter: (MustacheBox, RenderingInfo) throws -> Rendering) -> FilterFunction {
CoreFunctions.swift:296
    return Filter { (box: MustacheBox) in
CoreFunctions.swift:810
public typealias WillRenderFunction = (tag: Tag, box: MustacheBox) -> MustacheBox
CoreFunctions.swift:810
public typealias WillRenderFunction = (tag: Tag, box: MustacheBox) -> MustacheBox
CoreFunctions.swift:862
public typealias DidRenderFunction = (tag: Tag, box: MustacheBox, string: String?) -> Void
ExpressionInvocation.swift:26
    func invokeWithContext(context: Context) throws -> MustacheBox {
ExpressionInvocation.swift:30
    private func evaluate(context context: Context, expression: Expression) throws -> MustacheBox {
MustacheBox.swift:127
    public var arrayValue: [MustacheBox]? {
MustacheBox.swift:135
    public var dictionaryValue: [String: MustacheBox]? {
MustacheBox.swift:148
    public func mustacheBoxForKey(key: String) -> MustacheBox {
MustacheBox.swift:505
        let arrayValue: (() -> [MustacheBox]?)
MustacheBox.swift:506
        let dictionaryValue: (() -> [String: MustacheBox]?)
MustacheBox.swift:509
            @autoclosure(escaping) arrayValue: () -> [MustacheBox]? = nil,
MustacheBox.swift:510
            @autoclosure(escaping) dictionaryValue: () -> [String: MustacheBox]? = nil)
MustacheBox.swift:518
extension MustacheBox {
MustacheBox.swift:532
extension MustacheBox {
RenderingEngine.swift:131
        var box: MustacheBox
Template.swift:57
    public func render(box: MustacheBox = Box()) throws -> String {
Template.swift:135
    public func extendBaseContext(box: MustacheBox) {
Template.swift:159
    public func registerInBaseContext(key: String, _ box: MustacheBox) {
Template.swift:261
        return MustacheBox(
Template.swift:260
    public var mustacheBox: MustacheBox {
{ 0054 0055 // IMPLEMENTATION NOTE 0056 // 0057 // Why is MustacheBox a subclass of NSObject, and not, say, a Swift struct? 0058 // 0059 // Swift does not allow a class extension to override a method that is 0060 // inherited from an extension to its superclass and incompatible with 0061 // Objective-C. 0062 // 0063 // If MustacheBox were a pure Swift type, this Swift limit would prevent 0064 // NSObject subclasses such as NSNull, NSNumber, etc. to override 0065 // MustacheBoxable.mustacheBox, and provide custom rendering behavior. 0066 // 0067 // For an example of this limitation, see example below: 0068 // 0069 // import Foundation 0070 // 0071 // // A type that is not compatible with Objective-C 0072 // struct MustacheBox { } 0073 // 0074 // // So far so good 0075 // extension NSObject { 0076 // var mustacheBox: MustacheBox { return MustacheBox() } 0077 // } 0078 // 0079 // // Error: declarations in extensions cannot override yet 0080 // extension NSNull { 0081 // override var mustacheBox: MustacheBox { return MustacheBox() } 0082 // } 0083 // 0084 // This problem does not apply to Objc-C compatible protocols: 0085 // 0086 // import Foundation 0087 // 0088 // // So far so good 0089 // extension NSObject { 0090 // var prop: String { return "NSObject" } 0091 // } 0092 // 0093 // // No error 0094 // extension NSNull { 0095 // override var prop: String { return "NSNull" } 0096 // } 0097 // 0098 // NSObject().prop // "NSObject" 0099 // NSNull().prop // "NSNull" 0100 // 0101 // In order to let the user easily override NSObject.mustacheBox, we had to 0102 // keep its return type compatible with Objective-C, that is to say make 0103 // MustacheBox a subclass of NSObject. 0104 0105 0106 // ------------------------------------------------------------------------- 0107 // MARK: - The boxed value 0108 0109 /// The boxed value. 0110 public let value
EachFilter.swift:96
    throw MustacheError(kind: .RenderError, message: "Non-enumerable argument in each filter: \(box.value)")
ZipFilter.swift:40
            throw MustacheError(kind: .RenderError, message: "Non-enumerable argument in zip filter: `\(box.value)`")
CoreFunctions.swift:184
        return try filter(box.value as? T)
MustacheBox.swift:452
        self.value = value
MustacheBox.swift:481
                    if let value = self.value {
MustacheBox.swift:560
        } else if let value = value {
MustacheBox.swift:573
        if value == nil && hasCustomRenderFunction {
: Any? 0111 0112 /// The only empty box is `Box()`. 0113 public let isEmpty
EachFilter.swift:26
    if box.isEmpty {
ZipFilter.swift:33
        if box.isEmpty {
Context.swift:166
            if !box.isEmpty {
Context.swift:176
            if innerBox.isEmpty {
ExpressionInvocation.swift:53
                if filterBox.isEmpty {
MustacheBox.swift:451
        self.isEmpty = empty
: Bool 0114 0115 /** 0116 The boolean value of the box. 0117 0118 It tells whether the Box should trigger or prevent the rendering of regular 0119 `{{#section}}...{{/}}` and inverted `{{^section}}...{{/}}`. 0120 */ 0121 public let boolValue
MustacheBox.swift:454
        self.boolValue = boolValue ?? !empty
RenderingEngine.swift:164
                switch (inverted, box.boolValue) {
: Bool 0122 0123 /** 0124 If the boxed value can be iterated (Swift collection, NSArray, NSSet, etc.), 0125 returns an array of `MustacheBox`. 0126 */ 0127 public var arrayValue
EachFilter.swift:74
    if let boxes = box.arrayValue {
ZipFilter.swift:35
        } else if let array = box.arrayValue {
MustacheBox.swift:548
        if let array = arrayValue {
: [MustacheBox]? { 0128 return converter?.arrayValue() 0129 } 0130 0131 /** 0132 If the boxed value is a dictionary (Swift dictionary, NSDictionary, etc.), 0133 returns a dictionary `[String: MustacheBox]`. 0134 */ 0135 public var dictionaryValue
EachFilter.swift:41
    if let dictionary = box.dictionaryValue {
MustacheBox.swift:551
        } else if let dictionary = dictionaryValue {
: [String: MustacheBox]? { 0136 return converter?.dictionaryValue() 0137 } 0138 0139 /** 0140 Extracts a key out of a box. 0141 0142 let box = Box(["firstName": "Arthur"]) 0143 box.mustacheBoxForKey("firstName").value // "Arthur" 0144 0145 - parameter key: A key. 0146 - returns: The MustacheBox for *key*. 0147 */ 0148 public func mustacheBoxForKey
Context.swift:175
            let innerBox = box.mustacheBoxForKey(key)
ExpressionInvocation.swift:45
            return try evaluate(context: context, expression: baseExpression).mustacheBoxForKey(identifier)
(key: String) -> MustacheBox { 0149 return keyedSubscript?(key: key) ?? Box() 0150 } 0151 0152 0153 // ------------------------------------------------------------------------- 0154 // MARK: - Other facets 0155 0156 /// See the documentation of `RenderFunction`. 0157 public private(set) var render
EachFilter.swift:56
                return try element.box.render(info: info)
EachFilter.swift:88
                return try box.render(info: info)
HTMLEscapeHelper.swift:56
                let rendering = try box.render(info: info)
JavascriptEscapeHelper.swift:55
                let rendering = try box.render(info: info)
Box.swift:847
            let boxRendering = try box(item).render(info: info)
CoreFunctions.swift:272
            let rendering = try box.render(info: info)
MustacheBox.swift:461
            self.render = render
MustacheBox.swift:472
            self.render = { (_) in return Rendering("") }
MustacheBox.swift:474
            self.render = { [unowned self] (info: RenderingInfo) in
RenderingEngine.swift:162
                rendering = try box.render(info: info)
RenderingEngine.swift:169
                    rendering = try box.render(info: info)
: RenderFunction 0158 0159 /// See the documentation of `FilterFunction`. 0160 public let filter
ExpressionInvocation.swift:52
            guard let filter = filterBox.filter else {
MustacheBox.swift:456
        self.filter = filter
MustacheBox.swift:564
        if let _ = filter {
: FilterFunction? 0161 0162 /// See the documentation of `WillRenderFunction`. 0163 public let willRender
Context.swift:227
            if let willRender = box.willRender {
MustacheBox.swift:457
        self.willRender = willRender
MustacheBox.swift:567
        if let _ = willRender {
: WillRenderFunction? 0164 0165 /// See the documentation of `DidRenderFunction`. 0166 public let didRender
Context.swift:242
            if let didRender = box.didRender {
MustacheBox.swift:458
        self.didRender = didRender
MustacheBox.swift:570
        if let _ = didRender {
: DidRenderFunction? 0167 0168 0169 // ------------------------------------------------------------------------- 0170 // MARK: - Multi-facetted Box Initialization 0171 0172 /** 0173 This is the most low-level initializer of MustacheBox. 0174 0175 It is suited for building "advanced" boxes. There are simpler versions of 0176 the `Box` function that may well better suit your need: you should check 0177 them. 0178 0179 This initializer can take up to seven parameters, all optional, that define 0180 how the box interacts with the Mustache engine: 0181 0182 - `value`: an optional boxed value 0183 - `boolValue`: an optional boolean value for the Box. 0184 - `keyedSubscript`: an optional KeyedSubscriptFunction 0185 - `filter`: an optional FilterFunction 0186 - `render`: an optional RenderFunction 0187 - `willRender`: an optional WillRenderFunction 0188 - `didRender`: an optional DidRenderFunction 0189 0190 0191 To illustrate the usage of all those parameters, let's look at how the 0192 `{{f(a)}}` tag is rendered. 0193 0194 First the `a` and `f` expressions are evaluated. The Mustache engine looks 0195 in the context stack for boxes whose *keyedSubscript* return non-empty boxes 0196 for the keys "a" and "f". Let's call them aBox and fBox. 0197 0198 Then the *filter* of the fBox is evaluated with aBox as an argument. It is 0199 likely that the result depends on the *value* of the aBox: it is the 0200 resultBox. 0201 0202 Then the Mustache engine is ready to render resultBox. It looks in the 0203 context stack for boxes whose *willRender* function is defined. Those 0204 willRender functions have the opportunity to process the resultBox, and 0205 eventually provide the box that will be actually rendered: the renderedBox. 0206 0207 The renderedBox has a *render* function: it is evaluated by the Mustache 0208 engine which appends its result to the final rendering. 0209 0210 Finally the Mustache engine looks in the context stack for boxes whose 0211 *didRender* function is defined, and call them. 0212 0213 0214 ### value 0215 0216 The optional `value` parameter gives the boxed value. The value is used when 0217 the box is rendered (unless you provide a custom RenderFunction). It is also 0218 returned by the `value` property of MustacheBox. 0219 0220 let aBox = MustacheBox(value: 1) 0221 0222 // Renders "1" 0223 let template = try! Template(string: "{{a}}") 0224 try! template.render(Box(["a": aBox])) 0225 0226 0227 ### boolValue 0228 0229 The optional `boolValue` parameter tells whether the Box should trigger or 0230 prevent the rendering of regular `{{#section}}...{{/}}` and inverted 0231 `{{^section}}...{{/}}` tags. The default boolValue is true, unless the 0232 Box is initialized without argument to build the empty box. 0233 0234 // Render "true", "false" 0235 let template = try! Template(string:"{{#.}}true{{/.}}{{^.}}false{{/.}}") 0236 try! template.render(MustacheBox(boolValue: true)) 0237 try! template.render(MustacheBox(boolValue: false)) 0238 0239 0240 ### keyedSubscript 0241 0242 The optional `keyedSubscript` parameter is a `KeyedSubscriptFunction` that 0243 lets the Mustache engine extract keys out of the box. For example, the 0244 `{{a}}` tag would call the subscript function with `"a"` as an argument, and 0245 render the returned box. 0246 0247 The default value is nil, which means that no key can be extracted. 0248 0249 See `KeyedSubscriptFunction` for a full discussion of this type. 0250 0251 let box = MustacheBox(keyedSubscript: { (key: String) in 0252 return Box("key:\(key)") 0253 }) 0254 0255 // Renders "key:a" 0256 let template = try! Template(string:"{{a}}") 0257 try! template.render(box) 0258 0259 0260 ### filter 0261 0262 The optional `filter` parameter is a `FilterFunction` that lets the Mustache 0263 engine evaluate filtered expression that involve the box. The default value 0264 is nil, which means that the box can not be used as a filter. 0265 0266 See `FilterFunction` for a full discussion of this type. 0267 0268 let box = MustacheBox(filter: Filter { (x: Int?) in 0269 return Box(x! * x!) 0270 }) 0271 0272 // Renders "100" 0273 let template = try! Template(string:"{{square(x)}}") 0274 try! template.render(Box(["square": box, "x": Box(10)])) 0275 0276 0277 ### render 0278 0279 The optional `render` parameter is a `RenderFunction` that is evaluated when 0280 the Box is rendered. 0281 0282 The default value is nil, which makes the box perform default Mustache 0283 rendering: 0284 0285 - `{{box}}` renders the built-in Swift String Interpolation of the value, 0286 HTML-escaped. 0287 0288 - `{{{box}}}` renders the built-in Swift String Interpolation of the value, 0289 not HTML-escaped. 0290 0291 - `{{#box}}...{{/box}}` does not render if `boolValue` is false. Otherwise, 0292 it pushes the box on the top of the context stack, and renders the section 0293 once. 0294 0295 - `{{^box}}...{{/box}}` renders once if `boolValue` is false. Otherwise, it 0296 does not render. 0297 0298 See `RenderFunction` for a full discussion of this type. 0299 0300 let box = MustacheBox(render: { (info: RenderingInfo) in 0301 return Rendering("foo") 0302 }) 0303 0304 // Renders "foo" 0305 let template = try! Template(string:"{{.}}") 0306 try! template.render(box) 0307 0308 0309 ### willRender, didRender 0310 0311 The optional `willRender` and `didRender` parameters are a 0312 `WillRenderFunction` and `DidRenderFunction` that are evaluated for all tags 0313 as long as the box is in the context stack. 0314 0315 See `WillRenderFunction` and `DidRenderFunction` for a full discussion of 0316 those types. 0317 0318 let box = MustacheBox(willRender: { (tag: Tag, box: MustacheBox) in 0319 return Box("baz") 0320 }) 0321 0322 // Renders "baz baz" 0323 let template = try! Template(string:"{{#.}}{{foo}} {{bar}}{{/.}}") 0324 try! template.render(box) 0325 0326 0327 ### Multi-facetted boxes 0328 0329 By mixing all those parameters, you can finely tune the behavior of a box. 0330 0331 GRMustache source code ships a few multi-facetted boxes, which may inspire 0332 you. See for example: 0333 0334 - NSFormatter.mustacheBox 0335 - HTMLEscape.mustacheBox 0336 - StandardLibrary.Localizer.mustacheBox 0337 0338 Let's give an example: 0339 0340 // A regular type: 0341 0342 struct Person { 0343 let firstName: String 0344 let lastName: String 0345 } 0346 0347 We want: 0348 0349 1. `{{person.firstName}}` and `{{person.lastName}}` should render the 0350 matching properties. 0351 2. `{{person}}` should render the concatenation of the first and last names. 0352 0353 We'll provide a `KeyedSubscriptFunction` to implement 1, and a 0354 `RenderFunction` to implement 2: 0355 0356 // Have Person conform to MustacheBoxable so that we can box people, and 0357 // render them: 0358 0359 extension Person : MustacheBoxable { 0360 0361 // MustacheBoxable protocol requires objects to implement this property 0362 // and return a MustacheBox: 0363 0364 var mustacheBox: MustacheBox { 0365 0366 // A person is a multi-facetted object: 0367 return MustacheBox( 0368 // It has a value: 0369 value: self, 0370 0371 // It lets Mustache extracts properties by name: 0372 keyedSubscript: { (key: String) -> MustacheBox in 0373 switch key { 0374 case "firstName": return Box(self.firstName) 0375 case "lastName": return Box(self.lastName) 0376 default: return Box() 0377 } 0378 }, 0379 0380 // It performs custom rendering: 0381 render: { (info: RenderingInfo) -> Rendering in 0382 switch info.tag.type { 0383 case .Variable: 0384 // {{ person }} 0385 return Rendering("\(self.firstName) \(self.lastName)") 0386 case .Section: 0387 // {{# person }}...{{/}} 0388 // 0389 // Perform the default rendering: push self on the top 0390 // of the context stack, and render the section: 0391 let context = info.context.extendedContext(Box(self)) 0392 return try info.tag.render(context) 0393 } 0394 } 0395 ) 0396 } 0397 } 0398 0399 // Renders "The person is Errol Flynn" 0400 let person = Person(firstName: "Errol", lastName: "Flynn") 0401 let template = try! Template(string: "{{# person }}The person is {{.}}{{/ person }}") 0402 try! template.render(Box(["person": person])) 0403 0404 - parameter value: An optional boxed value. 0405 - parameter boolValue: An optional boolean value for the Box. 0406 - parameter keyedSubscript: An optional `KeyedSubscriptFunction`. 0407 - parameter filter: An optional `FilterFunction`. 0408 - parameter render: An optional `RenderFunction`. 0409 - parameter willRender: An optional `WillRenderFunction`. 0410 - parameter didRender: An optional `DidRenderFunction`. 0411 - returns: A MustacheBox. 0412 */ 0413 public convenience init
HTMLEscapeHelper.swift:28
        return MustacheBox(
JavascriptEscapeHelper.swift:28
        return MustacheBox(
Logger.swift:75
            return MustacheBox(
Box.swift:175
        return MustacheBox(
Box.swift:232
        return MustacheBox(
Box.swift:289
        return MustacheBox(
Box.swift:346
        return MustacheBox(
Box.swift:414
        return MustacheBox(
Box.swift:1323
    return MustacheBox(filter: filter)
Box.swift:1344
    return MustacheBox(render: render)
Box.swift:1376
    return MustacheBox(willRender: willRender)
Box.swift:1409
    return MustacheBox(didRender: didRender)
Box.swift:1673
    return MustacheBox(
Template.swift:261
        return MustacheBox(
( 0414 value: Any? = nil, 0415 boolValue: Bool? = nil, 0416 keyedSubscript: KeyedSubscriptFunction? = nil, 0417 filter: FilterFunction? = nil, 0418 render: RenderFunction? = nil, 0419 willRender: WillRenderFunction? = nil, 0420 didRender: DidRenderFunction? = nil) 0421 { 0422 self.init( 0423 converter: nil, 0424 value: value, 0425 boolValue: boolValue, 0426 keyedSubscript: keyedSubscript, 0427 filter: filter, 0428 render: render, 0429 willRender: willRender, 0430 didRender: didRender) 0431 } 0432 0433 0434 // ------------------------------------------------------------------------- 0435 // MARK: - Internal 0436 0437 let keyedSubscript
MustacheBox.swift:149
        return keyedSubscript?(key: key) ?? Box()
MustacheBox.swift:455
        self.keyedSubscript = keyedSubscript
: KeyedSubscriptFunction? 0438 let converter
MustacheBox.swift:128
        return converter?.arrayValue()
MustacheBox.swift:136
        return converter?.dictionaryValue()
MustacheBox.swift:453
        self.converter = converter
: Converter? 0439 0440 init
Box.swift:593
        return MustacheBox(
Box.swift:917
        return MustacheBox(
Box.swift:967
        return MustacheBox(
Box.swift:1212
        return MustacheBox(
Box.swift:1278
        return MustacheBox(
MustacheBox.swift:422
        self.init(
( 0441 converter: Converter?, 0442 value: Any? = nil, 0443 boolValue: Bool? = nil, 0444 keyedSubscript: KeyedSubscriptFunction? = nil, 0445 filter: FilterFunction? = nil, 0446 render: RenderFunction? = nil, 0447 willRender: WillRenderFunction? = nil, 0448 didRender: DidRenderFunction? = nil) 0449 { 0450 let empty = (value == nil) && (keyedSubscript == nil) && (render == nil) && (filter == nil) && (willRender == nil) && (didRender == nil) 0451 self.isEmpty = empty 0452 self.value = value 0453 self.converter = converter 0454 self.boolValue = boolValue ?? !empty 0455 self.keyedSubscript = keyedSubscript 0456 self.filter = filter 0457 self.willRender = willRender 0458 self.didRender = didRender 0459 if let render = render { 0460 self.hasCustomRenderFunction = true 0461 self.render = render 0462 } else { 0463 // The default render function: it renders {{variable}} tags as the 0464 // boxed value, and {{#section}}...{{/}} tags by adding the box to 0465 // the context stack. 0466 // 0467 // IMPLEMENTATIN NOTE 0468 // 0469 // We have to set self.render twice in order to avoid the compiler 0470 // error: "variable 'self.render' captured by a closure before being 0471 // initialized" 0472 self.render = { (_) in return Rendering("") } 0473 self.hasCustomRenderFunction = false 0474 self.render = { [unowned self] (info: RenderingInfo) in 0475 0476 // Default rendering depends on the tag type: 0477 switch info.tag.type { 0478 case .Variable: 0479 // {{ box }} and {{{ box }}} 0480 0481 if let value = self.value { 0482 // Use the built-in Swift String Interpolation: 0483 return Rendering("\(value)", .Text) 0484 } else { 0485 return Rendering("", .Text) 0486 } 0487 case .Section: 0488 // {{# box }}...{{/ box }} 0489 0490 // Push the value on the top of the context stack: 0491 let context = info.context.extendedContext(self) 0492 0493 // Renders the inner content of the section tag: 0494 return try info.tag.render(context) 0495 } 0496 } 0497 } 0498 } 0499 0500 private let hasCustomRenderFunction
MustacheBox.swift:460
            self.hasCustomRenderFunction = true
MustacheBox.swift:473
            self.hasCustomRenderFunction = false
MustacheBox.swift:573
        if value == nil && hasCustomRenderFunction {
: Bool 0501 0502 // Converter wraps all the conversion closures that help MustacheBox expose 0503 // its raw value (typed Any) as useful types. 0504 struct Converter
Box.swift:594
            converter: MustacheBox.Converter(dictionaryValue: dict),
Box.swift:918
            converter: MustacheBox.Converter(arrayValue: self.map({ box($0) })),
Box.swift:968
            converter: MustacheBox.Converter(arrayValue: self.map({ box($0) })),
Box.swift:1213
            converter: MustacheBox.Converter(
Box.swift:1279
            converter: MustacheBox.Converter(
MustacheBox.swift:438
    let converter: Converter?
MustacheBox.swift:441
        converter: Converter?,
{ 0505 let arrayValue
MustacheBox.swift:128
        return converter?.arrayValue()
MustacheBox.swift:512
            self.arrayValue = arrayValue
: (() -> [MustacheBox]?) 0506 let dictionaryValue
MustacheBox.swift:136
        return converter?.dictionaryValue()
MustacheBox.swift:513
            self.dictionaryValue = dictionaryValue
: (() -> [String: MustacheBox]?) 0507 0508 init
Box.swift:594
            converter: MustacheBox.Converter(dictionaryValue: dict),
Box.swift:918
            converter: MustacheBox.Converter(arrayValue: self.map({ box($0) })),
Box.swift:968
            converter: MustacheBox.Converter(arrayValue: self.map({ box($0) })),
Box.swift:1213
            converter: MustacheBox.Converter(
Box.swift:1279
            converter: MustacheBox.Converter(
( 0509 @autoclosure(escaping) arrayValue: () -> [MustacheBox]? = nil, 0510 @autoclosure(escaping) dictionaryValue: () -> [String: MustacheBox]? = nil) 0511 { 0512 self.arrayValue = arrayValue 0513 self.dictionaryValue = dictionaryValue 0514 } 0515 } 0516 } 0517 0518 extension MustacheBox { 0519 /// A textual representation of `self`. 0520 public var description: String { 0521 let facets = self.facetsDescriptions 0522 switch facets.count { 0523 case 0: 0524 return "MustacheBox(Empty)" 0525 default: 0526 let content = facets.joinWithSeparator(",") 0527 return "MustacheBox(\(content))" 0528 } 0529 } 0530 } 0531 0532 extension MustacheBox { 0533 /// A textual representation of the boxed value. Useful for debugging. 0534 public var valueDescription
Logger.swift:78
                        self.log("\(self.indentationPrefix)\(tag) will render \(box.valueDescription)")
Logger.swift:88
                        self.log("\(self.indentationPrefix)\(tag) did render \(box.valueDescription) as \(string.debugDescription)")
MustacheBox.swift:549
            let items = array.map { $0.valueDescription }.joinWithSeparator(",")
MustacheBox.swift:556
                    return "\(key.debugDescription):\(box.valueDescription)"
: String { 0535 let facets = self.facetsDescriptions 0536 switch facets.count { 0537 case 0: 0538 return "Empty" 0539 case 1: 0540 return facets.first! 0541 default: 0542 return "(" + facets.joinWithSeparator(",") + ")" 0543 } 0544 } 0545 0546 var facetsDescriptions
MustacheBox.swift:521
        let facets = self.facetsDescriptions
MustacheBox.swift:535
        let facets = self.facetsDescriptions
: [String] { 0547 var facets = [String]() 0548 if let array = arrayValue { 0549 let items = array.map { $0.valueDescription }.joinWithSeparator(",") 0550 facets.append("[\(items)]") 0551 } else if let dictionary = dictionaryValue { 0552 if dictionary.isEmpty { 0553 facets.append("[:]") 0554 } else { 0555 let items = dictionary.map { (key, box) in 0556 return "\(key.debugDescription):\(box.valueDescription)" 0557 }.joinWithSeparator(",") 0558 facets.append("[\(items)]") 0559 } 0560 } else if let value = value { 0561 facets.append(String(reflecting: value)) 0562 } 0563 0564 if let _ = filter { 0565 facets.append("FilterFunction") 0566 } 0567 if let _ = willRender { 0568 facets.append("WillRenderFunction") 0569 } 0570 if let _ = didRender { 0571 facets.append("DidRenderFunction") 0572 } 0573 if value == nil && hasCustomRenderFunction { 0574 facets.append("RenderFunction") 0575 } 0576 0577 return facets 0578 } 0579 } 0580