Skip to content

Instantly share code, notes, and snippets.

@jarsen
Last active November 10, 2016 00:14
Show Gist options
  • Save jarsen/0f0919d3f43b2a2268e6 to your computer and use it in GitHub Desktop.
Save jarsen/0f0919d3f43b2a2268e6 to your computer and use it in GitHub Desktop.

Revisions

  1. jarsen revised this gist Dec 16, 2015. No changes.
  2. jarsen revised this gist Dec 16, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JaSON.swift
    Original file line number Diff line number Diff line change
    @@ -51,7 +51,7 @@ public protocol JSONValueType {
    extension JSONValueType {
    public static func JSONValue(object: Any) throws -> ValueType {
    guard let objectValue = object as? ValueType else {
    throw JSONError.TypeMismatch(expected: JSONValue.self, actual: object.dynamicType)
    throw JSONError.TypeMismatch(expected: ValueType.self, actual: object.dynamicType)
    }
    return objectValue
    }
  3. jarsen revised this gist Dec 16, 2015. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions JaSON.swift
    Original file line number Diff line number Diff line change
    @@ -136,6 +136,10 @@ extension Dictionary where Key: JSONKeyType {
    throw JSONError.KeyNotFound(key: key)
    }

    if let _ = accumulator as? NSNull {
    throw JSONError.NullValue(key: key)
    }

    return accumulator
    }

    @@ -145,10 +149,6 @@ extension Dictionary where Key: JSONKeyType {
    throw JSONError.TypeMismatchWithKey(key: key, expected: A.self, actual: any.dynamicType)
    }

    if let _ = result as? NSNull {
    throw JSONError.NullValue(key: key)
    }

    return result
    }

  4. jarsen revised this gist Oct 16, 2015. 1 changed file with 39 additions and 5 deletions.
    44 changes: 39 additions & 5 deletions JaSON.swift
    Original file line number Diff line number Diff line change
    @@ -43,14 +43,14 @@ extension String: JSONKeyType {
    //

    public protocol JSONValueType {
    typealias _JSONValue = Self
    typealias ValueType = Self

    static func JSONValue(object: Any) throws -> _JSONValue
    static func JSONValue(object: Any) throws -> ValueType
    }

    extension JSONValueType {
    public static func JSONValue(object: Any) throws -> _JSONValue {
    guard let objectValue = object as? _JSONValue else {
    public static func JSONValue(object: Any) throws -> ValueType {
    guard let objectValue = object as? ValueType else {
    throw JSONError.TypeMismatch(expected: JSONValue.self, actual: object.dynamicType)
    }
    return objectValue
    @@ -95,6 +95,27 @@ extension NSURL: JSONValueType {
    }
    }

    //
    // MARK: - JSONObjectConvertible
    //

    public protocol JSONObjectConvertible : JSONValueType {
    typealias ConvertibleType = Self
    init(json: JSONObject) throws
    }

    extension JSONObjectConvertible {
    public static func JSONValue(object: Any) throws -> ConvertibleType {
    guard let json = object as? JSONObject else {
    throw JSONError.TypeMismatch(expected: JSONObject.self, actual: object.dynamicType)
    }
    guard let value = try self.init(json: json) as? ConvertibleType else {
    throw JSONError.TypeMismatch(expected: ConvertibleType.self, actual: object.dynamicType)
    }
    return value
    }
    }

    //
    // MARK: - JSONObject
    //
    @@ -156,7 +177,17 @@ extension Dictionary where Key: JSONKeyType {
    // MARK: - Tests
    //

    var json: JSONObject = ["url": "http://apple.com", "foo": (2 as NSNumber), "str": "Hello, World!", "array": [1,2,3,4,7], "object": ["foo": (3 as NSNumber), "str": "Hello, World!"], "bool": (true as NSNumber)]
    struct User : JSONObjectConvertible {
    let name: String
    let email: String

    init(json: JSONObject) throws {
    name = try json.JSONValueForKey("name")
    email = try json.JSONValueForKey("email")
    }
    }

    var json: JSONObject = ["url": "http://apple.com", "foo": (2 as NSNumber), "str": "Hello, World!", "array": [1,2,3,4,7], "object": ["foo": (3 as NSNumber), "str": "Hello, World!"], "bool": (true as NSNumber), "urls": ["http://apple.com", "http://google.com"], "user": ["name": "Jason", "email": "[email protected]"], "users": [["name": "Jason", "email": "[email protected]"], ["name": "Bob", "email": "[email protected]"]]]
    do {
    var str: String = try json.JSONValueForKey("str")
    // var foo1: String = try json.JSONValueForKey("foo")
    @@ -169,6 +200,9 @@ do {
    let innerfoo2: Int = try json.JSONValueForKey("object.foo")
    let bool: Bool = try json.JSONValueForKey("bool")
    let url: NSURL = try json.JSONValueForKey("url")
    let urls: [NSURL] = try json.JSONValueForKey("urls")
    let user: User = try json.JSONValueForKey("user")
    let users: [User] = try json.JSONValueForKey("users")
    }
    catch {
    print("\(error)")
  5. jarsen revised this gist Oct 16, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions JaSON.swift
    Original file line number Diff line number Diff line change
    @@ -70,10 +70,10 @@ extension Bool: JSONValueType {}

    extension Array where Element: JSONValueType {
    public static func JSONValue(object: Any) throws -> [Element] {
    guard let objectValue = object as? [Element] else {
    guard let anyArray = object as? [AnyObject] else {
    throw JSONError.TypeMismatch(expected: self, actual: object.dynamicType)
    }
    return objectValue
    return try anyArray.map { try Element.JSONValue($0) as! Element }
    }
    }

  6. jarsen revised this gist Oct 15, 2015. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions JaSON.swift
    Original file line number Diff line number Diff line change
    @@ -136,7 +136,7 @@ extension Dictionary where Key: JSONKeyType {
    return try Array<A>.JSONValue(any)
    }

    public func JSONOptionalForKey<A: JSONValueType>(key: Key) throws -> A? {
    public func JSONValueForKey<A: JSONValueType>(key: Key) throws -> A? {
    do {
    return try self.JSONValueForKey(key) as A
    }
    @@ -161,11 +161,11 @@ do {
    var str: String = try json.JSONValueForKey("str")
    // var foo1: String = try json.JSONValueForKey("foo")
    var foo2: Int = try json.JSONValueForKey("foo")
    var foo3: Int? = try json.JSONOptionalForKey("foo")
    var foo4: Int? = try json.JSONOptionalForKey("bar")
    var foo3: Int? = try json.JSONValueForKey("foo")
    var foo4: Int? = try json.JSONValueForKey("bar")
    var arr: [Int] = try json.JSONValueForKey("array")
    var obj: JSONObject = try json.JSONValueForKey("object")
    let innerfoo: Int = try obj.JSONValueForKey("foo")
    var obj: JSONObject? = try json.JSONValueForKey("object")
    let innerfoo: Int = try obj!.JSONValueForKey("foo")
    let innerfoo2: Int = try json.JSONValueForKey("object.foo")
    let bool: Bool = try json.JSONValueForKey("bool")
    let url: NSURL = try json.JSONValueForKey("url")
  7. jarsen revised this gist Oct 15, 2015. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions JaSON.swift
    Original file line number Diff line number Diff line change
    @@ -86,9 +86,6 @@ extension Dictionary: JSONValueType {
    }
    }

    // MARK: -
    // MARK: JSONObject NSURL Support

    extension NSURL: JSONValueType {
    public static func JSONValue(object: Any) throws -> NSURL {
    guard let urlString = object as? String, objectValue = NSURL(string: urlString) else {
  8. jarsen created this gist Oct 15, 2015.
    178 changes: 178 additions & 0 deletions JaSON.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,178 @@
    import Foundation

    //
    // MARK: - JSONError Type
    //

    public enum JSONError: ErrorType, CustomStringConvertible {
    case KeyNotFound(key: JSONKeyType)
    case NullValue(key: JSONKeyType)
    case TypeMismatch(expected: Any, actual: Any)
    case TypeMismatchWithKey(key: JSONKeyType, expected: Any, actual: Any)

    public var description: String {
    switch self {
    case let .KeyNotFound(key):
    return "Key not found: \(key.stringValue)"
    case let .NullValue(key):
    return "Null Value found at: \(key.stringValue)"
    case let .TypeMismatch(expected, actual):
    return "Type mismatch. Expected type \(expected). Got '\(actual)'"
    case let .TypeMismatchWithKey(key, expected, actual):
    return "Type mismatch. Expected type \(expected) at key: \(key). Got '\(actual)'"
    }
    }
    }

    //
    // MARK: - JSONKeyType
    //

    public protocol JSONKeyType: Hashable {
    var stringValue: String { get }
    }

    extension String: JSONKeyType {
    public var stringValue: String {
    return self
    }
    }

    //
    // MARK: - JSONValueType
    //

    public protocol JSONValueType {
    typealias _JSONValue = Self

    static func JSONValue(object: Any) throws -> _JSONValue
    }

    extension JSONValueType {
    public static func JSONValue(object: Any) throws -> _JSONValue {
    guard let objectValue = object as? _JSONValue else {
    throw JSONError.TypeMismatch(expected: JSONValue.self, actual: object.dynamicType)
    }
    return objectValue
    }
    }

    //
    // MARK: - JSONValueType Implementations
    //

    extension String: JSONValueType {}
    extension Int: JSONValueType {}
    extension UInt: JSONValueType {}
    extension Float: JSONValueType {}
    extension Double: JSONValueType {}
    extension Bool: JSONValueType {}

    extension Array where Element: JSONValueType {
    public static func JSONValue(object: Any) throws -> [Element] {
    guard let objectValue = object as? [Element] else {
    throw JSONError.TypeMismatch(expected: self, actual: object.dynamicType)
    }
    return objectValue
    }
    }

    extension Dictionary: JSONValueType {
    public static func JSONValue(object: Any) throws -> [Key: Value] {
    guard let objectValue = object as? [Key: Value] else {
    throw JSONError.TypeMismatch(expected: self, actual: object.dynamicType)
    }
    return objectValue
    }
    }

    // MARK: -
    // MARK: JSONObject NSURL Support

    extension NSURL: JSONValueType {
    public static func JSONValue(object: Any) throws -> NSURL {
    guard let urlString = object as? String, objectValue = NSURL(string: urlString) else {
    throw JSONError.TypeMismatch(expected: self, actual: object.dynamicType)
    }
    return objectValue
    }
    }

    //
    // MARK: - JSONObject
    //

    public typealias JSONObject = [String: AnyObject]

    extension Dictionary where Key: JSONKeyType {
    private func anyForKey(key: Key) throws -> Any {
    let pathComponents = key.stringValue.characters.split(".").map(String.init)
    var accumulator: Any = self

    for component in pathComponents {
    if let componentData = accumulator as? [Key: Value], value = componentData[component as! Key] {
    accumulator = value
    continue
    }

    throw JSONError.KeyNotFound(key: key)
    }

    return accumulator
    }

    public func JSONValueForKey<A: JSONValueType>(key: Key) throws -> A {
    let any = try anyForKey(key)
    guard let result = try A.JSONValue(any) as? A else {
    throw JSONError.TypeMismatchWithKey(key: key, expected: A.self, actual: any.dynamicType)
    }

    if let _ = result as? NSNull {
    throw JSONError.NullValue(key: key)
    }

    return result
    }

    public func JSONValueForKey<A: JSONValueType>(key: Key) throws -> [A] {
    let any = try anyForKey(key)
    return try Array<A>.JSONValue(any)
    }

    public func JSONOptionalForKey<A: JSONValueType>(key: Key) throws -> A? {
    do {
    return try self.JSONValueForKey(key) as A
    }
    catch JSONError.KeyNotFound {
    return nil
    }
    catch JSONError.NullValue {
    return nil
    }
    catch {
    throw error
    }
    }
    }

    //
    // MARK: - Tests
    //

    var json: JSONObject = ["url": "http://apple.com", "foo": (2 as NSNumber), "str": "Hello, World!", "array": [1,2,3,4,7], "object": ["foo": (3 as NSNumber), "str": "Hello, World!"], "bool": (true as NSNumber)]
    do {
    var str: String = try json.JSONValueForKey("str")
    // var foo1: String = try json.JSONValueForKey("foo")
    var foo2: Int = try json.JSONValueForKey("foo")
    var foo3: Int? = try json.JSONOptionalForKey("foo")
    var foo4: Int? = try json.JSONOptionalForKey("bar")
    var arr: [Int] = try json.JSONValueForKey("array")
    var obj: JSONObject = try json.JSONValueForKey("object")
    let innerfoo: Int = try obj.JSONValueForKey("foo")
    let innerfoo2: Int = try json.JSONValueForKey("object.foo")
    let bool: Bool = try json.JSONValueForKey("bool")
    let url: NSURL = try json.JSONValueForKey("url")
    }
    catch {
    print("\(error)")
    }