Guest User

Untitled

a guest
Jan 22nd, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.33 KB | None | 0 0
  1. /* Credits to @gsampaio for coming up with the Effect<S, A> type.
  2. * Even though this flavor of reducer also describes side-effects,
  3. * testing is still trivial since it's sufficient to check if the
  4. * side-effects are of the right type. The actual execution of the
  5. * effect can be tested separately using integration tests. */
  6.  
  7. import RxSwift
  8.  
  9. class Effect<S: Equatable, A: Action> {
  10. open func execute(state: () -> S) -> Observable<A> {
  11. fatalError("not implemented")
  12. }
  13.  
  14. static func empty<S, A>() -> Effect<S, A> {
  15. return EmptyEffect()
  16. }
  17.  
  18. private class EmptyEffect<S: Equatable, A: Action>: Effect<S, A> {
  19. override func execute(state: () -> S) -> Observable<A> {
  20. return .empty()
  21. }
  22. }
  23. }
  24.  
  25. protocol Action {}
  26.  
  27. struct Reducer<S: Equatable, A: Action> {
  28. let reduce: (S, A) -> (S, Effect<S, A>)
  29.  
  30. init (_ reduce: @escaping (S, A) -> (S, Effect<S, A>)) {
  31. self.reduce = reduce
  32. }
  33. }
  34.  
  35. class Store<S: Equatable, A: Action> {
  36. private let actionSink: AnyObserver<A>
  37. private let state: Observable<S>
  38.  
  39. fileprivate init (actionSink: AnyObserver<A>, state: Observable<S>) {
  40. self.actionSink = actionSink
  41. self.state = state
  42. }
  43.  
  44. static func create<S, A>(reducer: Reducer<S, A>, initialState: S) -> Store<S, A> {
  45. let actionSink: AnyObserver<A>
  46. let stateSubject = BehaviorSubject<S>(value: initialState)
  47. var dispatch: (A) -> Void = { _ in }
  48. var interpret: (Effect<S, A>) -> Void = { _ in }
  49.  
  50. var currentState = initialState {
  51. didSet { stateSubject.onNext(currentState) }
  52. }
  53.  
  54. actionSink = AnyObserver<A> { event in
  55. switch event {
  56. case let .next(action): dispatch(action)
  57. default: break
  58. }
  59. }
  60.  
  61. dispatch = { action in
  62. let (nextState, nextEffect) = reducer.reduce(currentState, action)
  63. currentState = nextState
  64. interpret(nextEffect)
  65. }
  66.  
  67. interpret = { effect in
  68. _ = effect.execute(state: { currentState }).subscribe(onNext: dispatch)
  69. }
  70.  
  71. return Store<S, A>(actionSink: actionSink, state: stateSubject)
  72. }
  73.  
  74. func asObserver() -> AnyObserver<A> {
  75. return actionSink
  76. }
  77.  
  78. func asObservable() -> Observable<S> {
  79. return state
  80. }
  81. }
  82.  
  83. //
  84.  
  85. class PrintEffect: Effect<PrintState, PrintAction> {
  86. override func execute(state: () -> PrintState) -> Observable<PrintAction> {
  87. print("State before effect:", state())
  88. return .just(.finishPrinting)
  89. }
  90. }
  91.  
  92. enum PrintAction: Action {
  93. case startPrinting
  94. case finishPrinting
  95. }
  96.  
  97. struct PrintState: Equatable {
  98. let isPrinting: Bool
  99.  
  100. static func == (lhs: PrintState, rhs: PrintState) -> Bool {
  101. return lhs.isPrinting == rhs.isPrinting
  102. }
  103. }
  104.  
  105. func PrintReducer() -> Reducer<PrintState, PrintAction> {
  106. return Reducer { _, action in
  107. switch action {
  108. case .startPrinting:
  109. return (PrintState(isPrinting: true), PrintEffect())
  110. case .finishPrinting:
  111. return (PrintState(isPrinting: false), .empty())
  112. }
  113. }
  114. }
  115.  
  116. let store = Store<PrintState, PrintAction>.create(reducer: PrintReducer(), initialState: PrintState(isPrinting: false))
  117. _ = store.asObservable().subscribe(onNext: { state in print("Subscribed state:", state) })
  118. store.asObserver().onNext(.startPrinting)
Add Comment
Please, Sign In to add comment