Skip to content

Commit

Permalink
Merge pull request #4 from drekka/develop
Browse files Browse the repository at this point in the history
Tweaking final and updating doco
  • Loading branch information
drekka authored Mar 28, 2019
2 parents 5220d51 + 12bb9ec commit e77f81f
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 127 deletions.
4 changes: 2 additions & 2 deletions Machinus.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 3MHZ7974Y8;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 0.0.4;
DYLIB_CURRENT_VERSION = 0.1.1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Machinus/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
Expand All @@ -448,7 +448,7 @@
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 3MHZ7974Y8;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 0.0.4;
DYLIB_CURRENT_VERSION = 0.1.1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Machinus/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
Expand Down
2 changes: 1 addition & 1 deletion Machinus/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.0.5</string>
<string>$(DYLIB_CURRENT_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
Expand Down
38 changes: 22 additions & 16 deletions Machinus/Machinus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,22 @@ public class Machinus<T>: StateMachine where T: StateIdentifier {

// Validate the state is known and not final
if state(forIdentifier: backgroundState).isFinal {
fatalError("More than one state is using the same identifier")
fatalError("🤖 More than one state is using the same identifier")
}

os_log("🤖 Setting .%@ as the background state.", type: .debug, String(describing: backgroundState))
os_log("🤖 %@: Setting .%@ as the background state.", type: .debug, self.name, String(describing: backgroundState))

// Adding notification watching for backgrounding and foregrounding.
backgroundObserver = NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { [weak self] _ in
guard let self = self else { return }
os_log("🤖 Transitioning to background state .%@", type: .debug, String(describing: backgroundState))
os_log("🤖 %@: Transitioning to background state .%@", type: .debug, self.name, String(describing: backgroundState))
self.transition(toState: backgroundState) { restoreState, _ in
self.restoreState = restoreState
}
}
foregroundObserver = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { [weak self] _ in
guard let self = self, let restoreState = self.restoreState else { return }
os_log("🤖 Restoring state .%@", type: .debug, String(describing: backgroundState))
os_log("🤖 %@: Restoring state .%@", type: .debug, self.name, String(describing: backgroundState))
self.transition(toState: restoreState) { _, _ in
self.restoreState = nil
}
Expand All @@ -88,7 +88,7 @@ public class Machinus<T>: StateMachine where T: StateIdentifier {
self.current = firstState

if Set(self.states.map { $0.identifier }).count != self.states.count {
fatalError("More than one state is using the same identifier")
fatalError("🤖 More than one state is using the same identifier")
}
}

Expand All @@ -110,8 +110,7 @@ public class Machinus<T>: StateMachine where T: StateIdentifier {

public func transition(completion: @escaping (_ previousState: T?, _ error: Error?) -> Void) {
guard let dynamicClosure = current.dynamicTransition else {
completion(nil, MachinusError.dynamicTransitionNotDefined)
return
fatalError("🤖 No dynamic transition defined")
}
runTransition(nextState: dynamicClosure, completion: completion)
}
Expand Down Expand Up @@ -141,7 +140,7 @@ public class Machinus<T>: StateMachine where T: StateIdentifier {
self.transitionLock.lock()
let toStateIdentifier = nextState()

os_log("🤖 Transitioning to .%@", type: .debug, String(describing: toStateIdentifier))
os_log("🤖 %@: Transitioning to .%@", type: .debug, self.name, String(describing: toStateIdentifier))
if let toState = self.preflightTransition(toState: toStateIdentifier, completion: completion) {
self.executeTransition(toState: toState, completion: completion)
}
Expand All @@ -165,39 +164,46 @@ public class Machinus<T>: StateMachine where T: StateIdentifier {

private func preflightTransition(toState toStateIdentifier: T, completion: @escaping (_ previousState: T?, _ error: Error?) -> Void) -> StateConfig<T>? {

os_log("🤖 Pre-flighting transition ...", type: .debug)
os_log("🤖 %@: Pre-flighting transition ...", type: .debug, self.name)

let newState = state(forIdentifier: toStateIdentifier)

// If the state is the same state then do nothing.
guard current != toStateIdentifier else {
os_log("🤖 Already in state", type: .debug)
os_log("🤖 %@: Already in state", type: .debug, self.name)
completion(nil, enableSameStateError ? MachinusError.alreadyInState : nil)
return nil
}

// Ignore the rest of the pre-flight if we are about to transition to or from the background state.
if isBackgroundTransition(toOrFromState: toStateIdentifier) {
os_log("🤖 Transitioning to or from background state .%@, ignoring allowed and barriers.", type: .debug, String(describing: backgroundState!))

// Background transitions from a final state are automatically ignored.
if current.isFinal {
os_log("🤖 %@: Final state cannot transition to the background state. Ignoring request.", type: .info, self.name)
completion(nil, nil)
return nil
}

os_log("🤖 %@: Transitioning to or from background state .%@, ignoring allowed and barriers.", type: .debug, self.name, String(describing: backgroundState!))
return newState
}

// Check for a final state transition
if current.isFinal {
os_log("🤖 Final state, cannot transition", type: .error)
os_log("🤖 %@: Final state, cannot transition", type: .error, self.name)
completion(nil, enableFinalStateTransitionError ? MachinusError.finalState : nil)
return nil
}


guard newState.transitionBarrier() else {
os_log("🤖 Transition barrier blocked transition", type: .debug)
os_log("🤖 %@: Transition barrier blocked transition", type: .debug, self.name)
completion(nil, MachinusError.transitionDenied)
return nil
}

guard current.canTransition(toState: newState) else {
os_log("🤖 Illegal transition", type: .debug)
os_log("🤖 %@: Illegal transition", type: .debug, self.name)
completion(nil, MachinusError.illegalTransition)
return nil
}
Expand All @@ -207,7 +213,7 @@ public class Machinus<T>: StateMachine where T: StateIdentifier {

private func executeTransition(toState: StateConfig<T>, completion: @escaping (_ previousState: T?, _ error: Error?) -> Void) {

os_log("🤖 Executing transition ...", type: .debug)
os_log("🤖 %@: Executing transition ...", type: .debug, self.name)

let toStateIdentifier = toState.identifier
let fromState = current
Expand Down
5 changes: 1 addition & 4 deletions Machinus/MachinusError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ public enum MachinusError: Error {
/// Returned when the target state is not in the current state's allowed transition list.
case illegalTransition

/// Thrown when there is no dynamic transition defined on the current state.
case dynamicTransitionNotDefined

/// Thrown if youu attempt to transition from a final state.
/// Thrown when a transition is requested from a final state.
case finalState
}
2 changes: 1 addition & 1 deletion Machinus/StateMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public protocol StateMachine {
/// If true and a transition to the same state is requested an error will be thrown. Otherwise the completion is called with both values as nil.
var enableSameStateError: Bool { get set }

/// If true and a transition from a final state. Otherwise the completion is called with both values as nil.
/// If enabled and a transition from a final state is attempted then a MachinusError.finalState error is returned. Otherwise a nil error is returned.
var enableFinalStateTransitionError: Bool { get set }

/// If enabled, the engine will send notifications of a state change.
Expand Down
11 changes: 1 addition & 10 deletions MachinusTests/MachinusTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,16 +208,7 @@ class MachinusTests: XCTestCase {
}

func testDynamicTransitionNotDefinedFailure() {

var prevState: MyState?
var error: Error?
machine.transition {
prevState = $0
error = $1
}

expect(error as? MachinusError).toEventually(equal(.dynamicTransitionNotDefined))
expect(prevState).to(beNil())
expect(self.machine.transition { _, _ in }).toEventually(throwAssertion())
}

// MARK: - Background transitions
Expand Down
Loading

0 comments on commit e77f81f

Please sign in to comment.