Created
November 7, 2016 07:15
-
-
Save zeeshankhan/c619489413faf1ca3d84b4521aae4117 to your computer and use it in GitHub Desktop.
A simple demonstration of Result
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
import Foundation | |
import XCPlayground | |
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true | |
typealias JSONDictionary = [String: Any] | |
enum SomeError : Error { | |
case zoError | |
} | |
enum Result<T> { | |
case success(T) | |
case failure(Error) | |
} | |
extension Result { | |
func map<U>(f: (T) -> U) -> Result<U> { | |
switch self { | |
case .success(let t): | |
return .success(f(t)) | |
case .failure(let error): | |
return .failure(error) | |
} | |
} | |
func flatMap<U>(f: (T) -> Result<U>) -> Result<U> { | |
switch self { | |
case .success(let t): | |
return f(t) | |
case .failure(let error): | |
return .failure(error) | |
} | |
} | |
} | |
extension Result { | |
// Return the value if it is a .success or throw the error if it is a .failure | |
func resolve() throws -> T { | |
switch self { | |
case Result.success(let value): | |
return value | |
case Result.failure(let error): | |
throw error | |
} | |
} | |
// Construct a .success if the expression returns a value or a .failure if it throws | |
init( _ throwingExpression: (Void) throws -> T) { | |
do { | |
let value = try throwingExpression() | |
self = Result.success(value) | |
} | |
catch { | |
self = Result.failure(error) | |
} | |
} | |
} | |
struct Gist { | |
let id: String | |
} | |
func jsonFrom(data: Data) -> Result<Any> { | |
let json = try! JSONSerialization.jsonObject(with: data, options: []) | |
return .success(json as Any) | |
} | |
func gistFrom(json: JSONDictionary) -> Gist { | |
let id = json["id"] as! String | |
return Gist(id: id) | |
} | |
func gistsFrom(json: Any) -> Result<[Gist]> { | |
let gistsJSON = json as! [JSONDictionary] | |
let gists = gistsJSON.flatMap { | |
gistFrom(json: $0) | |
} | |
return .success(gists) | |
} | |
// May be we don't need no reason | |
// Can't stop. | |
func fetch(url: URL, completion: @escaping (Result<Data>) -> Void) { | |
URLSession.shared.dataTask(with: url) { (data, response, error) in | |
completion( Result { | |
if let error = error { throw error } | |
guard let data = data else { throw SomeError.zoError } | |
return data | |
}) | |
}.resume() | |
} | |
let url = URL(string: "https://api.github.com/gists/public")! | |
fetch(url: url) { (resultData: Result<Data>) in | |
let resultGists = resultData | |
.flatMap(f: jsonFrom) | |
.flatMap(f: gistsFrom) | |
// Then if we want to go back in the do/try/catch world for the rest of the code: | |
do { | |
let gists = try resultGists.resolve() | |
print(gists) | |
} catch { | |
print("error") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment