{ | |
"status": 200, | |
"response": { | |
"customers": [ | |
{ | |
"name": { | |
"first_name": "Lex", | |
"last_name": "Luthor" | |
}, | |
"age": 28, | |
"gender": "male", | |
"address": { | |
"street": "244 Clifton Place", | |
"city": "Edneyville", | |
"state": null | |
}, | |
"skills": null | |
}, | |
{ | |
"name": { | |
"first_name": "Ada", | |
"last_name": "Stuart" | |
}, | |
"age": 29, | |
"gender": "female", | |
"address": { | |
"street": "754 Marconi Place", | |
"city": "Rosburg", | |
"state": "Louisiana" | |
}, | |
"skills": [ | |
"laborum", | |
"et", | |
"proident", | |
"dolor", | |
"exercitation", | |
"nisi" | |
] | |
}, | |
{ | |
"name": { | |
"first_name": "Judith", | |
"last_name": "Roach" | |
}, | |
"age": 24, | |
"gender": "female", | |
"address": { | |
"street": "675 Reed Street", | |
"city": "Cochranville", | |
"state": "Pennsylvania" | |
}, | |
"skills": null | |
}, | |
{ | |
"name": { | |
"first_name": "Jana", | |
"last_name": "Decker" | |
}, | |
"age": 21, | |
"gender": "female", | |
"address": { | |
"street": "524 Bridge Street", | |
"city": "Gila", | |
"state": "New Hampshire" | |
}, | |
"skills": [ | |
"sit", | |
"irure", | |
"duis", | |
"sit" | |
] | |
}, | |
{ | |
"name": { | |
"first_name": "Lydia", | |
"last_name": "Maxwell" | |
}, | |
"age": 31, | |
"gender": "female", | |
"address": { | |
"street": "596 Folsom Place", | |
"city": "Galesville", | |
"state": null | |
}, | |
"skills": [ | |
"sunt", | |
"et", | |
"et", | |
"ullamco", | |
"est", | |
"ipsum", | |
"laborum" | |
] | |
} | |
] | |
} | |
} |
_ _ | |
| |__ | |__ __ _ _ __ __ _ __ ___ ____ _ | |
| '_ \| '_ \ / _` | '__/ _` |/ _` \ \ / / _` | | |
| |_) | | | | (_| | | | (_| | (_| |\ V / (_| | | |
|_.__/|_| |_|\__,_|_| \__, |\__,_| \_/ \__, | | |
|___/ |___/ | |
Just a dummy text file to have a proper titles for gists 😒 |
import Foundation | |
func get<T>(box: [String: AnyObject], key: String) throws -> T { | |
typealias ParseErrorType = ParseError<String, T.Type> | |
guard let value = box[key] else { | |
throw ParseErrorType.NilValue(key) | |
} | |
guard let typedValue = value as? T else { | |
throw ParseErrorType.InvalidType(key, expected: T.self) | |
} | |
return typedValue | |
} | |
func get<T>(item: AnyObject) throws -> T { | |
guard let typedItem = item as? T else { | |
throw ParseError.InvalidType(item, expected: T.self) | |
} | |
return typedItem | |
} | |
func keyPath<T>(path: String) -> (box: [String: AnyObject]) throws -> T { | |
typealias ParseErrorType = ParseError<String, T.Type> | |
return { box in | |
guard let value = (box as NSDictionary).valueForKeyPath(path) else { | |
throw ParseErrorType.NilValue(path) | |
} | |
guard let typedValue = value as? T else { | |
throw ParseErrorType.InvalidType(path, expected: T.self) | |
} | |
return typedValue | |
} | |
} |
import Foundation | |
guard let data = NSData(contentsOfFile: "customers.json"), | |
let jsonData = try? NSJSONSerialization.JSONObjectWithData(data, options: []) else { | |
print("Couldn't load JSON file") | |
exit(1) | |
} | |
do { | |
let customers: [Customer]? = try get(jsonData) <~~ keyPath("response.customers") <<~ Customer.init | |
print(customers) | |
} catch { | |
print(error) | |
} |
import Foundation | |
struct Customer { | |
let name: String // first_name, last_name | |
let age: Int | |
let gender: Gender | |
let address: Address | |
let skills: [String]? | |
init(json: JSON) throws { | |
name = try get(json, key: "name") <~~ Customer.parseName | |
age = try get(json, key: "age") | |
gender = try get(json, key: "gender") <~~ Gender.parseGender | |
address = try get(json, key: "address") <~~ Address.init | |
skills = try? get(json, key: "skills") | |
} | |
static func parseName(data: [String: AnyObject]) -> String { | |
return ["first_name", "last_name"].map{ data[$0] as? String } | |
.flatMap{ $0 } | |
.joinWithSeparator(", ") | |
} | |
} | |
enum Gender { | |
case Unknown, Male, Female | |
static func parseGender(gender: String) -> Gender { | |
switch gender { | |
case "male": | |
return .Male | |
case "female": | |
return .Female | |
default: | |
return .Unknown | |
} | |
} | |
} | |
struct Address { | |
let street: String | |
let city: String | |
let state: String? | |
init(json: JSON) throws { | |
street = try get(json, key: "street") | |
city = try get(json, key: "city") | |
state = try? get(json, key: "state") | |
} | |
} |
infix operator <~~ { | |
associativity left | |
precedence 110 | |
} | |
infix operator <<~ { | |
associativity left | |
precedence 110 | |
} | |
func <~~<A, B>(x: A, f: (A throws -> B)) throws -> B { | |
return try f(x) | |
} | |
func <<~<A, B>(x: [A], f: (A throws -> B)) throws -> [B] { | |
return try x.map(f) | |
} |
typealias JSON = [String: AnyObject] | |
enum ParseError<T, U>: ErrorType { | |
case InvalidType(T, expected: U) | |
case NilValue(T) | |
} | |
extension ParseError: CustomStringConvertible { | |
var description: String { | |
switch self { | |
case .InvalidType(let aThing, let expectedType): | |
return "\(aThing) is not of type: \(expectedType)" | |
case .NilValue(let key): | |
return "\(key) is nil" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment