Last active
October 7, 2015 18:44
-
-
Save jarsen/7a4f21a13fb1509df918 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MARK: - Keys | |
import Foundation | |
public protocol JSONKeyType { | |
var JSONKey: String { get } | |
} | |
extension String: JSONKeyType { | |
public var JSONKey: String { | |
return self | |
} | |
} | |
// MARK: - Values | |
public protocol JSONValueType { | |
static func JSONValue(object: Any) throws -> Self | |
} | |
extension JSONValueType { | |
public static func JSONValue(object: Any) throws -> Self { | |
if let object = object as? Self { | |
return object | |
} | |
throw JSONError.TypeMismatch | |
} | |
} | |
extension Int : JSONValueType { | |
} | |
extension String : JSONValueType { | |
} | |
// example of implementing your own JSONValueTypes | |
//extension NSDate : JSONValueType { | |
// public static func JSONValue(object: Any) throws -> NSDate { | |
// if let dateString = object as? String { | |
// return try NSDate.fromISO8601String(dateString) | |
// } | |
// throw JSONError.TypeMismatch | |
// } | |
//} | |
extension Array where Element : JSONValueType { | |
public static func JSONValue(object: Any) throws -> [Element] { | |
if let object = object as? [Element] { | |
return object | |
} | |
throw JSONError.TypeMismatch | |
} | |
} | |
extension Dictionary : JSONValueType { | |
public static func JSONValue(object: Any) throws -> Dictionary<Key, Value> { | |
if let object = object as? Dictionary<Key, Value> { | |
return object | |
} | |
throw JSONError.TypeMismatch | |
} | |
} | |
// MARK: - The Parsing | |
public enum JSONError: ErrorType { | |
case NoValueForKey(String) | |
case TypeMismatch | |
} | |
extension Dictionary where Key: JSONKeyType { | |
private func objectForKey(key: Key) throws -> Any { | |
let pathComponents = key.JSONKey.characters.split(".").map(String.init) | |
var accumulator: Any = self | |
for component in pathComponents { | |
if let componentData = accumulator as? [Key: Value] { | |
if let value = componentData[ component as! Key ] { | |
accumulator = value | |
continue | |
} | |
} | |
throw JSONError.NoValueForKey(key.JSONKey) | |
} | |
return accumulator | |
} | |
public func JSONValueForKey<A: JSONValueType>(key: Key) throws -> A { | |
let accumulator = try objectForKey(key) | |
return try A.JSONValue(accumulator) | |
} | |
public func JSONValueForKey<A: JSONValueType>(key: Key) throws -> [A] { | |
let accumulator = try objectForKey(key) | |
return try Array<A>.JSONValue(accumulator) | |
} | |
public func JSONOptionalForKey<A: JSONValueType>(key: Key) throws -> A? { | |
do { | |
return try self.JSONValueForKey(key) as A | |
} | |
catch JSONError.NoValueForKey { | |
return nil | |
} | |
catch { | |
throw JSONError.TypeMismatch | |
} | |
} | |
} | |
public typealias JSONObject = Dictionary<String, AnyObject> | |
// MARK: - Tests | |
var object: JSONObject = ["foo" : (2 as NSNumber), "str": "Hello, World!", "array" : [1,2,3,4,7], "object": ["foo" : (3 as NSNumber), "str": "Hello, World!"]] | |
do { | |
var str: String = try object.JSONValueForKey("str") | |
// var foo1: String = try object.JSONValueForKey("foo") | |
var foo2: Int = try object.JSONValueForKey("foo") | |
var foo3: Int? = try object.JSONOptionalForKey("foo") | |
var foo4: Int? = try object.JSONOptionalForKey("bar") | |
var arr: [Int] = try object.JSONValueForKey("array") | |
var obj: JSONObject = try object.JSONValueForKey("object") | |
let innerfoo: Int = try obj.JSONValueForKey("foo") | |
let innerfoo2: Int = try object.JSONValueForKey("object.foo") | |
} | |
catch JSONError.NoValueForKey { | |
print("no value for key") | |
} | |
catch JSONError.TypeMismatch { | |
print("Wrong value") | |
} | |
catch { | |
print("Unknown Error") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment