Skip to content

Commit 3dc5f34

Browse files
committed
Rename SignalProducer.Type.attempt to init(_:).
1 parent 180e917 commit 3dc5f34

File tree

3 files changed

+85
-70
lines changed

3 files changed

+85
-70
lines changed

Sources/Deprecations+Removals.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ import Dispatch
33
import Result
44

55
// MARK: Unavailable methods in ReactiveSwift 2.0.
6+
extension SignalProducerProtocol {
7+
@available(*, unavailable, renamed:"init(_:)")
8+
public static func attempt(_ operation: @escaping () -> Result<Value, Error>) -> SignalProducer<Value, Error> { fatalError() }
9+
}
10+
11+
extension SignalProducerProtocol where Error == AnyError {
12+
@available(*, unavailable, renamed:"init(_:)")
13+
public static func attempt(_ operation: @escaping () throws -> Value) -> SignalProducer<Value, Error> { fatalError() }
14+
}
15+
616
extension PropertyProtocol {
717
@available(*, unavailable, renamed:"flatMap(_:_:)")
818
public func flatMap<P: PropertyProtocol>(_ strategy: FlattenStrategy, transform: @escaping (Value) -> P) -> Property<P.Value> { fatalError() }

Sources/SignalProducer.swift

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,26 @@ public struct SignalProducer<Value, Error: Swift.Error> {
8282
}
8383
}
8484

85+
/// Create a `SignalProducer` that will attempt the given operation once for
86+
/// each invocation of `start()`.
87+
///
88+
/// Upon success, the started signal will send the resulting value then
89+
/// complete. Upon failure, the started signal will fail with the error that
90+
/// occurred.
91+
///
92+
/// - parameters:
93+
/// - action: A closure that returns instance of `Result`.
94+
public init(_ action: @escaping () -> Result<Value, Error>) {
95+
self.init { observer, disposable in
96+
action().analysis(ifSuccess: { value in
97+
observer.send(value: value)
98+
observer.sendCompleted()
99+
}, ifFailure: { error in
100+
observer.send(error: error)
101+
})
102+
}
103+
}
104+
85105
/// Creates a producer for a `Signal` that will immediately fail with the
86106
/// given error.
87107
///
@@ -183,6 +203,25 @@ public struct SignalProducer<Value, Error: Swift.Error> {
183203
}
184204
}
185205

206+
extension SignalProducer where Error == AnyError {
207+
/// Create a `SignalProducer` that will attempt the given failable operation once for
208+
/// each invocation of `start()`.
209+
///
210+
/// Upon success, the started producer will send the resulting value then
211+
/// complete. Upon failure, the started signal will fail with the error that
212+
/// occurred.
213+
///
214+
/// - parameters:
215+
/// - operation: A failable closure.
216+
public init(_ action: @escaping () throws -> Value) {
217+
self.init {
218+
return ReactiveSwift.materialize {
219+
return try action()
220+
}
221+
}
222+
}
223+
}
224+
186225
/// A protocol used to constraint `SignalProducer` operators.
187226
public protocol SignalProducerProtocol {
188227
/// The type of values being sent on the producer
@@ -1411,58 +1450,6 @@ extension SignalProducer where Error == NoError {
14111450
}
14121451
}
14131452

1414-
extension SignalProducer {
1415-
/// Create a `SignalProducer` that will attempt the given operation once for
1416-
/// each invocation of `start()`.
1417-
///
1418-
/// Upon success, the started signal will send the resulting value then
1419-
/// complete. Upon failure, the started signal will fail with the error that
1420-
/// occurred.
1421-
///
1422-
/// - parameters:
1423-
/// - operation: A closure that returns instance of `Result`.
1424-
///
1425-
/// - returns: A `SignalProducer` that will forward `success`ful `result` as
1426-
/// `value` event and then complete or `failed` event if `result`
1427-
/// is a `failure`.
1428-
public static func attempt(_ operation: @escaping () -> Result<Value, Error>) -> SignalProducer<Value, Error> {
1429-
return SignalProducer<Value, Error> { observer, disposable in
1430-
operation().analysis(ifSuccess: { value in
1431-
observer.send(value: value)
1432-
observer.sendCompleted()
1433-
}, ifFailure: { error in
1434-
observer.send(error: error)
1435-
})
1436-
}
1437-
}
1438-
}
1439-
1440-
// FIXME: SWIFT_COMPILER_ISSUE
1441-
//
1442-
// One of the `SignalProducer.attempt` overloads is kept in the protocol to
1443-
// mitigate an overloading issue. Moving them back to the concrete type would be
1444-
// a binary-breaking, source-compatible change.
1445-
1446-
extension SignalProducerProtocol where Error == AnyError {
1447-
/// Create a `SignalProducer` that, when start, would invoke a throwable action.
1448-
///
1449-
/// The produced `Signal` would forward the result and complete if the action
1450-
/// succeeds. Otherwise, the produced signal would propagate the thrown error and
1451-
/// terminate.
1452-
///
1453-
/// - parameters:
1454-
/// - action: A throwable closure which yields a value.
1455-
///
1456-
/// - returns: A producer that yields the result or the error of the given action.
1457-
public static func attempt(_ action: @escaping () throws -> Value) -> SignalProducer<Value, AnyError> {
1458-
return .attempt {
1459-
ReactiveSwift.materialize {
1460-
try action()
1461-
}
1462-
}
1463-
}
1464-
}
1465-
14661453
extension SignalProducer where Error == AnyError {
14671454
/// Apply a throwable action to every value from `self`, and forward the values
14681455
/// if the action succeeds. If the action throws an error, the produced `Signal`

Tests/ReactiveSwiftTests/SignalProducerSpec.swift

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,27 @@ class SignalProducerSpec: QuickSpec {
204204
}
205205
}
206206

