Last active
April 16, 2018 18:41
-
-
Save polac24/79da9649c68ee4cdc4ed5a7764c7eea3 to your computer and use it in GitHub Desktop.
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
public typealias HandleAction<T> = (T) throws -> () | |
public protocol ErrorHandleable: class { | |
func `throw`(_: Error, finally: @escaping (Bool) -> Void) | |
func `catch`(action: @escaping HandleAction<Error>) -> ErrorHandleable | |
} | |
public class ErrorHandler: ErrorHandleable { | |
private var parent: ErrorHandler? | |
private let action: HandleAction<Error> | |
convenience init(action: @escaping HandleAction<Error> = { throw $0 }) { | |
self.init(action: action, parent: nil) | |
} | |
private init(action: @escaping HandleAction<Error>, parent: ErrorHandler? = nil) { | |
self.action = action | |
self.parent = parent | |
} | |
public func `throw`(_ error: Error, finally: @escaping (Bool) -> Void) { | |
`throw`(error, previous: [], finally: finally) | |
} | |
private func `throw`(_ error: Error, previous: [ErrorHandler], finally: ((Bool) -> Void)? = nil) { | |
if let parent = parent { | |
parent.`throw`(error, previous: previous + [self], finally: finally) | |
return | |
} | |
serve(error, next: AnyCollection(previous.reversed()), finally: finally) | |
} | |
private func serve(_ error: Error, next: AnyCollection<ErrorHandler>, finally: ((Bool) -> Void)? = nil) { | |
do { | |
try action(error) | |
finally?(true) | |
} catch { | |
if let nextHandler = next.first { | |
nextHandler.serve(error, next: next.dropFirst(), finally: finally) | |
} else { | |
finally?(false) | |
} | |
} | |
} | |
public func `catch`(action: @escaping HandleAction<Error>) -> ErrorHandleable { | |
return ErrorHandler(action: action, parent: self) | |
} | |
} | |
// | |
// Protocol extensions for convenience API | |
public extension ErrorHandleable { | |
func `do`<A>(_ section: () throws -> A) { | |
do { | |
try section() | |
} catch { | |
`throw`(error) | |
} | |
} | |
} | |
public extension ErrorHandleable { | |
func `throw`(_ error: Error) { | |
`throw`(error, finally: { _ in }) | |
} | |
} | |
public extension ErrorHandleable { | |
func `catch`<K:Error>(_ type: K.Type, action: @escaping HandleAction<K>) -> ErrorHandleable { | |
return `catch`(action: { (e) in | |
if let k = e as? K { | |
try action(k) | |
} else { | |
throw e | |
} | |
}) | |
} | |
func `catch`<K:Error>(_ value: K, action: @escaping HandleAction<K>) -> ErrorHandleable where K: Equatable { | |
return `catch`(action: { (e) in | |
if let k = e as? K, k == value { | |
try action(k) | |
} else { | |
throw e | |
} | |
}) | |
} | |
} | |
public extension ErrorHandleable { | |
func listen(action: @escaping (Error) -> ()) -> ErrorHandleable { | |
return `catch`(action: { e in | |
action(e) | |
throw e | |
}) | |
} | |
func listen<K:Error>(_ type: K.Type, action: @escaping (K) -> ()) -> ErrorHandleable { | |
return `catch`(type, action: { e in | |
action(e) | |
throw e | |
}) | |
} | |
func listen<K:Error>(_ value: K, action: @escaping (K) -> ()) -> ErrorHandleable where K: Equatable { | |
return `catch`(value, action: { e in | |
action(e) | |
throw e | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment