Skip to content

Instantly share code, notes, and snippets.

@jarsen
Last active October 7, 2015 18:44
Show Gist options
  • Save jarsen/7a4f21a13fb1509df918 to your computer and use it in GitHub Desktop.
Save jarsen/7a4f21a13fb1509df918 to your computer and use it in GitHub Desktop.
// 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