Babel 0.8.1

Babel 0.8.1

测试已测试
语言语言 SwiftSwift
许可协议 MIT
发布上次发布2019年5月
SPM支持 SPM

Mathew Huusko V 维护。



Babel 0.8.1

Babel

Babel

JSON!纯 Swift,驱动失败的,推导的但清晰的,带有强大但可选的操作符。

是什么?

核心

Value – 表示 Swift ~原始值和/或那些值的字典/数组的递归结构。

JSON – 使用 JSON 数据(字符串或字节数组)初始化 Value

解码 – 简单地遍历 Value 树,并在过程中期望某些类型(或可转换为类型),具有明确的/抛出失败的case。

可选类型

Decodable – 描述可以从 Value 解码的类型方便的协议;Swift ~原始类型的 Decodable 扩展;扩展将 Value 的数组/字典解码为 Decodable 类型的数组/字典。

操作符 – 利用 解码Decodable 强大功能的简洁操作符。

Foundation – 为常见的 Foundation 类型提供 Decodable 扩展;使用 NSData 形式的 JSON 初始化 Value;非纯 Swift/依赖于 Foundation ;)。

辅助工具 - 一些方便的调试或在游乐场中玩耍的工具。

为什么(我们还没有42个这些东西)?

在强类型语言中处理JSON或其他字符串类型的数据,是一项既繁琐又常见的任务。人们往往愿意尝试直到感觉合适。我已经尝试过许多其他解决方案,有的喜欢,有的讨厌,我觉得把喜欢的属性聚集在一起放在一起是有价值的。典型吗?

话虽如此,我相信Babel可以超越其大多数被盗部分的总和。主要目标/目的是提出一个解决方案,在尊重数据模型语义的同时,解码字符串类型的数据。有时缺失的值可以接受,有时不行,有时空值(null)可以接受,有时不行。有时你有小数,但它实际上是以字符串的形式存储/传递的。有时你需要解析整个数组,有时可以忽略解码失败的项。这些类型的事情应该简单明了地描述,以便我们能回到好的编码中——无论那是什么。

最后,一个例子

首先,请在浏览完以下内容后玩玩 Xcode/Babel.playground(这部分是从这里切出来的)。在具有类型推理的语言的排版中能传达的内容是有限的……该死的Swift,你这么漂亮的伪代码外观真美!

import Babel

let jsonString = "<JSON HERE, SEE PLAYGROUND>"

let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!

let value: Value

switch dataExample {
case .String: value = try! Value(JSON: jsonString)
case .Data: value = try! Value(JSON: jsonData)
case .LiteralConvertible:
    value = [
        "apiVersion": "2.0",
        "data": [
            "items": [
                [
                    "title": "Google Developers Day US - Maps API Introduction",
                    "content": [
                        "5": "http://www.youtube.com/v/hYB0mn5zh2c?f...",
                        "6": "rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp",
                        "1": "rtsp://v5.cache3.c.youtube.com/CiILENy.../0/0/0/video.3gp"
                    ],
                    "favoriteCount": 201,
                    "rating": 4.63,
                    "uploaded": "2007-06-05T22:07:03.000Z"
                ],
                ....
            ],
            "totalItems": 800
        ]
    ]
case .NSObject:
    value = try! Value(NSObject: NSJSONSerialization.JSONObjectWithData(jsonData, options: .AllowFragments))
}
以下的所有解码示例在语义上是等价的(对于给定的数据模型,它们以相同的方式导航/解析/成功/失败)。你更喜欢哪个(你不一定喜欢自定义运算符)?
do {
    let content: [Int: NSURL]?
    
    switch decodingExample {
    case .Operators:
        content = try value =>? "data" => "items" =>?? 0 => "content"
        
    case .FunctionInferred:
        content = try value.maybeValueFor("data")?.valueFor("items")
                           .maybeValueAt(0, throwOnMissing: false)?.valueFor("content").decode()
        
    case .FunctionExplicit:
        content = try value.asDictionary()
                           .maybeValueFor("data", nilOnNull: true, throwOnMissing: true)?.asDictionary()
                           .valueFor("items").asArray()
                           .maybeValueAt(0, nilOnNull: true, throwOnMissing: false)?.asDictionary()
                           .valueFor("content").asDictionary()
                           .decode(keyType: Int.self, valueType: NSURL.self, ignoreFailures: false)
        
    case .UnwrappingAndChecking:
        var decodedContent: [Int: NSURL]?
        
        if let valueDictionary = value.dictionaryValue {
            if let data = valueDictionary["data"] {
                if data.isNull {
                    decodedContent = nil
                } else if let dataDictionary = data.dictionaryValue {
                    if let items = dataDictionary["items"] {
                        if let itemsArray = items.arrayValue {
                            if itemsArray.count > 0 && itemsArray[0].isDictionary {
                                let itemDictionary = itemsArray[0].dictionaryValue!

                                if let content = itemDictionary["content"] {
                                    if let contentDictionary = content.dictionaryValue {
                                        decodedContent = [:]
                                        
                                        for (key, value) in contentDictionary {
                                            if let key = Int(key) {
                                                if let string = value.stringValue, url = NSURL(string: string) {
                                                    decodedContent![key] = url
                                                } else { throw DecodingError.TypeMismatch(expectedType: NSURL.self, value: value) }
                                            } else { throw DecodingError.TypeMismatch(expectedType: Int.self, value: .String(key)) }
                                        }
                                    } else { throw DecodingError.TypeMismatch(expectedType: Dictionary<String, Value>.self, value: content) }
                                } else { throw DecodingError.MissingKey(key: "content", dictionary: itemDictionary) }
                            } else { decodedContent = nil }
                        } else { throw DecodingError.TypeMismatch(expectedType: Array<Value>.self, value: items) }
                    } else { throw DecodingError.MissingKey(key: "items", dictionary: dataDictionary) }
                } else { throw DecodingError.TypeMismatch(expectedType: Dictionary<String, Value>.self, value: data) }
            } else { throw DecodingError.MissingKey(key: "data", dictionary: valueDictionary) }
        } else { throw DecodingError.TypeMismatch(expectedType: Dictionary<String, Value>.self, value: value) }

        content = decodedContent
    }
    
    prettyPrint("Nested content: ", content)
} catch let error { prettyPrint("Nested content error: ", error) }