Skip to content

Commit

Permalink
Merge pull request #38 from CombineCommunity/feature/rewrite-statemac…
Browse files Browse the repository at this point in the history
…hine-dsl

Feature/rewrite statemachine dsl
  • Loading branch information
twittemb authored Mar 1, 2021
2 parents ceb6c2b + 31bbd72 commit 9d8ba9b
Show file tree
Hide file tree
Showing 44 changed files with 1,604 additions and 796 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
**v0.3.0 - Tyranus**:

- Feedback: introduce the "on:" keyword to explicitly declare the type of state that concerns the side effect
- Feedback: replace the parameter "sideEffect" by "perform" to have a nice readable sentence: ...(on: Loading.self, ..., perform: sideEffect)
- State Machine: introduce a new DSL based on From/On that allows to group transitions from the same state type
- State Machine: provide assert functions to ease the unit tests of transitions

**v0.2.0 - Vader**:

Expand Down
217 changes: 195 additions & 22 deletions Examples/Examples.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"pins": [
{
"package": "Feedbacks",
"repositoryURL": "[email protected]:twittemb/Feedbacks.git",
"repositoryURL": "[email protected]:CombineCommunity/Feedbacks.git",
"state": {
"branch": null,
"revision": "ceca7e90a065cbb67346d0234243f598500ddfc5",
"revision": "826c7798699acd5a9d0348049eaeb8917399a94f",
"version": null
}
}
Expand Down
2 changes: 1 addition & 1 deletion Examples/Examples/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct ContentView: View {
destination: GifList.RootView(
system: GifList
.System
.gifOverview
.gifs
.uiSystem(viewStateFactory: GifList.ViewState.stateToViewState(state:))
.run()
))
Expand Down
20 changes: 20 additions & 0 deletions Examples/Examples/CounterApp/Models/Counter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Counter.swift
// Examples
//
// Created by Thibault Wittemberg on 2021-02-28.
//

struct Counter: Equatable {
let value: Int
let min: Int
let max: Int

func decrease() -> Counter {
Counter(value: self.value - 1, min: self.min, max: self.max)
}

func increase() -> Counter {
Counter(value: self.value + 1, min: self.min, max: self.max)
}
}
7 changes: 1 addition & 6 deletions Examples/Examples/CounterApp/System/CounterApp+Events.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@ extension CounterApp {

extension CounterApp.Events {
struct TogglePause: Event {}

struct Reset: Event {
let value: Int
}

struct Reset: Event {}
struct Increase: Event {}

struct Decrease: Event {}
}

20 changes: 2 additions & 18 deletions Examples/Examples/CounterApp/System/CounterApp+SideEffects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,17 @@ extension CounterApp {

extension CounterApp.SideEffects {
// This effect will make the state decrease when it is already decreasing and not paused
// When the state is equal to 0, then the effect asks for an increase
static func decreaseEffect(state: CounterApp.States.Decreasing) -> AnyPublisher<Event, Never> {
guard !state.isPaused else { return Empty().eraseToAnyPublisher() }

if state.value > 0 {
return Just<Event>(CounterApp.Events.Decrease())
.delay(for: 1, scheduler: DispatchQueue(label: UUID().uuidString))
.eraseToAnyPublisher()
}

return Just<Event>(CounterApp.Events.Increase())
return Just<Event>(CounterApp.Events.Decrease())
.delay(for: 1, scheduler: DispatchQueue(label: UUID().uuidString))
.eraseToAnyPublisher()
}

// This effect will make the state increase when it is already increasing and not paused
// When the state is equal to 10, then the effect asks for a decrease
static func increaseEffect(state: CounterApp.States.Increasing) -> AnyPublisher<Event, Never> {
guard !state.isPaused else { return Empty().eraseToAnyPublisher() }

if state.value < 10 {
return Just<Event>(CounterApp.Events.Increase())
.delay(for: 1, scheduler: DispatchQueue(label: UUID().uuidString))
.eraseToAnyPublisher()
}

return Just<Event>(CounterApp.Events.Decrease())
return Just<Event>(CounterApp.Events.Increase())
.delay(for: 1, scheduler: DispatchQueue(label: UUID().uuidString))
.eraseToAnyPublisher()
}
Expand Down
12 changes: 6 additions & 6 deletions Examples/Examples/CounterApp/System/CounterApp+States.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ extension CounterApp {
}

extension CounterApp.States {
struct Fixed: State {
let value: Int
struct Fixed: State, Equatable {
let counter: Counter
}

struct Increasing: State {
let value: Int
struct Increasing: State, Equatable {
let counter: Counter
let isPaused: Bool
}

struct Decreasing: State {
let value: Int
struct Decreasing: State, Equatable {
let counter: Counter
let isPaused: Bool
}
}
41 changes: 34 additions & 7 deletions Examples/Examples/CounterApp/System/CounterApp+System.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ extension CounterApp {
extension CounterApp.System {
static let counter = System {
InitialState {
CounterApp.States.Fixed(value: 10)
CounterApp.States.Fixed(counter: Counter(value: 10, min: 0, max: 10))
}

Feedbacks {
Feedback(on: CounterApp.States.Decreasing.self,
strategy: .cancelOnNewState,
sideEffect: CounterApp.SideEffects.decreaseEffect(state:))
perform: CounterApp.SideEffects.decreaseEffect(state:))

Feedback(on: CounterApp.States.Increasing.self,
strategy: .cancelOnNewState,
sideEffect: CounterApp.SideEffects.increaseEffect(state:))
perform: CounterApp.SideEffects.increaseEffect(state:))
}
.onStateReceived {
print("Counter: New state has been received: \($0)")
Expand All @@ -35,10 +35,37 @@ extension CounterApp.System {
}

Transitions {
CounterApp.Transitions.fixedTransition
CounterApp.Transitions.resetTransition
CounterApp.Transitions.decreasingTransitions
CounterApp.Transitions.increasingTransitions
From(CounterApp.States.Fixed.self) { state in
On(CounterApp.Events.TogglePause.self, transitionTo: CounterApp.States.Decreasing(counter: state.counter, isPaused: false))
}

From(AnyState.self) {
On(CounterApp.Events.Reset.self) {
CounterApp.States.Fixed(counter: Counter(value: 10, min: 0, max: 10))
}
}

From(CounterApp.States.Decreasing.self) { state in
On(CounterApp.Events.TogglePause.self, transitionTo: CounterApp.States.Decreasing(counter: state.counter, isPaused: !state.isPaused))
On(CounterApp.Events.Decrease.self) {
guard !state.isPaused else { return state }
if state.counter.value == state.counter.min {
return CounterApp.States.Increasing(counter: state.counter.increase(), isPaused: false)
}
return CounterApp.States.Decreasing(counter: state.counter.decrease(), isPaused: false)
}
}

From(CounterApp.States.Increasing.self) { state in
On(CounterApp.Events.TogglePause.self, transitionTo: CounterApp.States.Increasing(counter: state.counter, isPaused: !state.isPaused))
On(CounterApp.Events.Increase.self) {
guard !state.isPaused else { return state }
if state.counter.value == state.counter.max {
return CounterApp.States.Decreasing(counter: state.counter.decrease(), isPaused: false)
}
return CounterApp.States.Increasing(counter: state.counter.increase(), isPaused: false)
}
}
}
}
}
56 changes: 0 additions & 56 deletions Examples/Examples/CounterApp/System/CounterApp+Transitions.swift

This file was deleted.

14 changes: 7 additions & 7 deletions Examples/Examples/CounterApp/Views/CounterApp+RootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ extension CounterApp {
HStack {
Spacer()
Button(action: {
self.system.emit(CounterApp.Events.Reset(value: 10))
self.system.emit(CounterApp.Events.Reset())
}) {
Text("Reset")
.font(.system(size: 25))
Expand Down Expand Up @@ -66,9 +66,9 @@ extension CounterApp {

private func counterValue(from rawState: RawState) -> Int {
switch rawState.state {
case let fixed as CounterApp.States.Fixed: return fixed.value
case let decreasing as CounterApp.States.Decreasing: return decreasing.value
case let increasing as CounterApp.States.Increasing: return increasing.value
case let fixed as CounterApp.States.Fixed: return fixed.counter.value
case let decreasing as CounterApp.States.Decreasing: return decreasing.counter.value
case let increasing as CounterApp.States.Increasing: return increasing.counter.value
default: return 0
}
}
Expand Down Expand Up @@ -99,11 +99,11 @@ extension CounterApp {
private func counterDescription(from rawState: RawState) -> String {
switch rawState.state {
case let fixed as CounterApp.States.Fixed:
return "Fixed(value: \(fixed.value))"
return "Fixed(value: \(fixed.counter.value))"
case let decreasing as CounterApp.States.Decreasing:
return "Decreasing(value: \(decreasing.value), paused: \(decreasing.isPaused))"
return "Decreasing(value: \(decreasing.counter.value), paused: \(decreasing.isPaused))"
case let increasing as CounterApp.States.Increasing:
return "Increasing(value: \(increasing.value), paused: \(increasing.isPaused))"
return "Increasing(value: \(increasing.counter.value), paused: \(increasing.isPaused))"
default: return "undefined"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ extension GifDetail {
}

extension GifDetail.States {
struct Loading: State {}
struct Loading: State, Equatable {}

struct Loaded: State {
struct Loaded: State, Equatable {
let gif: Gif
let isFavorite: Bool
}

struct TogglingFavorite: State {
struct TogglingFavorite: State, Equatable {
let gif: Gif
let isFavorite: Bool
}

struct Failed: State {}
struct Failed: State, Equatable {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ extension GifDetail.System {
}

Feedbacks {
Feedback(on: GifDetail.States.Loading.self, strategy: .cancelOnNewState, sideEffect: loadSideEffect)
Feedback(on: GifDetail.States.Loading.self, strategy: .cancelOnNewState, perform: loadSideEffect)
.execute(on: DispatchQueue(label: "Load Gif Queue"))

Feedback(on: GifDetail.States.TogglingFavorite.self, strategy: .cancelOnNewState, sideEffect: toggleFavoriteSideEffect)
Feedback(on: GifDetail.States.TogglingFavorite.self, strategy: .cancelOnNewState, perform: toggleFavoriteSideEffect)
.execute(on: DispatchQueue(label: "Toggle Favorite Queue"))
}
.onStateReceived {
Expand All @@ -45,9 +45,24 @@ extension GifDetail.System {
}

Transitions {
GifDetail.Transitions.loadingTransitions
GifDetail.Transitions.loadedTransition
GifDetail.Transitions.togglingTransitions
From(GifDetail.States.Loading.self) {
On(GifDetail.Events.LoadingIsComplete.self) { event in
GifDetail.States.Loaded(gif: event.gif, isFavorite: event.isFavorite)
}

On(GifDetail.Events.LoadingHasFailed.self, transitionTo: GifDetail.States.Failed())
}

From(GifDetail.States.Loaded.self) { state in
On(GifDetail.Events.ToggleFavorite.self, transitionTo: GifDetail.States.TogglingFavorite(gif: state.gif, isFavorite: !state.isFavorite))
}

From(GifDetail.States.TogglingFavorite.self) {
On(GifDetail.Events.LoadingIsComplete.self) { event in
GifDetail.States.Loaded(gif: event.gif, isFavorite: event.isFavorite)
}
On(GifDetail.Events.LoadingHasFailed.self, transitionTo: GifDetail.States.Failed())
}
}
}
}
Expand Down

This file was deleted.

Loading

0 comments on commit 9d8ba9b

Please sign in to comment.