Skip to content

Commit

Permalink
Change Reducer to a function type
Browse files Browse the repository at this point in the history
  • Loading branch information
Qata committed Feb 27, 2017
1 parent 05c0a4a commit 6e0411b
Show file tree
Hide file tree
Showing 7 changed files with 24 additions and 53 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#Upcoming Release
**Breaking API Changes:**

- Change Reducer to a generic function type - @Qata

**API Changes:**

- Rename `Middleware.increase(_:)` to `Middleware.flatMap(_:)` - @Qata
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ enum AppAction: Action {
Your reducer needs to respond to these different actions, that can be done by switching over the value of action:

```swift
let appReducer = Reducer<AppState> { action, state in
let appReducer: Reducer<AppState> = { action, state in
switch action as? AppAction {
case .Increase?:
state.counter += 1
Expand All @@ -69,7 +69,7 @@ let appReducer = Reducer<AppState> { action, state in
}
```

A single `Reducer` should only deal with a single field of the state struct. You can chain together multiple reducers using `Reducer(firstReducer, secondReducer, ...)`.
A single `Reducer` should only deal with a single field of the state struct. You can nest multiple reducers within your main reducer to provide separation of concerns.

In order to have a predictable app state, it is important that the reducer is always free of side effects, it receives the current app state and an action and returns the new app state.

Expand Down
39 changes: 1 addition & 38 deletions Sources/CoreTypes/Reducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,4 @@

import Foundation

/**
Reducer is a structure that allows you to modify the current state
by reducing actions.
*/
public struct Reducer<State: StateType> {
public let transform: (Action, State) -> State

/**
Initialises the `Reducer` with a transformative function.
- parameter transform: The function that will be able to modify passed state.
*/
public init(_ transform: @escaping (Action, State) -> State) {
self.transform = transform
}

/**
Initialises the `Reducer` by concatenating the transformative functions from
the `Reducer`s that were passed in.
*/
public init(_ first: Reducer<State>, _ rest: Reducer<State>...) {
self = rest.reduce(first) {
$0.concat($1)
}
}

/// Concatenates the transform function of the passed `Reducer` onto the callee's transform.
public func concat(_ other: Reducer<State>) -> Reducer<State> {
return map(other.transform)
}

/// Concatenates the transform function onto the callee's transform.
public func map(_ transform: @escaping (Action, State) -> State) -> Reducer<State> {
return Reducer<State> {
return transform($0, self.transform($0, $1))
}
}
}
public typealias Reducer<State> = (_ action: Action, _ state: State) -> State
4 changes: 2 additions & 2 deletions Sources/CoreTypes/Store.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ open class Store<ObservableProperty: ObservablePropertyType> where ObservablePro
private let reducer: StoreReducer
private let disposeBag = SubscriptionReferenceBag()

public required init(reducer: StoreReducer, observable: ObservableProperty, middleware: StoreMiddleware = Middleware()) {
public required init(reducer: @escaping StoreReducer, observable: ObservableProperty, middleware: StoreMiddleware = Middleware()) {
self.reducer = reducer
self.observable = observable
self.middleware = middleware
Expand All @@ -30,7 +30,7 @@ open class Store<ObservableProperty: ObservablePropertyType> where ObservablePro
actions.forEach { self?.dispatch($0) }
}
middleware.transform({ self.observable.value }, dispatchFunction, action).forEach { action in
observable.value = reducer.transform(action, observable.value)
observable.value = reducer(action, observable.value)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/Observable/StoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class DeInitStore<State: StateType>: Store<ObservableProperty<State>> {
deInitAction?()
}

convenience init(reducer: Reducer<ObservableProperty<State>.ValueType>,
convenience init(reducer: @escaping Reducer<ObservableProperty<State>.ValueType>,
observable: ObservableProperty<State>,
middleware: Middleware<ObservableProperty<State>.ValueType> = Middleware(),
deInitAction: @escaping () -> Void) {
Expand All @@ -46,7 +46,7 @@ class DeInitStore<State: StateType>: Store<ObservableProperty<State>> {
self.deInitAction = deInitAction
}

required init(reducer: Reducer<ObservableProperty<State>.ValueType>,
required init(reducer: @escaping Reducer<ObservableProperty<State>.ValueType>,
observable: ObservableProperty<State>,
middleware: Middleware<ObservableProperty<State>.ValueType>) {
super.init(reducer: reducer,
Expand Down
18 changes: 11 additions & 7 deletions Tests/ReducerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ class MockReducerContainer {
var reducer: Reducer<CounterState>!

init() {
reducer = Reducer { action, state in
reducer = { action, state in
self.calledWithAction.append(action)
return state
}
}
}

let increaseByOneReducer = Reducer { action, state in
let increaseByOneReducer: Reducer<CounterState> = { action, state in
CounterState(count: state.count + 1)
}

let increaseByTwoReducer = Reducer { action, state in
let increaseByTwoReducer: Reducer<CounterState> = { action, state in
CounterState(count: state.count + 2)
}

Expand All @@ -39,9 +39,11 @@ class ReducerTests: XCTestCase {
let mockReducer1 = MockReducerContainer()
let mockReducer2 = MockReducerContainer()

let combinedReducer = Reducer(mockReducer1.reducer, mockReducer2.reducer)
let combinedReducer: Reducer<CounterState> = { action, state in
mockReducer2.reducer(action, mockReducer1.reducer(action, state))
}

_ = combinedReducer.transform(NoOpAction(), CounterState())
_ = combinedReducer(NoOpAction(), CounterState())

XCTAssertEqual(mockReducer1.calledWithAction.count, 1)
XCTAssertEqual(mockReducer2.calledWithAction.count, 1)
Expand All @@ -53,9 +55,11 @@ class ReducerTests: XCTestCase {
it combines the results from each individual reducer correctly
*/
func testCombinesReducerResults() {
let combinedReducer = Reducer(increaseByOneReducer, increaseByTwoReducer)
let combinedReducer: Reducer<CounterState> = { action, state in
increaseByTwoReducer(action, increaseByOneReducer(action, state))
}

let newState = combinedReducer.transform(NoOpAction(), CounterState())
let newState = combinedReducer(NoOpAction(), CounterState())

XCTAssertEqual(newState.count, 3)
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/TestFakes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ struct SetValueStringAction: StandardActionConvertible {

}

let testReducer = Reducer<TestAppState> { action, state in
let testReducer: Reducer<TestAppState> = { action, state in
switch action {
case let action as SetValueAction:
return TestAppState(testValue: action.value)
Expand All @@ -76,7 +76,7 @@ let testReducer = Reducer<TestAppState> { action, state in
}
}

let testValueStringReducer = Reducer<TestStringAppState> { action, state in
let testValueStringReducer: Reducer<TestStringAppState> = { action, state in
switch action {
case let action as SetValueStringAction:
return TestStringAppState(testValue: action.value)
Expand Down

0 comments on commit 6e0411b

Please sign in to comment.