import Foundation | |
public class JSONObject { | |
public struct Error { | |
public enum Element: Equatable { | |
case Index(Int) | |
case Key(String) | |
} | |
public let keyPath: [Element] | |
public let expectedTypeName: String | |
public let actualTypeName: String | |
} | |
let underlyingValue: AnyObject? | |
public private(set) var errors = [Error]() | |
let keyPath: [Error.Element] | |
let parent: JSONObject? | |
public init(underlyingValue: AnyObject?, keyPath: [Error.Element], parent: JSONObject?) { | |
self.underlyingValue = underlyingValue | |
self.keyPath = keyPath | |
self.parent = parent | |
} | |
public convenience init(_ underlyingValue: AnyObject?) { | |
self.init(underlyingValue: underlyingValue, keyPath: [], parent: nil) | |
} | |
func get<T>(typename: String) -> T? { | |
if let typedValue = underlyingValue as? T { | |
return typedValue | |
} else { | |
let typeName = underlyingValue.map{ NSStringFromClass($0.classForCoder) } | |
let error = Error(keyPath: keyPath, expectedTypeName: typename, actualTypeName: typeName ?? "nil") | |
addError(error) | |
return nil | |
} | |
} | |
func addError(error: Error) { | |
errors.append(error) | |
parent?.addError(error) | |
} | |
public var string: String { | |
return get("string") ?? "" | |
} | |
public var double: Double { | |
return get("number") ?? 0.0 | |
} | |
public var dict: JSONDictionary { | |
if let dict: NSDictionary = get("dictionary") { | |
return JSONDictionary(parent: self, dict: dict) | |
} else { | |
return JSONDictionary(parent: nil, dict: [:]) | |
} | |
} | |
public var array: JSONArray { | |
if let array: NSArray = get("array") { | |
return JSONArray(parent: self, array: array) | |
} else { | |
return JSONArray(parent: nil, array: []) | |
} | |
} | |
} | |
public struct JSONDictionary { | |
let parent: JSONObject? | |
let dict: NSDictionary | |
public subscript(key: String) -> JSONObject { | |
let keyPath = (parent?.keyPath ?? []) + [.Key(key)] | |
return JSONObject(underlyingValue: dict[key], keyPath: keyPath, parent: parent) | |
} | |
} | |
public struct JSONArray { | |
let parent: JSONObject? | |
let array: NSArray | |
public subscript(key: Int) -> JSONObject { | |
let value: AnyObject? = key < array.count ? array[key] : nil | |
let keyPath = (parent?.keyPath ?? []) + [.Index(key)] | |
return JSONObject(underlyingValue: value, keyPath: keyPath, parent: parent) | |
} | |
public func map<T>(f: JSONObject -> T) -> [T] { | |
var results = [T]() | |
for i in 0 ..< array.count { | |
results.append(f(self[i])) | |
} | |
return results | |
} | |
} | |
public func ==(a: JSONObject.Error.Element, b: JSONObject.Error.Element) -> Bool { | |
switch (a, b) { | |
case let (.Index(aIndex), .Index(bIndex)): | |
return aIndex == bIndex | |
case let(.Key(aKey), .Key(bKey)): | |
return aKey == bKey | |
default: | |
return false | |
} | |
} | |
public func Decode<T>(json: AnyObject?, f: JSONObject -> T) -> (T?, [JSONObject.Error]?) { | |
let obj = JSONObject(json) | |
let result = f(obj) | |
if obj.errors.count == 0 { | |
return (result, nil) | |
} else { | |
return (nil, obj.errors) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment