diff --git a/Result/Result.swift b/Result/Result.swift index 72c7b5a..0f0ced0 100644 --- a/Result/Result.swift +++ b/Result/Result.swift @@ -201,4 +201,14 @@ public func >>- (result: Result, @noescape transform: T } +// MARK: - ErrorTypeConvertible conformance + +/// Make NSError conform to ErrorTypeConvertible +extension NSError: ErrorTypeConvertible { + public static func errorFromErrorType(error: ErrorType) -> NSError { + return error as NSError + } +} + + import Foundation diff --git a/Result/ResultType.swift b/Result/ResultType.swift index f445a32..c7ae4f9 100644 --- a/Result/ResultType.swift +++ b/Result/ResultType.swift @@ -64,6 +64,29 @@ public extension ResultType { } } +/// Protocol used to constrain `tryMap` to `Result`s with compatible `Error`s. +public protocol ErrorTypeConvertible: ErrorType { + typealias ConvertibleType = Self + static func errorFromErrorType(error: ErrorType) -> ConvertibleType +} + +public extension ResultType where Error: ErrorTypeConvertible { + + /// Returns the result of applying `transform` to `Success`es’ values, or wrapping thrown errors. + public func tryMap(@noescape transform: Value throws -> U) -> Result { + return flatMap { value in + do { + return .Success(try transform(value)) + } + catch { + let convertedError = Error.errorFromErrorType(error) as! Error + // Revisit this in a future version of Swift. https://twitter.com/jckarter/status/672931114944696321 + return .Failure(convertedError) + } + } + } +} + // MARK: - Operators infix operator &&& { diff --git a/ResultTests/ResultTests.swift b/ResultTests/ResultTests.swift index 2f574ed..c9bcf66 100644 --- a/ResultTests/ResultTests.swift +++ b/ResultTests/ResultTests.swift @@ -89,6 +89,16 @@ final class ResultTests: XCTestCase { XCTAssertNil(result.error) } + func testTryMapProducesSuccess() { + let result = success.tryMap(tryIsSuccess) + XCTAssert(result == success) + } + + func testTryMapProducesFailure() { + let result = Result.Success("fail").tryMap(tryIsSuccess) + XCTAssert(result == failure) + } + // MARK: Operators func testConjunctionOperator() { @@ -132,7 +142,7 @@ func attempt(value: T, succeed: Bool, error: NSErrorPointer) -> T? { } func tryIsSuccess(text: String?) throws -> String { - guard let text = text else { + guard let text = text where text == "success" else { throw error }