Skip to content

Commit cf8c2d6

Browse files
Create a Selector with another Selector and a KeyPath (#98)
* Create a Selector with another Selector and a KeyPath * Update SelectorTests.swift * Update Selector.swift
1 parent 327a4c4 commit cf8c2d6

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

Sources/Fluxor/Selector.swift

+33-9
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ public class Selector1<State, S1, Value>: Selector<State, Value> where
7676
self.projector = projector
7777
super.init(projector: { projector(selector1.map($0)) })
7878
}
79+
80+
/**
81+
Creates a `Selector` from a `Selector` and a `projector` function.
82+
83+
- Parameter selector1: The first `Selector`
84+
- Parameter projector: The closure to pass the value from the `Selector` to
85+
*/
86+
public convenience init(_ selector1: S1, keyPath: KeyPath<S1.Value, Value>) {
87+
self.init(selector1) { $0[keyPath: keyPath] }
88+
}
7989
}
8090

8191
/// A `Selector` created from two `Selector`s and a `projector` function.
@@ -122,8 +132,8 @@ public class Selector3<State, S1, S2, S3, Value>: Selector<State, Value> where
122132
_ projector: @escaping (S1.Value, S2.Value, S3.Value) -> Value) {
123133
self.projector = projector
124134
super.init(projector: { projector(selector1.map($0),
125-
selector2.map($0),
126-
selector3.map($0)) })
135+
selector2.map($0),
136+
selector3.map($0)) })
127137
}
128138
}
129139

@@ -152,9 +162,9 @@ public class Selector4<State, S1, S2, S3, S4, Value>: Selector<State, Value> whe
152162
_ projector: @escaping (S1.Value, S2.Value, S3.Value, S4.Value) -> Value) {
153163
self.projector = projector
154164
super.init(projector: { projector(selector1.map($0),
155-
selector2.map($0),
156-
selector3.map($0),
157-
selector4.map($0)) })
165+
selector2.map($0),
166+
selector3.map($0),
167+
selector4.map($0)) })
158168
}
159169
}
160170

@@ -186,10 +196,10 @@ public class Selector5<State, S1, S2, S3, S4, S5, Value>: Selector<State, Value>
186196
_ projector: @escaping (S1.Value, S2.Value, S3.Value, S4.Value, S5.Value) -> Value) {
187197
self.projector = projector
188198
super.init(projector: { projector(selector1.map($0),
189-
selector2.map($0),
190-
selector3.map($0),
191-
selector4.map($0),
192-
selector5.map($0)) })
199+
selector2.map($0),
200+
selector3.map($0),
201+
selector4.map($0),
202+
selector5.map($0)) })
193203
}
194204
}
195205

@@ -208,6 +218,20 @@ public extension Selector {
208218
.init(selector1, projector)
209219
}
210220

221+
/**
222+
Creates a `Selector` from a `Selector` and a `KeyPath`.
223+
224+
- Parameter selector1: The first `Selector`
225+
- Parameter keyPath: The `keyPath` to create the `Selector` from
226+
- Parameter keyPath: The `KeyPath` to subscript in the value from the `Selector`
227+
- Returns: A `Selector` from the given `Selector` and the `KeyPath`
228+
*/
229+
static func with<S1>(_ selector1: S1,
230+
keyPath: KeyPath<S1.Value, Value>)
231+
-> Selector1<State, S1, Value> {
232+
.init(selector1, keyPath: keyPath)
233+
}
234+
211235
/**
212236
Creates a `Selector` from two `Selector`s and a `projector` function.
213237

Tests/FluxorTests/SelectorTests.swift

+14-5
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ class SelectorTests: XCTestCase {
2121
private let scandalsSelector = Selector(keyPath: \TestState.scandals)
2222
private let newProductsSelector = Selector(projector: { (state: TestState) in state.newProducts })
2323

24-
private lazy var fullNameSelector = Selector1(nameSelector) {
24+
private lazy var fullNameSelector = Selector.with(nameSelector) {
2525
"\($0.firstName) \($0.lastName)"
2626
}
2727

28-
private lazy var formattedBirthdaySelector = Selector1(birthdaySelector) {
28+
private lazy var firstNameSelector = Selector.with(nameSelector, keyPath: \.firstName)
29+
30+
private lazy var formattedBirthdaySelector = Selector.with(birthdaySelector) {
2931
"\($0.month) \($0.day), \($0.year)"
3032
}
3133

32-
private lazy var formattedAddressSelector = Selector1(addressSelector) {
34+
private lazy var formattedAddressSelector = Selector.with(addressSelector) {
3335
"\($0.address), \($0.city), \($0.country)"
3436
}
3537

@@ -65,13 +67,20 @@ class SelectorTests: XCTestCase {
6567
XCTAssertEqual(addressSelector.map(state), state.address)
6668
}
6769

68-
/// Is it possible to create a `Selector` with 1 `Selector`s and map the state?
69-
func testCreateSelector1() {
70+
/// Is it possible to create a `Selector` with 1 `Selector`s and map the state with projector?
71+
func testCreateSelector1_Projector() {
7072
XCTAssertEqual(fullNameSelector.map(state), "Tim Cook")
7173
modifyState()
7274
XCTAssertEqual(fullNameSelector.map(state), "Steve Jobs")
7375
}
7476

77+
/// Is it possible to create a `Selector` with 1 `Selector`s and map the state with KeyPath?
78+
func testCreateSelector1_KeyPath() {
79+
XCTAssertEqual(firstNameSelector.map(state), "Tim")
80+
modifyState()
81+
XCTAssertEqual(firstNameSelector.map(state), "Steve")
82+
}
83+
7584
/// Is it possible to create a `Selector` with 2 `Selector`s and map the state?
7685
func testCreateSelector2() {
7786
let congratulationsSelector = Selector.with(fullNameSelector, birthdaySelector) {

0 commit comments

Comments
 (0)