Skip to content

Commit cbf1238

Browse files
authored
Merge pull request #15 from ReactiveCocoa/anders/scoping-event-type
Create scoped store that zooms only on the event type, and ignore/disable external event input completely
2 parents c8367c9 + 7da5a74 commit cbf1238

File tree

3 files changed

+30
-12
lines changed

3 files changed

+30
-12
lines changed

Loop/LoopBox.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import ReactiveSwift
22

33
internal class ScopedLoopBox<RootState, RootEvent, ScopedState, ScopedEvent>: LoopBoxBase<ScopedState, ScopedEvent> {
44
override var producer: SignalProducer<ScopedState, Never> {
5-
root.producer.map(value)
5+
root.producer.map(extract)
66
}
77

88
override var lifetime: Lifetime {
@@ -11,20 +11,20 @@ internal class ScopedLoopBox<RootState, RootEvent, ScopedState, ScopedEvent>: Lo
1111

1212
/// Loop Internal SPI
1313
override var _current: ScopedState {
14-
root._current[keyPath: value]
14+
extract(root._current)
1515
}
1616

1717
private let root: LoopBoxBase<RootState, RootEvent>
18-
private let value: KeyPath<RootState, ScopedState>
18+
private let extract: (RootState) -> ScopedState
1919
private let eventTransform: (ScopedEvent) -> RootEvent
2020

2121
init(
2222
root: LoopBoxBase<RootState, RootEvent>,
23-
value: KeyPath<RootState, ScopedState>,
23+
value: @escaping (RootState) -> ScopedState,
2424
event: @escaping (ScopedEvent) -> RootEvent
2525
) {
2626
self.root = root
27-
self.value = value
27+
self.extract = value
2828
self.eventTransform = event
2929
}
3030

@@ -33,12 +33,14 @@ internal class ScopedLoopBox<RootState, RootEvent, ScopedState, ScopedEvent>: Lo
3333
}
3434

3535
override func scoped<S, E>(
36-
to scope: KeyPath<ScopedState, S>,
36+
to scope: @escaping (ScopedState) -> S,
3737
event: @escaping (E) -> ScopedEvent
3838
) -> LoopBoxBase<S, E> {
39+
let extract = self.extract
40+
3941
return ScopedLoopBox<RootState, RootEvent, S, E>(
4042
root: self.root,
41-
value: value.appending(path: scope),
43+
value: { scope(extract($0)) },
4244
event: { [eventTransform] in eventTransform(event($0)) }
4345
)
4446
}
@@ -75,7 +77,7 @@ internal class RootLoopBox<State, Event>: LoopBoxBase<State, Event> {
7577
}
7678

7779
override func scoped<S, E>(
78-
to scope: KeyPath<State, S>,
80+
to scope: @escaping (State) -> S,
7981
event: @escaping (E) -> Event
8082
) -> LoopBoxBase<S, E> {
8183
ScopedLoopBox(root: self, value: scope, event: event)
@@ -108,7 +110,7 @@ internal class LoopBoxBase<State, Event> {
108110
func send(_ event: Event) { subclassMustImplement() }
109111

110112
func scoped<S, E>(
111-
to scope: KeyPath<State, S>,
113+
to scope: @escaping (State) -> S,
112114
event: @escaping (E) -> Event
113115
) -> LoopBoxBase<S, E> {
114116
subclassMustImplement()

Loop/Public/Loop.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,29 @@ public final class Loop<State, Event> {
4646
}
4747

4848
public func scoped<ScopedState, ScopedEvent>(
49-
to scope: KeyPath<State, ScopedState>,
49+
to scope: @escaping (State) -> ScopedState,
5050
event: @escaping (ScopedEvent) -> Event
5151
) -> Loop<ScopedState, ScopedEvent> {
5252
return Loop<ScopedState, ScopedEvent>(
5353
box: box.scoped(to: scope, event: event)
5454
)
5555
}
56+
57+
public func scoped<ScopedEvent>(
58+
event: @escaping (ScopedEvent) -> Event
59+
) -> Loop<State, ScopedEvent> {
60+
return Loop<State, ScopedEvent>(
61+
box: box.scoped(to: { $0 }, event: event)
62+
)
63+
}
64+
65+
/// Create a scoped `Loop` from `self` which will not accept any input from `Loop.send(_:)`. Note that sending
66+
/// events on `self` through `Loop.send(_:)` remains unaffected.
67+
public func ignoringInput() -> Loop<State, Never> {
68+
return Loop<State, Never>(
69+
box: box.scoped(to: { $0 }, event: { _ in fatalError() })
70+
)
71+
}
5672
}
5773

5874
extension Loop {
@@ -73,7 +89,7 @@ extension Loop {
7389
value: KeyPath<State, ScopedState>,
7490
event: @escaping (ScopedEvent) -> Event
7591
) -> Loop<ScopedState, ScopedEvent> {
76-
return scoped(to: value, event: event)
92+
return scoped(to: { $0[keyPath: value] }, event: event)
7793
}
7894

7995
@available(*, unavailable, message:"Loop now starts automatically.")

Loop/Public/SwiftUI/LoopBinding.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public struct LoopBinding<State, Event>: DynamicProperty {
3939
}
4040

4141
public func scoped<ScopedState, ScopedEvent>(
42-
to value: KeyPath<State, ScopedState>,
42+
to value: @escaping (State) -> ScopedState,
4343
event: @escaping (ScopedEvent) -> Event
4444
) -> LoopBinding<ScopedState, ScopedEvent> {
4545
LoopBinding<ScopedState, ScopedEvent>(loop.scoped(to: value, event: event))

0 commit comments

Comments
 (0)