207-
describe("init(_ block:)") {
207+
describe("init closure overloading") {
208+
it("should be inferred and overloaded without ambiguity") {
209+
let action: () -> String = { "" }
210+
let throwableAction: () throws -> String = { "" }
211+
let resultAction1: () -> Result<String, NoError> = { .success("") }
212+
let resultAction2: () -> Result<String, AnyError> = { .success("") }
213+
let throwableResultAction: () throws -> Result<String, NoError> = { .success("") }
214+
215+
expect(type(of: SignalProducer(action))) == SignalProducer<String, AnyError>.self
216+
expect(type(of: SignalProducer<String, NoError>(action))) == SignalProducer<String, NoError>.self
217+
expect(type(of: SignalProducer<String, TestError>(action))) == SignalProducer<String, TestError>.self
218+
219+
expect(type(of: SignalProducer(resultAction1))) == SignalProducer<String, NoError>.self
220+
expect(type(of: SignalProducer(resultAction2))) == SignalProducer<String, AnyError>.self
221+
222+
expect(type(of: SignalProducer(throwableAction))) == SignalProducer<String, AnyError>.self
223+
expect(type(of: SignalProducer(throwableResultAction))) == SignalProducer<Result<String, NoError>, AnyError>.self
224+
}
225+
}
226+
227+
describe("init(_:) lazy value") {
208228
it("should not evaluate the supplied closure until started") {
209229
var evaluated: Bool = false
210230
func lazyGetter() -> String {
@@ -287,7 +307,7 @@ class SignalProducerSpec: QuickSpec {
287307
}
288308
}
289309

290-
describe("SignalProducer.attempt") {
310+
describe("init(_:) lazy result") {
291311
it("should run the operation once per start()") {
292312
var operationRunTimes = 0
293313
let operation: () -> Result<String, NSError> = {
@@ -296,8 +316,8 @@ class SignalProducerSpec: QuickSpec {
296316
return .success("OperationValue")
297317
}
298318

299-
SignalProducer.attempt(operation).start()
300-
SignalProducer.attempt(operation).start()
319+
SignalProducer(operation).start()
320+
SignalProducer(operation).start()
301321

302322
expect(operationRunTimes) == 2
303323
}
@@ -308,7 +328,7 @@ class SignalProducerSpec: QuickSpec {
308328
return .success(operationReturnValue)
309329
}
310330

311-
let signalProducer = SignalProducer.attempt(operation)
331+
let signalProducer = SignalProducer(operation)
312332

313333
expect(signalProducer).to(sendValue(operationReturnValue, sendError: nil, complete: true))
314334
}
@@ -319,20 +339,19 @@ class SignalProducerSpec: QuickSpec {
319339
return .failure(operationError)
320340
}
321341

322-
let signalProducer = SignalProducer.attempt(operation)
342+
let signalProducer = SignalProducer(operation)
323343

324344
expect(signalProducer).to(sendValue(nil, sendError: operationError, complete: false))
325345
}
326346
}
327347

328-
describe("SignalProducer.attempt throws") {
348+
describe("init(_:) throwable lazy value") {
329349
it("should send a successful value then complete") {
330350
let operationReturnValue = "OperationValue"
331351

332-
let signalProducer = SignalProducer
333-
.attempt { () throws -> String in
334-
operationReturnValue
335-
}
352+
let signalProducer = SignalProducer { () throws -> String in
353+
operationReturnValue
354+
}
336355

337356
var error: Error?
338357
signalProducer.startWithFailed {
@@ -345,10 +364,9 @@ class SignalProducerSpec: QuickSpec {
345364
it("should send the error") {
346365
let operationError = TestError.default
347366

348-
let signalProducer = SignalProducer
349-
.attempt { () throws -> String in
350-
throw operationError
351-
}
367+
let signalProducer = SignalProducer { () throws -> String in
368+
throw operationError
369+
}
352370

353371
var error: TestError?
354372
signalProducer.startWithFailed {
@@ -2691,14 +2709,14 @@ class SignalProducerSpec: QuickSpec {
26912709
}
26922710
}
26932711

2712+
// MARK: - Helpers
2713+
26942714
private func == <T>(left: Expectation<T.Type>, right: Any.Type) {
26952715
left.to(NonNilMatcherFunc { expression, _ in
26962716
return try expression.evaluate()! == right
26972717
})
26982718
}
26992719

2700-
// MARK: - Helpers
2701-
27022720
extension SignalProducer {
27032721
internal static func pipe() -> (SignalProducer, ProducedSignal.Observer) {
27042722
let (signal, observer) = ProducedSignal.pipe()
@@ -2728,6 +2746,6 @@ extension SignalProducer {
27282746
}
27292747
}
27302748

2731-
return SignalProducer.attempt(operation)
2749+
return SignalProducer(operation)
27322750
}
27332751
}

0 commit comments

Comments
 (0)