Last active
April 7, 2016 16:44
-
-
Save bhargavg/d1d16d04d342d5804d8b2ee7337b840e to your computer and use it in GitHub Desktop.
Related blog post: http://bhargavg.com/swift/2016/04/07/handling-optionals-in-json.html
This file contains hidden or 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
[ | |
{ | |
"name": { | |
"first_name": "Lex", | |
"last_name": "Luthor" | |
}, | |
"age": 28, | |
"gender": "male", | |
"address": { | |
"city": "Edneyville", | |
"state": "Maine" | |
}, | |
"skills": [ | |
"laboris", | |
"id", | |
"consectetur", | |
"duis", | |
"incididunt", | |
"eiusmod" | |
] | |
}, | |
{ | |
"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": [ | |
"Lorem", | |
"do", | |
"commodo", | |
"occaecat" | |
] | |
}, | |
{ | |
"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": "Oklahoma" | |
}, | |
"skills": [ | |
"sunt", | |
"et", | |
"et", | |
"ullamco", | |
"est", | |
"ipsum", | |
"laborum" | |
] | |
} | |
] |
This file contains hidden or 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
import Foundation | |
func get<T>(box:[String: AnyObject], key: String) -> T? { | |
return box[key] as? T | |
} | |
func get<T>(item: AnyObject) -> T? { | |
return item as? T | |
} |
This file contains hidden or 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
_ _ | |
| |__ | |__ __ _ _ __ __ _ __ ___ ____ _ | |
| '_ \| '_ \ / _` | '__/ _` |/ _` \ \ / / _` | | |
| |_) | | | | (_| | | | (_| | (_| |\ V / (_| | | |
|_.__/|_| |_|\__,_|_| \__, |\__,_| \_/ \__, | | |
|___/ |___/ | |
Just a dummy text file to have a proper titles for gists 😒 |
This file contains hidden or 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
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) | |
} | |
func parseGender(gender: String) -> Gender { | |
switch gender { | |
case "male": | |
return .Male | |
case "female": | |
return .Female | |
default: | |
return .Unknown | |
} | |
} | |
func parseName(data: [String: AnyObject]) -> String? { | |
return ["first_name", "last_name"].map{ data[$0] as? String } | |
.flatMap{ $0 } | |
.joinWithSeparator(", ") | |
} | |
func parseAddress(data: [String: AnyObject]) -> Address? { | |
let x = makeAddress <?> get(data, key: "street") | |
<*> get(data, key: "city") | |
<*> get(data, key: "state") | |
return x | |
} | |
func parseCustomer(data: [String: AnyObject]) -> Customer? { | |
return makeCustomer <*> get(data, key: "name") <~~ parseName | |
<*> get(data, key: "age") | |
<*> get(data, key: "gender") <~~ parseGender | |
<?> get(data, key: "address") <~~ parseAddress | |
<*> get(data, key: "skills") | |
} | |
let customers: [Customer]? = get(jsonData) <<~ parseCustomer | |
if let customers = customers { | |
// There are totally 5 customers in JSON, | |
// but 2nd customer doesn't have name property | |
// making it invalid | |
// So, this will only parse 4 customers successfully | |
print("Parsed: \(customers.count) customers") | |
print(customers) | |
} else { | |
print("Failed to parse") | |
} |
This file contains hidden or 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
// Models | |
struct Customer { | |
let name: String // first_name, last_name | |
let age: Int | |
let gender: Gender | |
let address: Address? //Optional | |
let skills: [String] | |
} | |
enum Gender { | |
case Unknown, Male, Female | |
} | |
struct Address { | |
let street: String? | |
let city: String | |
let state: String | |
} | |
// Curries | |
func makeAddress(street: String?) -> (city: String) -> (state: String) -> Address { | |
return { city in { state in | |
return Address(street: street, city: city, state: state) | |
}} | |
} | |
func makeCustomer(name: String) -> (age: Int) -> (gender: Gender) -> (address: Address?) -> (skills: [String]) -> Customer { | |
return { age in { gender in { address in { skills in | |
return Customer(name: name, age: age, gender: gender, address: address, skills: skills) | |
}}}} | |
} |
This file contains hidden or 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
infix operator <*> { | |
associativity left | |
precedence 100 | |
} | |
infix operator <?> { | |
associativity left | |
precedence 100 | |
} | |
infix operator <~~ { | |
associativity left | |
precedence 110 | |
} | |
infix operator <<~ { | |
associativity left | |
precedence 110 | |
} | |
func <*><A, B>(f: (A -> B)?, x: A?) -> B? { | |
guard let f = f, x = x else { | |
return nil | |
} | |
return f(x) | |
} | |
func <?><A, B>(f: (A? -> B)?, x: A?) -> B? { | |
guard let f = f else { | |
return nil | |
} | |
return f(x) | |
} | |
func <~~<A, B>(x: A?, f: (A -> B?)) -> B? { | |
guard let x = x else { | |
return nil | |
} | |
return f(x) | |
} | |
func <<~<A, B>(x: [A]?, f: (A -> B?)) -> [B]? { | |
guard let x = x else { | |
return nil | |
} | |
return x.map(f).flatMap{ $0 } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment