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    let EachFilter
StandardLibrary.swift:173
    public static let each = EachFilter
= Filter { (box: MustacheBox) -> MustacheBox in 0024 0025 // {{# each(nothing) }}...{{/ }} 0026 if box.isEmpty { 0027 return box 0028 } 0029 0030 // {{# each(dictionary) }}...{{/ }} 0031 // 0032 // // Renders "firstName: Charles, lastName: Bronson." 0033 // let dictionary = ["firstName": "Charles", "lastName": "Bronson"] 0034 // let template = try! Template(string: "{{# each(dictionary) }}{{ @key }}: {{ . }}{{^ @last }}, {{/ @last }}{{/ each(dictionary) }}.") 0035 // template.registerInBaseContext("each", Box(StandardLibrary.each)) 0036 // try! template.render(Box(["dictionary": dictionary])) 0037 // 0038 // The dictionaryValue box property makes sure to return a 0039 // [String: MustacheBox] whatever the boxed dictionary-like value 0040 // (NSDictionary, [String: Int], [String: CustomObject], etc. 0041 if let dictionary = box.dictionaryValue { 0042 let count = dictionary.count 0043 let transformedBoxes = dictionary.enumerate().map { (index: Int, element: (key: String, box: MustacheBox)) -> MustacheBox in 0044 let customRenderFunction: RenderFunction = { info in 0045 var info = info 0046 // Push positional keys in the context stack and then perform 0047 // a regular rendering. 0048 var position: [String: MustacheBox] = [:] 0049 position["@index"] = Box(boxable: index) 0050 position["@indexPlusOne"] = Box(boxable: index + 1) 0051 position["@indexIsEven"] = Box(boxable: index % 2 == 0) 0052 position["@first"] = Box(boxable: index == 0) 0053 position["@last"] = Box(boxable: (index == count - 1)) 0054 position["@key"] = Box(boxable: element.key) 0055 info.context = info.context.extendedContext(Box(boxable: position)) 0056 return try element.box.render(info: info) 0057 } 0058 return Box(render: customRenderFunction) 0059 } 0060 return Box(boxable: transformedBoxes) 0061 } 0062 0063 0064 // {{# each(array) }}...{{/ }} 0065 // 0066 // // Renders "1: bread, 2: ham, 3: butter" 0067 // let array = ["bread", "ham", "butter"] 0068 // let template = try! Template(string: "{{# each(array) }}{{ @indexPlusOne }}: {{ . }}{{^ @last }}, {{/ @last }}{{/ each(array) }}.") 0069 // template.registerInBaseContext("each", Box(StandardLibrary.each)) 0070 // try! template.render(Box(["array": array])) 0071 // 0072 // The arrayValue box property makes sure to return a [MustacheBox] whatever 0073 // the boxed collection: NSArray, NSSet, [String], [CustomObject], etc. 0074 if let boxes = box.arrayValue { 0075 let count = boxes.count 0076 let transformedBoxes = boxes.enumerate().map { (index: Int, box: MustacheBox) -> MustacheBox in 0077 let customRenderFunction: RenderFunction = { info in 0078 var info = info 0079 // Push positional keys in the context stack and then perform 0080 // a regular rendering. 0081 var position: [String: MustacheBox] = [:] 0082 position["@index"] = Box(boxable: index) 0083 position["@indexPlusOne"] = Box(boxable: index + 1) 0084 position["@indexIsEven"] = Box(boxable: index % 2 == 0) 0085 position["@first"] = Box(boxable: index == 0) 0086 position["@last"] = Box(boxable: (index == count - 1)) 0087 info.context = info.context.extendedContext(Box(boxable: position)) 0088 return try box.render(info: info) 0089 } 0090 return Box(render: customRenderFunction) 0091 } 0092 return Box(boxable: transformedBoxes) 0093 } 0094 0095 // Non-iterable value 0096 throw MustacheError(kind: .RenderError, message: "Non-enumerable argument in each filter: \(box.value)") 0097 } 0098