├── .swift-version
├── Package.swift
├── Tests
├── LinuxMain.swift
└── StatedTests
│ ├── InputArgsAndMappedStateTests.swift
│ └── SimpleStatedTests.swift
├── Stated.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ ├── Stated-watchOS.xcscheme
│ │ ├── Stated-iOS.xcscheme
│ │ ├── Stated-tvOS.xcscheme
│ │ └── Stated-macOS.xcscheme
└── project.pbxproj
├── install_swiftenv.sh
├── Sources
└── Stated
│ ├── States
│ ├── SimpleState.swift
│ ├── StateTakingInput.swift
│ ├── StateUsingMappedState.swift
│ ├── State.swift
│ ├── AnyState.swift
│ └── StateSlot.swift
│ ├── DSL
│ ├── InputDSL.swift
│ ├── TransitionFromStateWithMapDSL.swift
│ ├── InputSlotDSL.swift
│ ├── TransitionFromStateDSL.swift
│ └── StateTransitionTriggerDSL.swift
│ ├── Transitions
│ ├── StateTransition.swift
│ ├── StateTransitionTrigger.swift
│ └── StateTransitionTriggerWithSideEffect.swift
│ ├── Inputs
│ └── InputSlot.swift
│ └── Machine
│ └── StateMachine.swift
├── Stated.podspec
├── Configs
├── StatedTests.plist
└── Stated.plist
├── LICENSE
├── .travis.yml
├── .gitignore
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 4.0
2 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 |
3 | let package = Package(
4 | name: "Stated"
5 | )
6 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import StatedTests
3 |
4 | XCTMain([
5 | testCase(SimpleStatedTests.allTests),
6 | testCase(InputArgsAndMappedStateTests.allTests)
7 | ])
--------------------------------------------------------------------------------
/Stated.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/install_swiftenv.sh:
--------------------------------------------------------------------------------
1 | git clone --depth 1 https://github.com/kylef/swiftenv.git ~/.swiftenv
2 | export SWIFTENV_ROOT="$HOME/.swiftenv"
3 | export PATH="$SWIFTENV_ROOT/bin:$SWIFTENV_ROOT/shims:$PATH"
4 |
5 | if [ -f ".swift-version" ] || [ -n "$SWIFT_VERSION" ]; then
6 | swiftenv install -s
7 | else
8 | swiftenv rehash
9 | fi
10 |
--------------------------------------------------------------------------------
/Sources/Stated/States/SimpleState.swift:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | public protocol SimpleState: State where Arguments == NoArguments, MappedState == Void {
5 | init()
6 | }
7 |
8 | extension SimpleState {
9 | public static func create(arguments: NoArguments, state: Void) -> Self {
10 | return self.init()
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/Stated/States/StateTakingInput.swift:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | public protocol StateTakingInput: State where MappedState == Void {
5 | static func create(arguments: Arguments) -> Self
6 | }
7 |
8 | extension StateTakingInput {
9 | public static func create(arguments: Arguments, state: Void) -> Self {
10 | return self.create(arguments: arguments)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/Stated/States/StateUsingMappedState.swift:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | public protocol StateUsingMappedState: State where Arguments == NoArguments {
5 | static func create(state: MappedState) -> Self
6 | }
7 |
8 | extension StateUsingMappedState {
9 | public static func create(arguments: NoArguments, state: MappedState) -> Self {
10 | return self.create(state: state)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/Stated/DSL/InputDSL.swift:
--------------------------------------------------------------------------------
1 | ///
2 | /// Sugar for creating an input with no arguments.
3 | ///
4 | public func input(_ friendlyName: String? = nil) -> InputSlot {
5 | return InputSlot(friendlyName)
6 | }
7 |
8 | ///
9 | /// Sugar for creating an input with arguments.
10 | /// Alternative to using `InputSlot("Input's debug name")`
11 | ///
12 | public func input(_ friendlyName: String? = nil, taking: Arguments.Type) -> InputSlot {
13 | return InputSlot(friendlyName)
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/Stated/States/State.swift:
--------------------------------------------------------------------------------
1 | public typealias NoArguments = Void
2 |
3 | ///
4 | ///
5 | ///
6 | public protocol State: AnyState {
7 | associatedtype Arguments = NoArguments
8 | associatedtype MappedState = Void
9 |
10 | static func create(arguments: Arguments, state: MappedState) -> Self
11 | }
12 |
13 | extension State {
14 | /// Create a slot that can only take this State in its position.
15 | ///
16 | public static var slot: StateSlot {
17 | return StateSlot()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Stated.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'Stated'
3 | s.version = '1.2.0'
4 | s.summary = 'Swift state machine with a beautiful DSL'
5 | s.homepage = 'https://github.com/jordanhamill/StateMachine'
6 | s.license = { :type => 'MIT', :file => 'LICENSE' }
7 | s.author = { 'Jordan Hamill' => 'jordan.hamill22@gmail.com' }
8 | s.ios.deployment_target = '10.0'
9 | s.osx.deployment_target = '10.9'
10 | s.source = { :git => 'https://github.com/jordanhamill/StateMachine.git', :tag => s.version.to_s }
11 | s.source_files = 'Sources/**/*'
12 | end
13 |
--------------------------------------------------------------------------------
/Sources/Stated/States/AnyState.swift:
--------------------------------------------------------------------------------
1 | public protocol AnyState { }
2 |
3 | extension AnyState {
4 | ///
5 | /// Globally unique identifier for this state.
6 | ///
7 | static var stateId: String { return String(reflecting: Self.self) }
8 |
9 | ///
10 | /// Globally unique identifier for this state.
11 | ///
12 | var stateId: String { return Self.stateId }
13 |
14 | public static func ==(lhs: Self, rhs: Self) -> Bool {
15 | return lhs.stateId == rhs.stateId
16 | }
17 | }
18 |
19 | public func ==(lhs: StateSlot, rhs: AnyState) -> Bool {
20 | return lhs.stateId == rhs.stateId
21 | }
22 |
23 | public func ==(lhs: AnyState, rhs: StateSlot) -> Bool {
24 | return rhs == lhs
25 | }
26 |
--------------------------------------------------------------------------------
/Configs/StatedTests.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Sources/Stated/States/StateSlot.swift:
--------------------------------------------------------------------------------
1 | public class ErasedStateSlot: Equatable, Hashable {
2 | let stateId: String
3 |
4 | fileprivate init(stateId: String) {
5 | self.stateId = stateId
6 | }
7 |
8 | public static func ==(lhs: ErasedStateSlot, rhs: ErasedStateSlot) -> Bool {
9 | return lhs.stateId == rhs.stateId
10 | }
11 |
12 | public var hashValue: Int {
13 | return stateId.hashValue
14 | }
15 |
16 | public func _to(_ to: StateSlot, map: @escaping (StateForSlot) -> StateTo.MappedState) -> StateTransition {
17 | return StateTransition(from: self, to: to, map: map)
18 | }
19 | }
20 |
21 | public class StateSlot: ErasedStateSlot {
22 | public init() {
23 | super.init(stateId: StateForSlot.stateId)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/Stated/Transitions/StateTransition.swift:
--------------------------------------------------------------------------------
1 | public class StateTransition where StateTo.Arguments == Arguments {
2 | let from: ErasedStateSlot
3 | let map: (StateFrom) -> StateTo.MappedState
4 | let to: StateSlot
5 |
6 | init(from: ErasedStateSlot, to: StateSlot, map: @escaping (StateFrom) -> StateTo.MappedState) {
7 | self.from = from
8 | self.to = to
9 | self.map = map
10 | }
11 |
12 | func trigger(withInput arguments: Arguments, stateMachine: StateMachine) -> (fromState: StateFrom, toState: StateTo) {
13 | let previousState = stateMachine.currentState as! StateFrom
14 | let nextState = StateTo.create(arguments: arguments, state: map(previousState))
15 | stateMachine.setNextState(state: nextState)
16 |
17 | return (previousState, nextState)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Configs/Stated.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.2.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2017 Jordan Hamill. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Jordan Hamill
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | matrix:
2 | include:
3 | - language: objective-c
4 | osx_image: xcode9
5 | before_script:
6 | - export LANG=en_US.UTF-8
7 |
8 | script:
9 | - xcodebuild -project Stated.xcodeproj clean
10 | - travis_retry xcodebuild -project Stated.xcodeproj -scheme Stated-iOS -destination 'platform=iOS Simulator,name=iPhone 7' -configuration Debug test
11 |
12 | - language: objective-c
13 | osx_image: xcode9
14 | before_script:
15 | - export LANG=en_US.UTF-8
16 |
17 | script:
18 | - xcodebuild -project Stated.xcodeproj clean
19 | - travis_retry xcodebuild -project Stated.xcodeproj -scheme Stated-macOS -configuration Debug test
20 |
21 | - language: generic
22 | os: linux
23 | sudo: required
24 | dist: trusty
25 | install:
26 | - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)"
27 | - swiftenv install https://swift.org/builds/swift-4.0-release/ubuntu1404/swift-4.0-RELEASE/swift-4.0-RELEASE-ubuntu14.04.tar.gz
28 | - swift build
29 |
30 | script:
31 | - swift test
--------------------------------------------------------------------------------
/Sources/Stated/Inputs/InputSlot.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct InputSlot: Equatable, Hashable, CustomDebugStringConvertible {
4 | public let friendlyName: String
5 | let uuid: String
6 |
7 | public init(_ friendlyName: String? = nil) {
8 | let uuid = UUID().uuidString
9 | self.uuid = uuid
10 | self.friendlyName = friendlyName ?? uuid
11 | }
12 |
13 | public func withArgs(_ args: Arguments) -> StateMachineInput {
14 | return { sm in
15 | guard let potentialTransitions = sm.inputToTransitionTriggers[self.uuid] else { fatalError("Undefined transition") }
16 |
17 | for erasedTransitionTrigger in potentialTransitions {
18 | let result = erasedTransitionTrigger.tryTransition(args: args, stateMachine: sm)
19 | switch result {
20 | case .noMatch:
21 | break
22 | case .triggered:
23 | return
24 | }
25 | }
26 |
27 | fatalError("Undefined transition")
28 | }
29 | }
30 |
31 | public static func ==(lhs: InputSlot, rhs: InputSlot) -> Bool {
32 | return lhs.uuid == rhs.uuid
33 | }
34 |
35 | public var hashValue: Int {
36 | return uuid.hashValue
37 | }
38 |
39 | public var debugDescription: String {
40 | return friendlyName
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/Stated/DSL/TransitionFromStateWithMapDSL.swift:
--------------------------------------------------------------------------------
1 | public struct TransitionFromStateWithMap {
2 | let transitionFromState: TransitionFromState
3 | let map: (StateFrom) -> MappedState
4 |
5 | public func to(_ to: StateSlot) -> StateTransitionTrigger
6 | where StateTo.Arguments == InputArguments, StateTo.MappedState == MappedState {
7 | let transition = transitionFromState.from._to(to, map: map)
8 | return StateTransitionTrigger(inputSlot: transitionFromState.input, transition: transition)
9 | }
10 | }
11 |
12 | ///
13 | /// Sugar for creating a mapped state transition e.g.
14 | /// An alias for `TransitionFromStateWithMap.to(_: toState)` to be used when mapping is required in order to construct the `toState`.
15 | /// ```
16 | /// anInput.given(fromState).transition(with: { $0.prop }).to(toState)
17 | /// ```
18 | /// Using operators you can get readable arrow structure
19 | /// ```
20 | /// anInput | fromState => { $0.prop } => toState
21 | /// ```
22 | ///
23 | public func => (
24 | transitionFromStateMap: TransitionFromStateWithMap,
25 | toState: StateSlot) -> StateTransitionTrigger
26 | where StateTo.Arguments == ArgumentsForToState {
27 | return transitionFromStateMap.to(toState)
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Stated/Transitions/StateTransitionTrigger.swift:
--------------------------------------------------------------------------------
1 | public class AnyStateTransitionTrigger {
2 | enum TransitionResult {
3 | case noMatch
4 | case triggered(arguments: Any, fromState: AnyState, toState: AnyState)
5 | }
6 |
7 | let inputUuid: String
8 | private let trigger: (Any, StateMachine) -> TransitionResult
9 |
10 | init(inputUuid: String, trigger: @escaping (Any, StateMachine) -> TransitionResult) {
11 | self.inputUuid = inputUuid
12 | self.trigger = trigger
13 | }
14 |
15 | func tryTransition(args: Any, stateMachine: StateMachine) -> TransitionResult {
16 | return trigger(args, stateMachine)
17 | }
18 | }
19 |
20 | public class StateTransitionTrigger: AnyStateTransitionTrigger where StateTo.Arguments == Arguments {
21 | let inputSlot: InputSlot
22 | let transition: StateTransition
23 |
24 | public init(inputSlot: InputSlot, transition: StateTransition) {
25 | self.inputSlot = inputSlot
26 | self.transition = transition
27 | super.init(inputUuid: inputSlot.uuid, trigger: { (args: Any, stateMachine: StateMachine) in
28 | guard stateMachine.currentState.stateId == transition.from.stateId else { return .noMatch }
29 | let typedArgs = args as! Arguments
30 |
31 | let (fromState, toState) = transition.trigger(withInput: typedArgs, stateMachine: stateMachine)
32 | return .triggered(arguments: args, fromState: fromState, toState: toState)
33 | })
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/Sources/Stated/Transitions/StateTransitionTriggerWithSideEffect.swift:
--------------------------------------------------------------------------------
1 | public struct SentInput: Equatable, CustomDebugStringConvertible {
2 | public let arguments: Arguments
3 | public let slot: InputSlot
4 |
5 | init(inputSlot: InputSlot, arguments: Arguments) {
6 | self.slot = inputSlot
7 | self.arguments = arguments
8 | }
9 |
10 | public static func ==(lhs: SentInput, rhs: SentInput) -> Bool {
11 | return lhs.slot.uuid == rhs.slot.uuid
12 | }
13 |
14 | public var debugDescription: String {
15 | return "Arguments: {\(arguments)} For: {\(slot)}"
16 | }
17 | }
18 |
19 | public func ==(lhs: SentInput, rhs: InputSlot) -> Bool {
20 | return lhs.slot.uuid == rhs.uuid
21 | }
22 |
23 | public class StateTransitionTriggerWithSideEffect: StateTransitionTrigger where StateTo.Arguments == Arguments {
24 | public let sideEffect: (StateMachine, StateTo, StateFrom, SentInput) -> Void
25 |
26 | public init(inputSlot: InputSlot, transition: StateTransition,
27 | sideEffect: @escaping (StateMachine, StateTo, StateFrom, SentInput) -> Void) {
28 | self.sideEffect = sideEffect
29 | super.init(inputSlot: inputSlot, transition: transition)
30 | }
31 |
32 | override func tryTransition(args: Any, stateMachine: StateMachine) -> TransitionResult {
33 | let result = super.tryTransition(args: args, stateMachine: stateMachine)
34 | switch result {
35 | case .noMatch:
36 | break
37 | case .triggered(let arguments, let fromState, let toState):
38 | let withArgs = SentInput(inputSlot: inputSlot, arguments: arguments as! Arguments)
39 | sideEffect(stateMachine, toState as! StateTo, fromState as! StateFrom, withArgs)
40 | }
41 | return result
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/Stated/DSL/InputSlotDSL.swift:
--------------------------------------------------------------------------------
1 |
2 | extension InputSlot {
3 | ///
4 | /// Define the current state the system must be in for a valid transition.
5 | /// For example a transition to `stateB` will occur when the system receives `goToB` and the current state is
6 | /// `stateA`.
7 | /// ```
8 | /// Inputs.goToB.given(States.stateA).transition(to: States.stateB)
9 | /// ```
10 | /// - parameter fromState: The current state constraint for the transition.
11 | ///
12 | public func given(_ fromState: StateSlot) -> TransitionFromState {
13 | return TransitionFromState(input: self, from: fromState)
14 | }
15 |
16 | ///
17 | /// Alias for `given`.
18 | ///
19 | /// Define the current state the system must be in for a valid transition.
20 | /// For example a transition to `stateB` will occur when the system receives `goToB` and the current state is
21 | /// `stateA`.
22 | /// ```
23 | /// Inputs.goToB.from(States.stateA).transition(to: States.stateB)
24 | /// ```
25 | /// - parameter fromState: The current state constraint for the transition.
26 | ///
27 | public func from(_ fromState: StateSlot) -> TransitionFromState {
28 | return given(fromState)
29 | }
30 | }
31 |
32 | ///
33 | /// Sugar for constructing a transition trigger given an input.
34 | /// This is an alias for `InputSlot.given` and `InputSlot.from`.
35 | /// ```
36 | /// anInput.given(fromState).transition(to: toState)
37 | /// ```
38 | /// Using operators you can get a table-like structure for easier reference:
39 | /// ```
40 | /// let triggerableStateTransition = anInput | fromState => toState
41 | /// ```
42 | ///
43 | public func |(
44 | input: InputSlot,
45 | fromState: StateSlot)
46 | -> TransitionFromState {
47 | return TransitionFromState(input: input, from: fromState)
48 | }
49 |
--------------------------------------------------------------------------------
/Sources/Stated/Machine/StateMachine.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public typealias StateMachineInput = (StateMachine) -> Void
4 |
5 | public class StateMachine {
6 | // MARK: Public
7 |
8 | ///
9 | /// Triggers when the current state changes
10 | ///
11 | public var onTransition: ((AnyState) -> Void)?
12 |
13 | // MARK: Internal
14 |
15 | let mappings: [AnyStateTransitionTrigger]
16 | let inputToTransitionTriggers: [String: [AnyStateTransitionTrigger]]
17 | private(set) var currentState: AnyState
18 |
19 | // MARK: Private
20 |
21 | private let lock = NSRecursiveLock()
22 |
23 | // MARK: Lifecycle
24 |
25 | public init(initialState: InitialState, mappings: [AnyStateTransitionTrigger]) {
26 | self.currentState = initialState
27 | self.mappings = mappings
28 |
29 | var inputToTransitionTriggers: [String: [AnyStateTransitionTrigger]] = [:]
30 | for transitionTrigger in mappings {
31 | var triggers = inputToTransitionTriggers[transitionTrigger.inputUuid] ?? []
32 | triggers.append(transitionTrigger)
33 | inputToTransitionTriggers[transitionTrigger.inputUuid] = triggers
34 | }
35 | self.inputToTransitionTriggers = inputToTransitionTriggers
36 | }
37 |
38 | // MARK: Public
39 |
40 | ///
41 | /// Send an input with arguments to trigger a state change.
42 | /// - warning: This will `fatalError` if a transition is not defined for the input + current state.
43 | /// - parameter input: Input with arguments. e.g. `anInput.withArgs(100)`
44 | ///
45 | public func send(_ input: StateMachineInput) {
46 | lock.lock(); defer { lock.unlock() }
47 | input(self)
48 | }
49 |
50 | ///
51 | /// Send an input that does not require arguments to trigger a state change.
52 | /// - warning: This will `fatalError` if a transition is not defined for the input + current state.
53 | /// - parameter input: Input without arguments.
54 | ///
55 | public func send(_ input: InputSlot) {
56 | send(input.withArgs(()))
57 | }
58 |
59 | ///
60 | /// Thread safe inspection of the current state of the system.
61 | /// - parameter inspect: A closure that has access to the current state.
62 | ///
63 | public func inspectCurrentState(inspect: (AnyState) -> Void) {
64 | lock.lock(); defer { lock.unlock() }
65 | inspect(currentState)
66 | }
67 |
68 | // MARK: Internal
69 |
70 | func setNextState(state: AnyState) {
71 | lock.lock(); defer { lock.unlock() }
72 | currentState = state
73 | onTransition?(currentState)
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Stated.xcodeproj/xcshareddata/xcschemes/Stated-watchOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
71 |
72 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Sources/Stated/DSL/TransitionFromStateDSL.swift:
--------------------------------------------------------------------------------
1 | infix operator =>: AdditionPrecedence
2 |
3 | ///
4 | /// Intermediary DSL object for constructing a transition given an input, current state and destination state.
5 | ///
6 | public struct TransitionFromState {
7 |
8 | // MARK: Public
9 |
10 | let input: InputSlot
11 | let from: StateSlot
12 |
13 | // MARK: Public
14 |
15 | public func transition(with map: @escaping (StateFrom) -> MappedState) -> TransitionFromStateWithMap {
16 | return TransitionFromStateWithMap(transitionFromState: self, map: map)
17 | }
18 |
19 | ///
20 | /// Alias for `transition(with:)`
21 | ///
22 | public func passes(_ map: @escaping (StateFrom) -> MappedState) -> TransitionFromStateWithMap {
23 | return transition(with: map)
24 | }
25 |
26 | public func transition(to: StateSlot) -> StateTransitionTrigger
27 | where StateTo.Arguments == InputArguments, StateTo.MappedState == Void {
28 |
29 | let map: (StateFrom) -> StateTo.MappedState = {_ in
30 | return ()
31 | }
32 |
33 | let transition = from._to(to, map: map)
34 | return StateTransitionTrigger(inputSlot: input, transition: transition)
35 | }
36 | }
37 |
38 |
39 | ///
40 | /// Sugar for creating a state transition e.g.
41 | /// An alias for `TransitionFromState.transition(to:)` to be used when mapping is not required.
42 | /// ```
43 | /// anInput.given(fromState).transition(to: toState)
44 | /// ```
45 | /// Using operators you can get readable arrow structure
46 | /// ```
47 | /// anInput | fromState => toState
48 | /// ```
49 | ///
50 | public func => (
51 | transitionFromState: TransitionFromState,
52 | toState: StateSlot) -> StateTransitionTrigger
53 | where StateTo.Arguments == ArgumentsForToState, StateTo.MappedState == Void {
54 | return transitionFromState.transition(to: toState)
55 | }
56 |
57 | ///
58 | /// Sugar for creating a mapped state transition e.g.
59 | /// An alias for `TransitionFromState.transition(with: { $0.prop })` to be used when mapping is required in order to construct the `toState`.
60 | /// ```
61 | /// anInput.given(fromState).transition(with: { $0.prop })
62 | /// ```
63 | /// Using operators you can get readable arrow structure
64 | /// ```
65 | /// anInput | fromState => { $0.prop }
66 | /// ```
67 | ///
68 | public func => (
69 | transitionFromState: TransitionFromState,
70 | map: @escaping (StateFrom) -> MappedState) -> TransitionFromStateWithMap {
71 | return transitionFromState.transition(with: map)
72 | }
73 |
--------------------------------------------------------------------------------
/Stated.xcodeproj/xcshareddata/xcschemes/Stated-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Stated.xcodeproj/xcshareddata/xcschemes/Stated-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Stated.xcodeproj/xcshareddata/xcschemes/Stated-macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Sources/Stated/DSL/StateTransitionTriggerDSL.swift:
--------------------------------------------------------------------------------
1 | extension StateTransitionTrigger {
2 | public func performingSideEffect(_ sideEffect: @escaping (StateMachine, StateTo, StateFrom, SentInput) -> Void) -> StateTransitionTriggerWithSideEffect {
3 | return StateTransitionTriggerWithSideEffect(
4 | inputSlot: self.inputSlot,
5 | transition: self.transition,
6 | sideEffect: sideEffect
7 | )
8 | }
9 |
10 | public func performingSideEffect(_ sideEffect: @escaping (StateMachine, StateTo, StateFrom) -> Void) -> StateTransitionTriggerWithSideEffect {
11 | return self.performingSideEffect { stateMachine, to, from, input in
12 | sideEffect(stateMachine, to, from)
13 | }
14 | }
15 |
16 | public func performingSideEffect(_ sideEffect: @escaping (StateMachine, StateTo) -> Void) -> StateTransitionTriggerWithSideEffect {
17 | return self.performingSideEffect { stateMachine, to, _, _ in
18 | sideEffect(stateMachine, to)
19 | }
20 | }
21 |
22 | public func performingSideEffect(_ sideEffect: @escaping (StateMachine) -> Void) -> StateTransitionTriggerWithSideEffect {
23 | return self.performingSideEffect { stateMachine, _, _, _ in
24 | sideEffect(stateMachine)
25 | }
26 | }
27 |
28 | public func performingSideEffect(_ sideEffect: @escaping () -> Void) -> StateTransitionTriggerWithSideEffect {
29 | return self.performingSideEffect { _, _, _, _ in
30 | sideEffect()
31 | }
32 | }
33 | }
34 |
35 | ///
36 | /// Sugar for performing a side effect when a state transition occurs.
37 | /// This is an alias for `StateTransitionTrigger.performingSideEffect`.
38 | /// ```
39 | /// anInput.given(fromState).transition(to: toState).performingSideEffect { stateMachine, toState, fromState, input in print("Side Effect") }
40 | /// ```
41 | /// Using operators you can get a table-like structure for easier reference:
42 | /// ```
43 | /// let triggerableStateTransition = anInput | fromState => toState | { stateMachine, toState, fromState, input in print("Side Effect") }
44 | /// ```
45 | ///
46 | public func |(
47 | stateTransitionTrigger: StateTransitionTrigger,
48 | sideEffect: @escaping (StateMachine, StateTo, StateFrom, SentInput) -> Void)
49 | -> StateTransitionTriggerWithSideEffect {
50 | return stateTransitionTrigger.performingSideEffect(sideEffect)
51 | }
52 |
53 | ///
54 | /// Sugar for performing a side effect when a state transition occurs.
55 | /// This is an alias for `StateTransitionTrigger.performingSideEffect`.
56 | /// ```
57 | /// anInput.given(fromState).transition(to: toState).performingSideEffect { stateMachine, toState, fromState in print("Side Effect") }
58 | /// ```
59 | /// Using operators you can get a table-like structure for easier reference:
60 | /// ```
61 | /// let triggerableStateTransition = anInput | fromState => toState | { stateMachine, toState, fromState in print("Side Effect") }
62 | /// ```
63 | ///
64 | public func |(
65 | stateTransitionTrigger: StateTransitionTrigger,
66 | sideEffect: @escaping (StateMachine, StateTo, StateFrom) -> Void)
67 | -> StateTransitionTriggerWithSideEffect {
68 | return stateTransitionTrigger.performingSideEffect(sideEffect)
69 | }
70 |
71 | ///
72 | /// Sugar for performing a side effect when a state transition occurs.
73 | /// This is an alias for `StateTransitionTrigger.performingSideEffect`.
74 | /// ```
75 | /// anInput.given(fromState).transition(to: toState).performingSideEffect { stateMachine, toState in print("Side Effect") }
76 | /// ```
77 | /// Using operators you can get a table-like structure for easier reference:
78 | /// ```
79 | /// let triggerableStateTransition = anInput | fromState => toState | { stateMachine, toState in print("Side Effect") }
80 | /// ```
81 | ///
82 | public func |(
83 | stateTransitionTrigger: StateTransitionTrigger,
84 | sideEffect: @escaping (StateMachine, StateTo) -> Void)
85 | -> StateTransitionTriggerWithSideEffect {
86 | return stateTransitionTrigger.performingSideEffect(sideEffect)
87 | }
88 |
89 | ///
90 | /// Sugar for performing a side effect when a state transition occurs.
91 | /// This is an alias for `StateTransitionTrigger.performingSideEffect`.
92 | /// ```
93 | /// anInput.given(fromState).transition(to: toState).performingSideEffect { stateMachine in print("Side Effect") }
94 | /// ```
95 | /// Using operators you can get a table-like structure for easier reference:
96 | /// ```
97 | /// let triggerableStateTransition = anInput | fromState => toState | { stateMachine in print("Side Effect") }
98 | /// ```
99 | ///
100 | public func |(
101 | stateTransitionTrigger: StateTransitionTrigger,
102 | sideEffect: @escaping (StateMachine) -> Void)
103 | -> StateTransitionTriggerWithSideEffect {
104 | return stateTransitionTrigger.performingSideEffect(sideEffect)
105 | }
106 |
107 | ///
108 | /// Sugar for performing a side effect when a state transition occurs.
109 | /// This is an alias for `StateTransitionTrigger.performingSideEffect`.
110 | /// ```
111 | /// anInput.given(fromState).transition(to: toState).performingSideEffect { print("Side Effect") }
112 | /// ```
113 | /// Using operators you can get a table-like structure for easier reference:
114 | /// ```
115 | /// let triggerableStateTransition = anInput | fromState => toState | { print("Side Effect") }
116 | /// ```
117 | ///
118 | public func |(
119 | stateTransitionTrigger: StateTransitionTrigger,
120 | sideEffect: @escaping () -> Void)
121 | -> StateTransitionTriggerWithSideEffect {
122 | return stateTransitionTrigger.performingSideEffect(sideEffect)
123 | }
124 |
--------------------------------------------------------------------------------
/Tests/StatedTests/InputArgsAndMappedStateTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import Stated
3 |
4 | class InputArgsAndMappedStateTests: XCTestCase {
5 |
6 | // MARK: Dummy business domain objects
7 |
8 | struct Account {
9 | let name: String
10 | }
11 |
12 | enum LaunchedFrom {
13 | case fresh
14 | case url(URL)
15 | }
16 |
17 | enum DeepLink {
18 | case viewPost
19 | case friendRequest
20 | }
21 |
22 | // MARK: Dummy business logic state machine
23 |
24 | class AppLauncher {
25 |
26 | // MARK: States
27 |
28 | public struct UninitializedState: SimpleState {
29 | public typealias Arguments = NoArguments
30 | public typealias MappedState = Void
31 | }
32 |
33 | struct InitializedState: StateTakingInput {
34 | typealias MappedState = Void
35 | typealias Arguments = LaunchedFrom
36 |
37 | let deepLink: DeepLink?
38 |
39 | static func create(arguments: LaunchedFrom) -> InitializedState {
40 | let deepLink: DeepLink?
41 | switch arguments {
42 | case .fresh:
43 | deepLink = nil
44 | case .url:
45 | deepLink = DeepLink.viewPost
46 | }
47 | return InitializedState(deepLink: deepLink)
48 | }
49 | }
50 |
51 | struct LoggedInState: State {
52 | typealias MappedState = DeepLink?
53 | typealias Arguments = Account
54 |
55 | let deepLink: DeepLink?
56 | let account: Account
57 |
58 | static func create(arguments: Account, state: DeepLink?) -> LoggedInState {
59 | return LoggedInState(deepLink: state, account: arguments)
60 | }
61 | }
62 |
63 | public struct LoggedOutState: SimpleState {
64 | public typealias Arguments = NoArguments
65 | public typealias MappedState = Void
66 | }
67 |
68 | struct States {
69 | static let uninitialized = UninitializedState.slot
70 | static let initialized = InitializedState.slot
71 | static let loggedIn = LoggedInState.slot
72 | static let loggedOut = LoggedOutState.slot
73 | }
74 |
75 | struct Inputs {
76 | static let initialize = input("initialize", taking: LaunchedFrom.self)
77 | static let logIn = input("logIn", taking: Account.self)
78 | static let logOut = input("logOut")
79 | }
80 |
81 | // MARK: Private propteries
82 |
83 | var machine: StateMachine!
84 |
85 | // MARK: Lifecycle
86 | init(logOutOnceLoggedIn: Bool, accountName: String) {
87 | let mappings: [AnyStateTransitionTrigger] = [
88 | Inputs.initialize
89 | .given(States.uninitialized)
90 | .transition(to: States.initialized)
91 | .performingSideEffect { (stateMachine: StateMachine) in
92 | let account = Account(name: accountName)
93 | stateMachine.send(Inputs.logIn.withArgs(account))
94 | },
95 |
96 | Inputs.logIn
97 | .given(States.initialized)
98 | .transition(with: { previousState in return previousState.deepLink })
99 | .to(States.loggedIn)
100 | .performingSideEffect { (stateMachine: StateMachine) in
101 | if logOutOnceLoggedIn {
102 | stateMachine.send(Inputs.logOut)
103 | }
104 | },
105 |
106 | Inputs.logOut
107 | .given(States.loggedIn)
108 | .transition(to: States.loggedOut)
109 | ]
110 |
111 | machine = StateMachine(initialState: UninitializedState(), mappings: mappings)
112 | }
113 |
114 | // MARK: Internal methods
115 |
116 | func initialize(from: LaunchedFrom) {
117 | machine.send(Inputs.initialize.withArgs(from))
118 | }
119 | }
120 |
121 | func testInitalState() {
122 | let appLauncher = AppLauncher(logOutOnceLoggedIn: false, accountName: "")
123 | appLauncher.machine.inspectCurrentState { currentState in
124 | XCTAssert(currentState == AppLauncher.States.uninitialized)
125 | }
126 | }
127 |
128 | func testFinalStateWhenLoggedIn() {
129 | let appLauncher = AppLauncher(logOutOnceLoggedIn: false, accountName: "")
130 | appLauncher.initialize(from: .fresh)
131 |
132 | appLauncher.machine.inspectCurrentState { currentState in
133 | XCTAssert(currentState == AppLauncher.States.loggedIn)
134 | }
135 | }
136 |
137 | func testFinalStateWhenLoggedOut() {
138 | let appLauncher = AppLauncher(logOutOnceLoggedIn: true, accountName: "")
139 | appLauncher.initialize(from: .fresh)
140 |
141 | appLauncher.machine.inspectCurrentState { currentState in
142 | XCTAssert(currentState == AppLauncher.States.loggedOut)
143 | }
144 | }
145 |
146 | func testLocalStateReceivesInputArgumentsWhenLoggedInFromFresh() {
147 | let appLauncher = AppLauncher(logOutOnceLoggedIn: false, accountName: "Testing name")
148 | appLauncher.initialize(from: .fresh)
149 |
150 | appLauncher.machine.inspectCurrentState { currentState in
151 | XCTAssert(currentState == AppLauncher.States.loggedIn)
152 | let state = currentState as! AppLauncher.LoggedInState
153 | XCTAssertEqual(state.account.name, "Testing name")
154 | XCTAssertNil(state.deepLink)
155 | }
156 | }
157 |
158 | func testLocalStateIsMappedAndForwardedWhenLoggedInFromUrl() {
159 | let appLauncher = AppLauncher(logOutOnceLoggedIn: false, accountName: "Another name")
160 | appLauncher.initialize(from: .url(URL(fileURLWithPath: "")))
161 |
162 | appLauncher.machine.inspectCurrentState { currentState in
163 | XCTAssert(currentState == AppLauncher.States.loggedIn)
164 | let state = currentState as! AppLauncher.LoggedInState
165 | XCTAssertEqual(state.account.name, "Another name")
166 | XCTAssertEqual(state.deepLink, .viewPost)
167 | }
168 | }
169 |
170 | static var allTests = [
171 | ("testInitalState", testInitalState),
172 | ("testFinalStateWhenLoggedIn", testFinalStateWhenLoggedIn),
173 | ("testFinalStateWhenLoggedOut", testFinalStateWhenLoggedOut),
174 | ("testLocalStateReceivesInputArgumentsWhenLoggedInFromFresh", testLocalStateReceivesInputArgumentsWhenLoggedInFromFresh),
175 | ("testLocalStateIsMappedAndForwardedWhenLoggedInFromUrl", testLocalStateIsMappedAndForwardedWhenLoggedInFromUrl)
176 | ]
177 | }
178 |
--------------------------------------------------------------------------------
/Tests/StatedTests/SimpleStatedTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import Stated
3 |
4 | class SimpleStatedTests: XCTestCase {
5 | class AppLauncher {
6 |
7 | struct UninitializedState: SimpleState { }
8 | struct InitializedState: SimpleState { }
9 | struct UpgradingState: SimpleState { }
10 | struct IndexingState: SimpleState { }
11 | struct LoggedInState: SimpleState { }
12 | struct LoggedOutState: SimpleState { }
13 |
14 | struct States {
15 | static let uninitialized = UninitializedState.slot
16 | static let initialized = InitializedState.slot
17 | static let upgrading = UpgradingState.slot
18 | static let indexing = IndexingState.slot
19 | static let loggedIn = LoggedInState.slot
20 | static let loggedOut = LoggedOutState.slot
21 | }
22 |
23 | struct Inputs {
24 | static let initialize = input()
25 | static let upgrade = input()
26 | static let indexDatabase = input()
27 | static let logIn = input()
28 | static let logOut = input()
29 | }
30 |
31 | // MARK: Private propteries
32 |
33 | var machine: StateMachine!
34 |
35 | // MARK: Lifecycle
36 |
37 | init(isUpgradePending: Bool, canLogIn: Bool) {
38 | func initialize(stateMachine: StateMachine) {
39 | if isUpgradePending {
40 | stateMachine.send(Inputs.upgrade)
41 | } else {
42 | stateMachine.send(Inputs.indexDatabase)
43 | }
44 | }
45 |
46 | func upgrade(stateMachine: StateMachine) {
47 | stateMachine.send(Inputs.indexDatabase)
48 | }
49 |
50 | func indexDatabase(stateMachine: StateMachine) {
51 | if canLogIn {
52 | stateMachine.send(Inputs.logIn)
53 | } else {
54 | stateMachine.send(Inputs.logOut)
55 | }
56 | }
57 |
58 | func logIn(stateMachine: StateMachine) {
59 | stateMachine.send(Inputs.logOut)
60 | }
61 |
62 | let mappings: [AnyStateTransitionTrigger] = [
63 | /* Input | from => to | side effect */
64 | Inputs.initialize | States.uninitialized => States.initialized | initialize,
65 |
66 | Inputs.upgrade | States.initialized => States.upgrading | upgrade,
67 |
68 | Inputs.indexDatabase | States.upgrading => States.indexing | indexDatabase,
69 | Inputs.indexDatabase | States.initialized => States.indexing | indexDatabase,
70 |
71 | Inputs.logIn | States.indexing => States.loggedIn | logIn,
72 |
73 | Inputs.logOut | States.indexing => States.loggedOut,
74 | Inputs.logOut | States.loggedIn => States.loggedOut,
75 | ]
76 | machine = StateMachine(initialState: UninitializedState(), mappings: mappings)
77 | }
78 |
79 | // MARK: Internal methods
80 |
81 | func initialize() {
82 | machine.send(Inputs.initialize)
83 | }
84 | }
85 |
86 | func testInitalState() {
87 | let appLauncher = AppLauncher(isUpgradePending: true, canLogIn: true)
88 | appLauncher.machine.inspectCurrentState { currentState in
89 | XCTAssert(currentState == AppLauncher.States.uninitialized)
90 | }
91 | }
92 |
93 | func testFinalState() {
94 | let appLauncher = AppLauncher(isUpgradePending: true, canLogIn: true)
95 | appLauncher.initialize()
96 |
97 | appLauncher.machine.inspectCurrentState { currentState in
98 | XCTAssert(currentState == AppLauncher.States.loggedOut)
99 | }
100 | }
101 |
102 | func testVisitedStatesForUpgradingLoggedIn() {
103 | let appLauncher = AppLauncher(isUpgradePending: true, canLogIn: true)
104 |
105 | var visitedStateIds: [String] = []
106 | let expectedStateIds: [String] = [
107 | AppLauncher.States.initialized.stateId,
108 | AppLauncher.States.upgrading.stateId,
109 | AppLauncher.States.indexing.stateId,
110 | AppLauncher.States.loggedIn.stateId,
111 | AppLauncher.States.loggedOut.stateId,
112 | ]
113 |
114 | appLauncher.machine.onTransition = { currentState in
115 | visitedStateIds.append(currentState.stateId)
116 | }
117 | appLauncher.initialize()
118 | XCTAssertEqual(visitedStateIds, expectedStateIds)
119 | }
120 |
121 | func testVisitedStatesForUpgradingLoggedOut() {
122 | let appLauncher = AppLauncher(isUpgradePending: true, canLogIn: false)
123 |
124 | var visitedStateIds: [String] = []
125 | let expectedStateIds: [String] = [
126 | AppLauncher.States.initialized.stateId,
127 | AppLauncher.States.upgrading.stateId,
128 | AppLauncher.States.indexing.stateId,
129 | AppLauncher.States.loggedOut.stateId,
130 | ]
131 |
132 | appLauncher.machine.onTransition = { currentState in
133 | visitedStateIds.append(currentState.stateId)
134 | }
135 | appLauncher.initialize()
136 | XCTAssertEqual(visitedStateIds, expectedStateIds)
137 | }
138 |
139 | func testVisitedStatesForNonUpgradeLoggedIn() {
140 | let appLauncher = AppLauncher(isUpgradePending: false, canLogIn: true)
141 |
142 | var visitedStateIds: [String] = []
143 | let expectedStateIds: [String] = [
144 | AppLauncher.States.initialized.stateId,
145 | AppLauncher.States.indexing.stateId,
146 | AppLauncher.States.loggedIn.stateId,
147 | AppLauncher.States.loggedOut.stateId,
148 | ]
149 |
150 | appLauncher.machine.onTransition = { currentState in
151 | visitedStateIds.append(currentState.stateId)
152 | }
153 | appLauncher.initialize()
154 | XCTAssertEqual(visitedStateIds, expectedStateIds)
155 | }
156 |
157 | func testVisitedStatesForNonUpgradeLoggedOut() {
158 | let appLauncher = AppLauncher(isUpgradePending: false, canLogIn: false)
159 |
160 | var visitedStateIds: [String] = []
161 | let expectedStateIds: [String] = [
162 | AppLauncher.States.initialized.stateId,
163 | AppLauncher.States.indexing.stateId,
164 | AppLauncher.States.loggedOut.stateId,
165 | ]
166 |
167 | appLauncher.machine.onTransition = { currentState in
168 | visitedStateIds.append(currentState.stateId)
169 | }
170 | appLauncher.initialize()
171 | XCTAssertEqual(visitedStateIds, expectedStateIds)
172 | }
173 |
174 | static var allTests = [
175 | ("testInitalState", testInitalState),
176 | ("testFinalState", testFinalState),
177 | ("testVisitedStatesForUpgradingLoggedIn", testVisitedStatesForUpgradingLoggedIn),
178 | ("testVisitedStatesForNonUpgradeLoggedIn", testVisitedStatesForNonUpgradeLoggedIn),
179 | ("testVisitedStatesForNonUpgradeLoggedOut", testVisitedStatesForNonUpgradeLoggedOut)
180 | ]
181 | }
182 |
183 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Stated
2 | A simple state machine implementation with a beautiful DSL.
3 |
4 | State transitions cause effects that can send a new input to the state machine, errors can be represented by new states and inputs.
5 | Each state conforms to one of `State`, `SimpleState`, `StateTakingInput` or `StateUsingMappedState`. A state object can receive arguments from a defined input. It can also be passed anything from the previous state
6 |
7 | The DSL was inspired by [RxAutomaton](https://github.com/inamiy/RxAutomaton).
8 |
9 | [](https://travis-ci.org/jordanhamill/Stated)
10 | 
11 | [](https://github.com/Carthage/Carthage)
12 | 
13 |
14 | ## Example State Machine
15 |
16 | App delegates can very quickly become a real handful based on the different initial screens that can appear.
17 | Below we have an app that has:
18 | - A Database Migration phase for updating local data.
19 | - A Database Indexing phase that shows a spinner. Useful if your app stores a large amount of local data.
20 | - Logged in state that shows the main `UIViewController`.
21 | - Logged out state that shows a login/signup `UIViewController`.
22 |
23 | ```swift
24 | import Stated
25 |
26 | class AppLauncher {
27 |
28 | // MARK: Create some simple states that hold no data.
29 |
30 | struct UninitializedState: SimpleState { }
31 | struct InitializedState: SimpleState { }
32 | struct UpgradingState: SimpleState { }
33 | struct IndexingState: SimpleState { }
34 | struct LoggedInState: SimpleState { }
35 | struct LoggedOutState: SimpleState { }
36 |
37 | // MARK: Define the states we're going to use by creating "slots" in which the system can place a given instance of one of our states
38 |
39 | struct States {
40 | static let uninitialized = UninitializedState.slot
41 | static let initialized = InitializedState.slot
42 | static let upgrading = UpgradingState.slot
43 | static let indexing = IndexingState.slot
44 | static let loggedIn = LoggedInState.slot
45 | static let loggedOut = LoggedOutState.slot
46 | }
47 |
48 | // MARK: Define inputs that will be used to trigger transitions between the above states
49 |
50 | struct Inputs {
51 | static let initialize = input()
52 | static let upgrade = input()
53 | static let indexDatabase = input()
54 | static let logIn = input()
55 | static let logOut = input()
56 | }
57 |
58 | // MARK: Private propteries
59 |
60 | private var machine: StateMachine!
61 |
62 | // MARK: Lifecycle
63 |
64 | init(upgradeService: Upgrade, apiService: APIService, db: PersistenceService, rootViewController: RootViewController) {
65 |
66 | // MARK: Side Effects
67 |
68 | func initialize(stateMachine: StateMachine) {
69 | if upgradeService.isUpgradePending {
70 | stateMachine.send(Inputs.upgrade)
71 | } else {
72 | stateMachine.send(Inputs.indexDatabase)
73 | }
74 | }
75 |
76 | func upgrade(stateMachine: StateMachine) {
77 | rootViewController.showUpgradeProgressController(onCompletion: {
78 | stateMachine.send(Inputs.indexDatabase)
79 | })
80 | }
81 |
82 | func indexDatabase(stateMachine: StateMachine) {
83 | db.createSecondaryIndices(onCompletion: {
84 | if apiService.canLogIn {
85 | stateMachine.send(Inputs.logIn)
86 | } else {
87 | stateMachine.send(Inputs.logOut)
88 | }
89 | })
90 | }
91 |
92 | func logIn(stateMachine: StateMachine) {
93 | rootViewController.showLoggedInExperience(apiService: apiService, db: db, onLogOut: {
94 | stateMachine.send(Inputs.logOut)
95 | })
96 | }
97 |
98 | func logOut(stateMachine: StateMachine) {
99 | rootViewController.showLogInViewController(onLoggedIn: {
100 | stateMachine.send(Inputs.logIn)
101 | })
102 | }
103 |
104 | // MARK: Define state machine using the inputs, slots and side effects from above
105 |
106 | // This is the long-form syntax and is exactly equivalent to the operator syntax below
107 | let mappings: [AnyStateTransitionTrigger] = [
108 | Inputs.initialize
109 | .given(States.uninitialized)
110 | .transition(to: States.initialized)
111 | .performingSideEffect(initialize),
112 |
113 | Inputs.upgrade
114 | .given(States.initialized)
115 | .transition(to: States.upgrading)
116 | .performingSideEffect(upgrade),
117 |
118 | Inputs.indexDatabase
119 | .given(States.upgrading)
120 | .transition(to: States.indexing)
121 | .performingSideEffect(indexDatabase),
122 | Inputs.indexDatabase
123 | .given(States.initialized)
124 | .transition(to: States.indexing)
125 | .performingSideEffect(indexDatabase),
126 |
127 | Inputs.logIn
128 | .given(States.indexing)
129 | .transition(to: States.loggedIn)
130 | .performingSideEffect(logIn),
131 | Inputs.logIn
132 | .given(States.loggedOut)
133 | .transition(to: States.loggedIn)
134 | .performingSideEffect(logIn),
135 |
136 | Inputs.logOut
137 | .given(States.indexing)
138 | .transition(to: States.loggedOut),
139 | .performingSideEffect(logOut)
140 | Inputs.logOut
141 | .given(States.loggedIn)
142 | .transition(to: States.loggedOut)
143 | .performingSideEffect(logOut)
144 | ]
145 |
146 | // This is the shorter operator syntax and is exactly equivalent to the syntax above.
147 | // It is very easy to visualize how the system should behave in this case
148 | let mappings: [AnyStateTransitionTrigger] = [
149 | /* Input | from => to | side effect */
150 | Inputs.initialize | States.uninitialized => States.initialized | initialize,
151 |
152 | Inputs.upgrade | States.initialized => States.upgrading | upgrade,
153 |
154 | Inputs.indexDatabase | States.upgrading => States.indexing | indexDatabase,
155 | Inputs.indexDatabase | States.initialized => States.indexing | indexDatabase,
156 |
157 | Inputs.logIn | States.indexing => States.loggedIn | logIn,
158 |
159 | Inputs.logOut | States.indexing => States.loggedOut | logOut,
160 | Inputs.logOut | States.loggedIn => States.loggedOut | logOut,
161 | ]
162 | machine = StateMachine(initialState: UninitializedState(), mappings: mappings)
163 | }
164 |
165 | // MARK: Internal methods
166 |
167 | func initialize() {
168 | machine.send(Inputs.initialize)
169 | }
170 | }
171 | ```
172 |
173 | ## Installation
174 |
175 | ### Cocoapods
176 |
177 | Add Stated to your Podfile:
178 | ```
179 | source 'https://github.com/CocoaPods/Specs.git'
180 | platform :ios, '10.0'
181 | use_frameworks!
182 |
183 | target '' do
184 | pod 'Stated'
185 | end
186 | ```
187 |
188 | Run the following command:
189 | ```
190 | $ pod install
191 | ```
192 |
193 | ### Carthage
194 |
195 | Add Stated to your Cartfile:
196 | ```
197 | github "jordanhamill/Stated"
198 | ```
199 |
200 | Run the following command:
201 | ```
202 | $ carthage update
203 | ```
204 |
205 | ### Swift Package Manager
206 |
207 | Add Stated as a dependency to your `package.swift`
208 |
209 | ```
210 | dependencies: [
211 | .Package(url: "https://github.com/jordanhamill/Stated.git", majorVersion: 1)
212 | ]
213 | ```
214 |
--------------------------------------------------------------------------------
/Stated.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 47;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 52D6D9871BEFF229002C0205 /* Stated.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* Stated.framework */; };
11 | 72483DD91F82DC8E0028400B /* StateTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC61F82DC8E0028400B /* StateTransition.swift */; };
12 | 72483DDA1F82DC8E0028400B /* StateTransitionTrigger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC71F82DC8E0028400B /* StateTransitionTrigger.swift */; };
13 | 72483DDB1F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC81F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift */; };
14 | 72483DDC1F82DC8E0028400B /* InputSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCA1F82DC8E0028400B /* InputSlot.swift */; };
15 | 72483DDD1F82DC8E0028400B /* StateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCB1F82DC8E0028400B /* StateMachine.swift */; };
16 | 72483DDE1F82DC8E0028400B /* InputDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCD1F82DC8E0028400B /* InputDSL.swift */; };
17 | 72483DDF1F82DC8E0028400B /* InputSlotDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCE1F82DC8E0028400B /* InputSlotDSL.swift */; };
18 | 72483DE01F82DC8E0028400B /* StateTransitionTriggerDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCF1F82DC8E0028400B /* StateTransitionTriggerDSL.swift */; };
19 | 72483DE11F82DC8E0028400B /* TransitionFromStateDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD01F82DC8E0028400B /* TransitionFromStateDSL.swift */; };
20 | 72483DE21F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD11F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift */; };
21 | 72483DE31F82DC8E0028400B /* AnyState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD31F82DC8E0028400B /* AnyState.swift */; };
22 | 72483DE41F82DC8E0028400B /* SimpleState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD41F82DC8E0028400B /* SimpleState.swift */; };
23 | 72483DE51F82DC8E0028400B /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD51F82DC8E0028400B /* State.swift */; };
24 | 72483DE61F82DC8E0028400B /* StateSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD61F82DC8E0028400B /* StateSlot.swift */; };
25 | 72483DE71F82DC8E0028400B /* StateTakingInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD71F82DC8E0028400B /* StateTakingInput.swift */; };
26 | 72483DE81F82DC8E0028400B /* StateUsingMappedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD81F82DC8E0028400B /* StateUsingMappedState.swift */; };
27 | 72483DED1F82DD570028400B /* SimpleStatedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DE91F82DCD10028400B /* SimpleStatedTests.swift */; };
28 | 72483DEE1F82DD570028400B /* SimpleStatedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DE91F82DCD10028400B /* SimpleStatedTests.swift */; };
29 | 72483DEF1F82DD580028400B /* SimpleStatedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DE91F82DCD10028400B /* SimpleStatedTests.swift */; };
30 | 72483DF01F82DD730028400B /* InputArgsAndMappedStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DEA1F82DCD10028400B /* InputArgsAndMappedStateTests.swift */; };
31 | 72483DF11F82DD740028400B /* InputArgsAndMappedStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DEA1F82DCD10028400B /* InputArgsAndMappedStateTests.swift */; };
32 | 72483DF21F82DD740028400B /* InputArgsAndMappedStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DEA1F82DCD10028400B /* InputArgsAndMappedStateTests.swift */; };
33 | 72483DF31F82DE9E0028400B /* InputDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCD1F82DC8E0028400B /* InputDSL.swift */; };
34 | 72483DF41F82DE9E0028400B /* InputSlotDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCE1F82DC8E0028400B /* InputSlotDSL.swift */; };
35 | 72483DF51F82DE9E0028400B /* StateTransitionTriggerDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCF1F82DC8E0028400B /* StateTransitionTriggerDSL.swift */; };
36 | 72483DF61F82DE9E0028400B /* TransitionFromStateDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD01F82DC8E0028400B /* TransitionFromStateDSL.swift */; };
37 | 72483DF71F82DE9E0028400B /* TransitionFromStateWithMapDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD11F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift */; };
38 | 72483DF81F82DE9E0028400B /* InputDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCD1F82DC8E0028400B /* InputDSL.swift */; };
39 | 72483DF91F82DE9E0028400B /* InputSlotDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCE1F82DC8E0028400B /* InputSlotDSL.swift */; };
40 | 72483DFA1F82DE9E0028400B /* StateTransitionTriggerDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCF1F82DC8E0028400B /* StateTransitionTriggerDSL.swift */; };
41 | 72483DFB1F82DE9E0028400B /* TransitionFromStateDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD01F82DC8E0028400B /* TransitionFromStateDSL.swift */; };
42 | 72483DFC1F82DE9E0028400B /* TransitionFromStateWithMapDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD11F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift */; };
43 | 72483DFD1F82DE9F0028400B /* InputDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCD1F82DC8E0028400B /* InputDSL.swift */; };
44 | 72483DFE1F82DE9F0028400B /* InputSlotDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCE1F82DC8E0028400B /* InputSlotDSL.swift */; };
45 | 72483DFF1F82DE9F0028400B /* StateTransitionTriggerDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCF1F82DC8E0028400B /* StateTransitionTriggerDSL.swift */; };
46 | 72483E001F82DE9F0028400B /* TransitionFromStateDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD01F82DC8E0028400B /* TransitionFromStateDSL.swift */; };
47 | 72483E011F82DE9F0028400B /* TransitionFromStateWithMapDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD11F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift */; };
48 | 72483E021F82DEA20028400B /* InputSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCA1F82DC8E0028400B /* InputSlot.swift */; };
49 | 72483E031F82DEA30028400B /* InputSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCA1F82DC8E0028400B /* InputSlot.swift */; };
50 | 72483E041F82DEA30028400B /* InputSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCA1F82DC8E0028400B /* InputSlot.swift */; };
51 | 72483E051F82DEA80028400B /* AnyState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD31F82DC8E0028400B /* AnyState.swift */; };
52 | 72483E061F82DEA80028400B /* SimpleState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD41F82DC8E0028400B /* SimpleState.swift */; };
53 | 72483E071F82DEA80028400B /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD51F82DC8E0028400B /* State.swift */; };
54 | 72483E081F82DEA80028400B /* StateSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD61F82DC8E0028400B /* StateSlot.swift */; };
55 | 72483E091F82DEA80028400B /* StateTakingInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD71F82DC8E0028400B /* StateTakingInput.swift */; };
56 | 72483E0A1F82DEA80028400B /* StateUsingMappedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD81F82DC8E0028400B /* StateUsingMappedState.swift */; };
57 | 72483E0B1F82DEA90028400B /* AnyState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD31F82DC8E0028400B /* AnyState.swift */; };
58 | 72483E0C1F82DEA90028400B /* SimpleState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD41F82DC8E0028400B /* SimpleState.swift */; };
59 | 72483E0D1F82DEA90028400B /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD51F82DC8E0028400B /* State.swift */; };
60 | 72483E0E1F82DEA90028400B /* StateSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD61F82DC8E0028400B /* StateSlot.swift */; };
61 | 72483E0F1F82DEA90028400B /* StateTakingInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD71F82DC8E0028400B /* StateTakingInput.swift */; };
62 | 72483E101F82DEA90028400B /* StateUsingMappedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD81F82DC8E0028400B /* StateUsingMappedState.swift */; };
63 | 72483E111F82DEA90028400B /* AnyState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD31F82DC8E0028400B /* AnyState.swift */; };
64 | 72483E121F82DEA90028400B /* SimpleState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD41F82DC8E0028400B /* SimpleState.swift */; };
65 | 72483E131F82DEA90028400B /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD51F82DC8E0028400B /* State.swift */; };
66 | 72483E141F82DEA90028400B /* StateSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD61F82DC8E0028400B /* StateSlot.swift */; };
67 | 72483E151F82DEA90028400B /* StateTakingInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD71F82DC8E0028400B /* StateTakingInput.swift */; };
68 | 72483E161F82DEA90028400B /* StateUsingMappedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DD81F82DC8E0028400B /* StateUsingMappedState.swift */; };
69 | 72483E171F82DEAD0028400B /* StateTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC61F82DC8E0028400B /* StateTransition.swift */; };
70 | 72483E181F82DEAD0028400B /* StateTransitionTrigger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC71F82DC8E0028400B /* StateTransitionTrigger.swift */; };
71 | 72483E191F82DEAD0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC81F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift */; };
72 | 72483E1A1F82DEAE0028400B /* StateTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC61F82DC8E0028400B /* StateTransition.swift */; };
73 | 72483E1B1F82DEAE0028400B /* StateTransitionTrigger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC71F82DC8E0028400B /* StateTransitionTrigger.swift */; };
74 | 72483E1C1F82DEAE0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC81F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift */; };
75 | 72483E1D1F82DEAE0028400B /* StateTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC61F82DC8E0028400B /* StateTransition.swift */; };
76 | 72483E1E1F82DEAE0028400B /* StateTransitionTrigger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC71F82DC8E0028400B /* StateTransitionTrigger.swift */; };
77 | 72483E1F1F82DEAE0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DC81F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift */; };
78 | 72483E201F82DEB10028400B /* StateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCB1F82DC8E0028400B /* StateMachine.swift */; };
79 | 72483E211F82DEB20028400B /* StateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCB1F82DC8E0028400B /* StateMachine.swift */; };
80 | 72483E221F82DEB20028400B /* StateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72483DCB1F82DC8E0028400B /* StateMachine.swift */; };
81 | DD7502881C68FEDE006590AF /* Stated.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6DA0F1BF000BD002C0205 /* Stated.framework */; };
82 | DD7502921C690C7A006590AF /* Stated.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D9F01BEFFFBE002C0205 /* Stated.framework */; };
83 | /* End PBXBuildFile section */
84 |
85 | /* Begin PBXContainerItemProxy section */
86 | 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */ = {
87 | isa = PBXContainerItemProxy;
88 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
89 | proxyType = 1;
90 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205;
91 | remoteInfo = Stated;
92 | };
93 | DD7502801C68FCFC006590AF /* PBXContainerItemProxy */ = {
94 | isa = PBXContainerItemProxy;
95 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
96 | proxyType = 1;
97 | remoteGlobalIDString = 52D6DA0E1BF000BD002C0205;
98 | remoteInfo = "Stated-macOS";
99 | };
100 | DD7502931C690C7A006590AF /* PBXContainerItemProxy */ = {
101 | isa = PBXContainerItemProxy;
102 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
103 | proxyType = 1;
104 | remoteGlobalIDString = 52D6D9EF1BEFFFBE002C0205;
105 | remoteInfo = "Stated-tvOS";
106 | };
107 | /* End PBXContainerItemProxy section */
108 |
109 | /* Begin PBXFileReference section */
110 | 52D6D97C1BEFF229002C0205 /* Stated.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Stated.framework; sourceTree = BUILT_PRODUCTS_DIR; };
111 | 52D6D9861BEFF229002C0205 /* Stated-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Stated-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
112 | 52D6D9E21BEFFF6E002C0205 /* Stated.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Stated.framework; sourceTree = BUILT_PRODUCTS_DIR; };
113 | 52D6D9F01BEFFFBE002C0205 /* Stated.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Stated.framework; sourceTree = BUILT_PRODUCTS_DIR; };
114 | 52D6DA0F1BF000BD002C0205 /* Stated.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Stated.framework; sourceTree = BUILT_PRODUCTS_DIR; };
115 | 72483DC61F82DC8E0028400B /* StateTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateTransition.swift; sourceTree = ""; };
116 | 72483DC71F82DC8E0028400B /* StateTransitionTrigger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateTransitionTrigger.swift; sourceTree = ""; };
117 | 72483DC81F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateTransitionTriggerWithSideEffect.swift; sourceTree = ""; };
118 | 72483DCA1F82DC8E0028400B /* InputSlot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputSlot.swift; sourceTree = ""; };
119 | 72483DCB1F82DC8E0028400B /* StateMachine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateMachine.swift; sourceTree = ""; };
120 | 72483DCD1F82DC8E0028400B /* InputDSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputDSL.swift; sourceTree = ""; };
121 | 72483DCE1F82DC8E0028400B /* InputSlotDSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputSlotDSL.swift; sourceTree = ""; };
122 | 72483DCF1F82DC8E0028400B /* StateTransitionTriggerDSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateTransitionTriggerDSL.swift; sourceTree = ""; };
123 | 72483DD01F82DC8E0028400B /* TransitionFromStateDSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionFromStateDSL.swift; sourceTree = ""; };
124 | 72483DD11F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionFromStateWithMapDSL.swift; sourceTree = ""; };
125 | 72483DD31F82DC8E0028400B /* AnyState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyState.swift; sourceTree = ""; };
126 | 72483DD41F82DC8E0028400B /* SimpleState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleState.swift; sourceTree = ""; };
127 | 72483DD51F82DC8E0028400B /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; };
128 | 72483DD61F82DC8E0028400B /* StateSlot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateSlot.swift; sourceTree = ""; };
129 | 72483DD71F82DC8E0028400B /* StateTakingInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateTakingInput.swift; sourceTree = ""; };
130 | 72483DD81F82DC8E0028400B /* StateUsingMappedState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateUsingMappedState.swift; sourceTree = ""; };
131 | 72483DE91F82DCD10028400B /* SimpleStatedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleStatedTests.swift; sourceTree = ""; };
132 | 72483DEA1F82DCD10028400B /* InputArgsAndMappedStateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputArgsAndMappedStateTests.swift; sourceTree = ""; };
133 | AD2FAA261CD0B6D800659CF4 /* Stated.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Stated.plist; sourceTree = ""; };
134 | AD2FAA281CD0B6E100659CF4 /* StatedTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = StatedTests.plist; sourceTree = ""; };
135 | DD75027A1C68FCFC006590AF /* Stated-macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Stated-macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
136 | DD75028D1C690C7A006590AF /* Stated-tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Stated-tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
137 | /* End PBXFileReference section */
138 |
139 | /* Begin PBXFrameworksBuildPhase section */
140 | 52D6D9781BEFF229002C0205 /* Frameworks */ = {
141 | isa = PBXFrameworksBuildPhase;
142 | buildActionMask = 2147483647;
143 | files = (
144 | );
145 | runOnlyForDeploymentPostprocessing = 0;
146 | };
147 | 52D6D9831BEFF229002C0205 /* Frameworks */ = {
148 | isa = PBXFrameworksBuildPhase;
149 | buildActionMask = 2147483647;
150 | files = (
151 | 52D6D9871BEFF229002C0205 /* Stated.framework in Frameworks */,
152 | );
153 | runOnlyForDeploymentPostprocessing = 0;
154 | };
155 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */ = {
156 | isa = PBXFrameworksBuildPhase;
157 | buildActionMask = 2147483647;
158 | files = (
159 | );
160 | runOnlyForDeploymentPostprocessing = 0;
161 | };
162 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */ = {
163 | isa = PBXFrameworksBuildPhase;
164 | buildActionMask = 2147483647;
165 | files = (
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | 52D6DA0B1BF000BD002C0205 /* Frameworks */ = {
170 | isa = PBXFrameworksBuildPhase;
171 | buildActionMask = 2147483647;
172 | files = (
173 | );
174 | runOnlyForDeploymentPostprocessing = 0;
175 | };
176 | DD7502771C68FCFC006590AF /* Frameworks */ = {
177 | isa = PBXFrameworksBuildPhase;
178 | buildActionMask = 2147483647;
179 | files = (
180 | DD7502881C68FEDE006590AF /* Stated.framework in Frameworks */,
181 | );
182 | runOnlyForDeploymentPostprocessing = 0;
183 | };
184 | DD75028A1C690C7A006590AF /* Frameworks */ = {
185 | isa = PBXFrameworksBuildPhase;
186 | buildActionMask = 2147483647;
187 | files = (
188 | DD7502921C690C7A006590AF /* Stated.framework in Frameworks */,
189 | );
190 | runOnlyForDeploymentPostprocessing = 0;
191 | };
192 | /* End PBXFrameworksBuildPhase section */
193 |
194 | /* Begin PBXGroup section */
195 | 52D6D9721BEFF229002C0205 = {
196 | isa = PBXGroup;
197 | children = (
198 | 8933C7811EB5B7E0000D00A4 /* Sources */,
199 | 8933C7831EB5B7EB000D00A4 /* Tests */,
200 | 52D6D99C1BEFF38C002C0205 /* Configs */,
201 | 52D6D97D1BEFF229002C0205 /* Products */,
202 | );
203 | sourceTree = "";
204 | };
205 | 52D6D97D1BEFF229002C0205 /* Products */ = {
206 | isa = PBXGroup;
207 | children = (
208 | 52D6D97C1BEFF229002C0205 /* Stated.framework */,
209 | 52D6D9861BEFF229002C0205 /* Stated-iOS Tests.xctest */,
210 | 52D6D9E21BEFFF6E002C0205 /* Stated.framework */,
211 | 52D6D9F01BEFFFBE002C0205 /* Stated.framework */,
212 | 52D6DA0F1BF000BD002C0205 /* Stated.framework */,
213 | DD75027A1C68FCFC006590AF /* Stated-macOS Tests.xctest */,
214 | DD75028D1C690C7A006590AF /* Stated-tvOS Tests.xctest */,
215 | );
216 | name = Products;
217 | sourceTree = "";
218 | };
219 | 52D6D99C1BEFF38C002C0205 /* Configs */ = {
220 | isa = PBXGroup;
221 | children = (
222 | DD7502721C68FC1B006590AF /* Frameworks */,
223 | DD7502731C68FC20006590AF /* Tests */,
224 | );
225 | path = Configs;
226 | sourceTree = "";
227 | };
228 | 72483DC51F82DC8E0028400B /* Transitions */ = {
229 | isa = PBXGroup;
230 | children = (
231 | 72483DC61F82DC8E0028400B /* StateTransition.swift */,
232 | 72483DC71F82DC8E0028400B /* StateTransitionTrigger.swift */,
233 | 72483DC81F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift */,
234 | );
235 | path = Transitions;
236 | sourceTree = "";
237 | };
238 | 72483DC91F82DC8E0028400B /* Inputs */ = {
239 | isa = PBXGroup;
240 | children = (
241 | 72483DCA1F82DC8E0028400B /* InputSlot.swift */,
242 | );
243 | path = Inputs;
244 | sourceTree = "";
245 | };
246 | 72483DCC1F82DC8E0028400B /* DSL */ = {
247 | isa = PBXGroup;
248 | children = (
249 | 72483DCD1F82DC8E0028400B /* InputDSL.swift */,
250 | 72483DCE1F82DC8E0028400B /* InputSlotDSL.swift */,
251 | 72483DCF1F82DC8E0028400B /* StateTransitionTriggerDSL.swift */,
252 | 72483DD01F82DC8E0028400B /* TransitionFromStateDSL.swift */,
253 | 72483DD11F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift */,
254 | );
255 | path = DSL;
256 | sourceTree = "";
257 | };
258 | 72483DD21F82DC8E0028400B /* States */ = {
259 | isa = PBXGroup;
260 | children = (
261 | 72483DD31F82DC8E0028400B /* AnyState.swift */,
262 | 72483DD41F82DC8E0028400B /* SimpleState.swift */,
263 | 72483DD51F82DC8E0028400B /* State.swift */,
264 | 72483DD61F82DC8E0028400B /* StateSlot.swift */,
265 | 72483DD71F82DC8E0028400B /* StateTakingInput.swift */,
266 | 72483DD81F82DC8E0028400B /* StateUsingMappedState.swift */,
267 | );
268 | path = States;
269 | sourceTree = "";
270 | };
271 | 72483E231F82DFDA0028400B /* Machine */ = {
272 | isa = PBXGroup;
273 | children = (
274 | 72483DCB1F82DC8E0028400B /* StateMachine.swift */,
275 | );
276 | path = Machine;
277 | sourceTree = "";
278 | };
279 | 8933C7811EB5B7E0000D00A4 /* Sources */ = {
280 | isa = PBXGroup;
281 | children = (
282 | 72483E231F82DFDA0028400B /* Machine */,
283 | 72483DCC1F82DC8E0028400B /* DSL */,
284 | 72483DC91F82DC8E0028400B /* Inputs */,
285 | 72483DD21F82DC8E0028400B /* States */,
286 | 72483DC51F82DC8E0028400B /* Transitions */,
287 | );
288 | name = Sources;
289 | path = Sources/Stated;
290 | sourceTree = "";
291 | };
292 | 8933C7831EB5B7EB000D00A4 /* Tests */ = {
293 | isa = PBXGroup;
294 | children = (
295 | 72483DEA1F82DCD10028400B /* InputArgsAndMappedStateTests.swift */,
296 | 72483DE91F82DCD10028400B /* SimpleStatedTests.swift */,
297 | );
298 | name = Tests;
299 | path = Tests/StatedTests;
300 | sourceTree = "";
301 | };
302 | DD7502721C68FC1B006590AF /* Frameworks */ = {
303 | isa = PBXGroup;
304 | children = (
305 | AD2FAA261CD0B6D800659CF4 /* Stated.plist */,
306 | );
307 | name = Frameworks;
308 | sourceTree = "";
309 | };
310 | DD7502731C68FC20006590AF /* Tests */ = {
311 | isa = PBXGroup;
312 | children = (
313 | AD2FAA281CD0B6E100659CF4 /* StatedTests.plist */,
314 | );
315 | name = Tests;
316 | sourceTree = "";
317 | };
318 | /* End PBXGroup section */
319 |
320 | /* Begin PBXHeadersBuildPhase section */
321 | 52D6D9791BEFF229002C0205 /* Headers */ = {
322 | isa = PBXHeadersBuildPhase;
323 | buildActionMask = 2147483647;
324 | files = (
325 | );
326 | runOnlyForDeploymentPostprocessing = 0;
327 | };
328 | 52D6D9DF1BEFFF6E002C0205 /* Headers */ = {
329 | isa = PBXHeadersBuildPhase;
330 | buildActionMask = 2147483647;
331 | files = (
332 | );
333 | runOnlyForDeploymentPostprocessing = 0;
334 | };
335 | 52D6D9ED1BEFFFBE002C0205 /* Headers */ = {
336 | isa = PBXHeadersBuildPhase;
337 | buildActionMask = 2147483647;
338 | files = (
339 | );
340 | runOnlyForDeploymentPostprocessing = 0;
341 | };
342 | 52D6DA0C1BF000BD002C0205 /* Headers */ = {
343 | isa = PBXHeadersBuildPhase;
344 | buildActionMask = 2147483647;
345 | files = (
346 | );
347 | runOnlyForDeploymentPostprocessing = 0;
348 | };
349 | /* End PBXHeadersBuildPhase section */
350 |
351 | /* Begin PBXNativeTarget section */
352 | 52D6D97B1BEFF229002C0205 /* Stated-iOS */ = {
353 | isa = PBXNativeTarget;
354 | buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Stated-iOS" */;
355 | buildPhases = (
356 | 52D6D9771BEFF229002C0205 /* Sources */,
357 | 52D6D9781BEFF229002C0205 /* Frameworks */,
358 | 52D6D9791BEFF229002C0205 /* Headers */,
359 | 52D6D97A1BEFF229002C0205 /* Resources */,
360 | );
361 | buildRules = (
362 | );
363 | dependencies = (
364 | );
365 | name = "Stated-iOS";
366 | productName = Stated;
367 | productReference = 52D6D97C1BEFF229002C0205 /* Stated.framework */;
368 | productType = "com.apple.product-type.framework";
369 | };
370 | 52D6D9851BEFF229002C0205 /* Stated-iOS Tests */ = {
371 | isa = PBXNativeTarget;
372 | buildConfigurationList = 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Stated-iOS Tests" */;
373 | buildPhases = (
374 | 52D6D9821BEFF229002C0205 /* Sources */,
375 | 52D6D9831BEFF229002C0205 /* Frameworks */,
376 | 52D6D9841BEFF229002C0205 /* Resources */,
377 | );
378 | buildRules = (
379 | );
380 | dependencies = (
381 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */,
382 | );
383 | name = "Stated-iOS Tests";
384 | productName = StatedTests;
385 | productReference = 52D6D9861BEFF229002C0205 /* Stated-iOS Tests.xctest */;
386 | productType = "com.apple.product-type.bundle.unit-test";
387 | };
388 | 52D6D9E11BEFFF6E002C0205 /* Stated-watchOS */ = {
389 | isa = PBXNativeTarget;
390 | buildConfigurationList = 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "Stated-watchOS" */;
391 | buildPhases = (
392 | 52D6D9DD1BEFFF6E002C0205 /* Sources */,
393 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */,
394 | 52D6D9DF1BEFFF6E002C0205 /* Headers */,
395 | 52D6D9E01BEFFF6E002C0205 /* Resources */,
396 | );
397 | buildRules = (
398 | );
399 | dependencies = (
400 | );
401 | name = "Stated-watchOS";
402 | productName = "Stated-watchOS";
403 | productReference = 52D6D9E21BEFFF6E002C0205 /* Stated.framework */;
404 | productType = "com.apple.product-type.framework";
405 | };
406 | 52D6D9EF1BEFFFBE002C0205 /* Stated-tvOS */ = {
407 | isa = PBXNativeTarget;
408 | buildConfigurationList = 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "Stated-tvOS" */;
409 | buildPhases = (
410 | 52D6D9EB1BEFFFBE002C0205 /* Sources */,
411 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */,
412 | 52D6D9ED1BEFFFBE002C0205 /* Headers */,
413 | 52D6D9EE1BEFFFBE002C0205 /* Resources */,
414 | );
415 | buildRules = (
416 | );
417 | dependencies = (
418 | );
419 | name = "Stated-tvOS";
420 | productName = "Stated-tvOS";
421 | productReference = 52D6D9F01BEFFFBE002C0205 /* Stated.framework */;
422 | productType = "com.apple.product-type.framework";
423 | };
424 | 52D6DA0E1BF000BD002C0205 /* Stated-macOS */ = {
425 | isa = PBXNativeTarget;
426 | buildConfigurationList = 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "Stated-macOS" */;
427 | buildPhases = (
428 | 52D6DA0A1BF000BD002C0205 /* Sources */,
429 | 52D6DA0B1BF000BD002C0205 /* Frameworks */,
430 | 52D6DA0C1BF000BD002C0205 /* Headers */,
431 | 52D6DA0D1BF000BD002C0205 /* Resources */,
432 | );
433 | buildRules = (
434 | );
435 | dependencies = (
436 | );
437 | name = "Stated-macOS";
438 | productName = "Stated-macOS";
439 | productReference = 52D6DA0F1BF000BD002C0205 /* Stated.framework */;
440 | productType = "com.apple.product-type.framework";
441 | };
442 | DD7502791C68FCFC006590AF /* Stated-macOS Tests */ = {
443 | isa = PBXNativeTarget;
444 | buildConfigurationList = DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "Stated-macOS Tests" */;
445 | buildPhases = (
446 | DD7502761C68FCFC006590AF /* Sources */,
447 | DD7502771C68FCFC006590AF /* Frameworks */,
448 | DD7502781C68FCFC006590AF /* Resources */,
449 | );
450 | buildRules = (
451 | );
452 | dependencies = (
453 | DD7502811C68FCFC006590AF /* PBXTargetDependency */,
454 | );
455 | name = "Stated-macOS Tests";
456 | productName = "Stated-OS Tests";
457 | productReference = DD75027A1C68FCFC006590AF /* Stated-macOS Tests.xctest */;
458 | productType = "com.apple.product-type.bundle.unit-test";
459 | };
460 | DD75028C1C690C7A006590AF /* Stated-tvOS Tests */ = {
461 | isa = PBXNativeTarget;
462 | buildConfigurationList = DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "Stated-tvOS Tests" */;
463 | buildPhases = (
464 | DD7502891C690C7A006590AF /* Sources */,
465 | DD75028A1C690C7A006590AF /* Frameworks */,
466 | DD75028B1C690C7A006590AF /* Resources */,
467 | );
468 | buildRules = (
469 | );
470 | dependencies = (
471 | DD7502941C690C7A006590AF /* PBXTargetDependency */,
472 | );
473 | name = "Stated-tvOS Tests";
474 | productName = "Stated-tvOS Tests";
475 | productReference = DD75028D1C690C7A006590AF /* Stated-tvOS Tests.xctest */;
476 | productType = "com.apple.product-type.bundle.unit-test";
477 | };
478 | /* End PBXNativeTarget section */
479 |
480 | /* Begin PBXProject section */
481 | 52D6D9731BEFF229002C0205 /* Project object */ = {
482 | isa = PBXProject;
483 | attributes = {
484 | LastSwiftUpdateCheck = 0720;
485 | LastUpgradeCheck = 0810;
486 | ORGANIZATIONNAME = "Jordan Hamill";
487 | TargetAttributes = {
488 | 52D6D97B1BEFF229002C0205 = {
489 | CreatedOnToolsVersion = 7.1;
490 | LastSwiftMigration = 0900;
491 | };
492 | 52D6D9851BEFF229002C0205 = {
493 | CreatedOnToolsVersion = 7.1;
494 | LastSwiftMigration = 0800;
495 | };
496 | 52D6D9E11BEFFF6E002C0205 = {
497 | CreatedOnToolsVersion = 7.1;
498 | LastSwiftMigration = 0800;
499 | };
500 | 52D6D9EF1BEFFFBE002C0205 = {
501 | CreatedOnToolsVersion = 7.1;
502 | LastSwiftMigration = 0800;
503 | };
504 | 52D6DA0E1BF000BD002C0205 = {
505 | CreatedOnToolsVersion = 7.1;
506 | LastSwiftMigration = 0800;
507 | };
508 | DD7502791C68FCFC006590AF = {
509 | CreatedOnToolsVersion = 7.2.1;
510 | LastSwiftMigration = 0800;
511 | };
512 | DD75028C1C690C7A006590AF = {
513 | CreatedOnToolsVersion = 7.2.1;
514 | LastSwiftMigration = 0800;
515 | };
516 | };
517 | };
518 | buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "Stated" */;
519 | compatibilityVersion = "Xcode 6.3";
520 | developmentRegion = English;
521 | hasScannedForEncodings = 0;
522 | knownRegions = (
523 | en,
524 | );
525 | mainGroup = 52D6D9721BEFF229002C0205;
526 | productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */;
527 | projectDirPath = "";
528 | projectRoot = "";
529 | targets = (
530 | 52D6D97B1BEFF229002C0205 /* Stated-iOS */,
531 | 52D6DA0E1BF000BD002C0205 /* Stated-macOS */,
532 | 52D6D9E11BEFFF6E002C0205 /* Stated-watchOS */,
533 | 52D6D9EF1BEFFFBE002C0205 /* Stated-tvOS */,
534 | 52D6D9851BEFF229002C0205 /* Stated-iOS Tests */,
535 | DD7502791C68FCFC006590AF /* Stated-macOS Tests */,
536 | DD75028C1C690C7A006590AF /* Stated-tvOS Tests */,
537 | );
538 | };
539 | /* End PBXProject section */
540 |
541 | /* Begin PBXResourcesBuildPhase section */
542 | 52D6D97A1BEFF229002C0205 /* Resources */ = {
543 | isa = PBXResourcesBuildPhase;
544 | buildActionMask = 2147483647;
545 | files = (
546 | );
547 | runOnlyForDeploymentPostprocessing = 0;
548 | };
549 | 52D6D9841BEFF229002C0205 /* Resources */ = {
550 | isa = PBXResourcesBuildPhase;
551 | buildActionMask = 2147483647;
552 | files = (
553 | );
554 | runOnlyForDeploymentPostprocessing = 0;
555 | };
556 | 52D6D9E01BEFFF6E002C0205 /* Resources */ = {
557 | isa = PBXResourcesBuildPhase;
558 | buildActionMask = 2147483647;
559 | files = (
560 | );
561 | runOnlyForDeploymentPostprocessing = 0;
562 | };
563 | 52D6D9EE1BEFFFBE002C0205 /* Resources */ = {
564 | isa = PBXResourcesBuildPhase;
565 | buildActionMask = 2147483647;
566 | files = (
567 | );
568 | runOnlyForDeploymentPostprocessing = 0;
569 | };
570 | 52D6DA0D1BF000BD002C0205 /* Resources */ = {
571 | isa = PBXResourcesBuildPhase;
572 | buildActionMask = 2147483647;
573 | files = (
574 | );
575 | runOnlyForDeploymentPostprocessing = 0;
576 | };
577 | DD7502781C68FCFC006590AF /* Resources */ = {
578 | isa = PBXResourcesBuildPhase;
579 | buildActionMask = 2147483647;
580 | files = (
581 | );
582 | runOnlyForDeploymentPostprocessing = 0;
583 | };
584 | DD75028B1C690C7A006590AF /* Resources */ = {
585 | isa = PBXResourcesBuildPhase;
586 | buildActionMask = 2147483647;
587 | files = (
588 | );
589 | runOnlyForDeploymentPostprocessing = 0;
590 | };
591 | /* End PBXResourcesBuildPhase section */
592 |
593 | /* Begin PBXSourcesBuildPhase section */
594 | 52D6D9771BEFF229002C0205 /* Sources */ = {
595 | isa = PBXSourcesBuildPhase;
596 | buildActionMask = 2147483647;
597 | files = (
598 | 72483DDE1F82DC8E0028400B /* InputDSL.swift in Sources */,
599 | 72483DDC1F82DC8E0028400B /* InputSlot.swift in Sources */,
600 | 72483DDB1F82DC8E0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */,
601 | 72483DE61F82DC8E0028400B /* StateSlot.swift in Sources */,
602 | 72483DE41F82DC8E0028400B /* SimpleState.swift in Sources */,
603 | 72483DE81F82DC8E0028400B /* StateUsingMappedState.swift in Sources */,
604 | 72483DD91F82DC8E0028400B /* StateTransition.swift in Sources */,
605 | 72483DDF1F82DC8E0028400B /* InputSlotDSL.swift in Sources */,
606 | 72483DE01F82DC8E0028400B /* StateTransitionTriggerDSL.swift in Sources */,
607 | 72483DDD1F82DC8E0028400B /* StateMachine.swift in Sources */,
608 | 72483DE21F82DC8E0028400B /* TransitionFromStateWithMapDSL.swift in Sources */,
609 | 72483DE51F82DC8E0028400B /* State.swift in Sources */,
610 | 72483DE11F82DC8E0028400B /* TransitionFromStateDSL.swift in Sources */,
611 | 72483DE31F82DC8E0028400B /* AnyState.swift in Sources */,
612 | 72483DE71F82DC8E0028400B /* StateTakingInput.swift in Sources */,
613 | 72483DDA1F82DC8E0028400B /* StateTransitionTrigger.swift in Sources */,
614 | );
615 | runOnlyForDeploymentPostprocessing = 0;
616 | };
617 | 52D6D9821BEFF229002C0205 /* Sources */ = {
618 | isa = PBXSourcesBuildPhase;
619 | buildActionMask = 2147483647;
620 | files = (
621 | 72483DF01F82DD730028400B /* InputArgsAndMappedStateTests.swift in Sources */,
622 | 72483DED1F82DD570028400B /* SimpleStatedTests.swift in Sources */,
623 | );
624 | runOnlyForDeploymentPostprocessing = 0;
625 | };
626 | 52D6D9DD1BEFFF6E002C0205 /* Sources */ = {
627 | isa = PBXSourcesBuildPhase;
628 | buildActionMask = 2147483647;
629 | files = (
630 | 72483E1C1F82DEAE0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */,
631 | 72483E031F82DEA30028400B /* InputSlot.swift in Sources */,
632 | 72483E0F1F82DEA90028400B /* StateTakingInput.swift in Sources */,
633 | 72483E211F82DEB20028400B /* StateMachine.swift in Sources */,
634 | 72483DFA1F82DE9E0028400B /* StateTransitionTriggerDSL.swift in Sources */,
635 | 72483E1B1F82DEAE0028400B /* StateTransitionTrigger.swift in Sources */,
636 | 72483DF91F82DE9E0028400B /* InputSlotDSL.swift in Sources */,
637 | 72483DFC1F82DE9E0028400B /* TransitionFromStateWithMapDSL.swift in Sources */,
638 | 72483E101F82DEA90028400B /* StateUsingMappedState.swift in Sources */,
639 | 72483DFB1F82DE9E0028400B /* TransitionFromStateDSL.swift in Sources */,
640 | 72483E0E1F82DEA90028400B /* StateSlot.swift in Sources */,
641 | 72483E0D1F82DEA90028400B /* State.swift in Sources */,
642 | 72483DF81F82DE9E0028400B /* InputDSL.swift in Sources */,
643 | 72483E0B1F82DEA90028400B /* AnyState.swift in Sources */,
644 | 72483E0C1F82DEA90028400B /* SimpleState.swift in Sources */,
645 | 72483E1A1F82DEAE0028400B /* StateTransition.swift in Sources */,
646 | );
647 | runOnlyForDeploymentPostprocessing = 0;
648 | };
649 | 52D6D9EB1BEFFFBE002C0205 /* Sources */ = {
650 | isa = PBXSourcesBuildPhase;
651 | buildActionMask = 2147483647;
652 | files = (
653 | 72483E1F1F82DEAE0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */,
654 | 72483E041F82DEA30028400B /* InputSlot.swift in Sources */,
655 | 72483E151F82DEA90028400B /* StateTakingInput.swift in Sources */,
656 | 72483E221F82DEB20028400B /* StateMachine.swift in Sources */,
657 | 72483DFF1F82DE9F0028400B /* StateTransitionTriggerDSL.swift in Sources */,
658 | 72483E1E1F82DEAE0028400B /* StateTransitionTrigger.swift in Sources */,
659 | 72483DFE1F82DE9F0028400B /* InputSlotDSL.swift in Sources */,
660 | 72483E011F82DE9F0028400B /* TransitionFromStateWithMapDSL.swift in Sources */,
661 | 72483E161F82DEA90028400B /* StateUsingMappedState.swift in Sources */,
662 | 72483E001F82DE9F0028400B /* TransitionFromStateDSL.swift in Sources */,
663 | 72483E141F82DEA90028400B /* StateSlot.swift in Sources */,
664 | 72483E131F82DEA90028400B /* State.swift in Sources */,
665 | 72483DFD1F82DE9F0028400B /* InputDSL.swift in Sources */,
666 | 72483E111F82DEA90028400B /* AnyState.swift in Sources */,
667 | 72483E121F82DEA90028400B /* SimpleState.swift in Sources */,
668 | 72483E1D1F82DEAE0028400B /* StateTransition.swift in Sources */,
669 | );
670 | runOnlyForDeploymentPostprocessing = 0;
671 | };
672 | 52D6DA0A1BF000BD002C0205 /* Sources */ = {
673 | isa = PBXSourcesBuildPhase;
674 | buildActionMask = 2147483647;
675 | files = (
676 | 72483E191F82DEAD0028400B /* StateTransitionTriggerWithSideEffect.swift in Sources */,
677 | 72483E021F82DEA20028400B /* InputSlot.swift in Sources */,
678 | 72483E091F82DEA80028400B /* StateTakingInput.swift in Sources */,
679 | 72483E201F82DEB10028400B /* StateMachine.swift in Sources */,
680 | 72483DF51F82DE9E0028400B /* StateTransitionTriggerDSL.swift in Sources */,
681 | 72483E181F82DEAD0028400B /* StateTransitionTrigger.swift in Sources */,
682 | 72483DF41F82DE9E0028400B /* InputSlotDSL.swift in Sources */,
683 | 72483DF71F82DE9E0028400B /* TransitionFromStateWithMapDSL.swift in Sources */,
684 | 72483E0A1F82DEA80028400B /* StateUsingMappedState.swift in Sources */,
685 | 72483DF61F82DE9E0028400B /* TransitionFromStateDSL.swift in Sources */,
686 | 72483E081F82DEA80028400B /* StateSlot.swift in Sources */,
687 | 72483E071F82DEA80028400B /* State.swift in Sources */,
688 | 72483DF31F82DE9E0028400B /* InputDSL.swift in Sources */,
689 | 72483E051F82DEA80028400B /* AnyState.swift in Sources */,
690 | 72483E061F82DEA80028400B /* SimpleState.swift in Sources */,
691 | 72483E171F82DEAD0028400B /* StateTransition.swift in Sources */,
692 | );
693 | runOnlyForDeploymentPostprocessing = 0;
694 | };
695 | DD7502761C68FCFC006590AF /* Sources */ = {
696 | isa = PBXSourcesBuildPhase;
697 | buildActionMask = 2147483647;
698 | files = (
699 | 72483DF11F82DD740028400B /* InputArgsAndMappedStateTests.swift in Sources */,
700 | 72483DEE1F82DD570028400B /* SimpleStatedTests.swift in Sources */,
701 | );
702 | runOnlyForDeploymentPostprocessing = 0;
703 | };
704 | DD7502891C690C7A006590AF /* Sources */ = {
705 | isa = PBXSourcesBuildPhase;
706 | buildActionMask = 2147483647;
707 | files = (
708 | 72483DF21F82DD740028400B /* InputArgsAndMappedStateTests.swift in Sources */,
709 | 72483DEF1F82DD580028400B /* SimpleStatedTests.swift in Sources */,
710 | );
711 | runOnlyForDeploymentPostprocessing = 0;
712 | };
713 | /* End PBXSourcesBuildPhase section */
714 |
715 | /* Begin PBXTargetDependency section */
716 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */ = {
717 | isa = PBXTargetDependency;
718 | target = 52D6D97B1BEFF229002C0205 /* Stated-iOS */;
719 | targetProxy = 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */;
720 | };
721 | DD7502811C68FCFC006590AF /* PBXTargetDependency */ = {
722 | isa = PBXTargetDependency;
723 | target = 52D6DA0E1BF000BD002C0205 /* Stated-macOS */;
724 | targetProxy = DD7502801C68FCFC006590AF /* PBXContainerItemProxy */;
725 | };
726 | DD7502941C690C7A006590AF /* PBXTargetDependency */ = {
727 | isa = PBXTargetDependency;
728 | target = 52D6D9EF1BEFFFBE002C0205 /* Stated-tvOS */;
729 | targetProxy = DD7502931C690C7A006590AF /* PBXContainerItemProxy */;
730 | };
731 | /* End PBXTargetDependency section */
732 |
733 | /* Begin XCBuildConfiguration section */
734 | 52D6D98E1BEFF229002C0205 /* Debug */ = {
735 | isa = XCBuildConfiguration;
736 | buildSettings = {
737 | ALWAYS_SEARCH_USER_PATHS = NO;
738 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
739 | CLANG_CXX_LIBRARY = "libc++";
740 | CLANG_ENABLE_MODULES = YES;
741 | CLANG_ENABLE_OBJC_ARC = YES;
742 | CLANG_WARN_BOOL_CONVERSION = YES;
743 | CLANG_WARN_CONSTANT_CONVERSION = YES;
744 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
745 | CLANG_WARN_EMPTY_BODY = YES;
746 | CLANG_WARN_ENUM_CONVERSION = YES;
747 | CLANG_WARN_INFINITE_RECURSION = YES;
748 | CLANG_WARN_INT_CONVERSION = YES;
749 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
750 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
751 | CLANG_WARN_UNREACHABLE_CODE = YES;
752 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
753 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
754 | COPY_PHASE_STRIP = NO;
755 | CURRENT_PROJECT_VERSION = 1;
756 | DEBUG_INFORMATION_FORMAT = dwarf;
757 | ENABLE_STRICT_OBJC_MSGSEND = YES;
758 | ENABLE_TESTABILITY = YES;
759 | GCC_C_LANGUAGE_STANDARD = gnu99;
760 | GCC_DYNAMIC_NO_PIC = NO;
761 | GCC_NO_COMMON_BLOCKS = YES;
762 | GCC_OPTIMIZATION_LEVEL = 0;
763 | GCC_PREPROCESSOR_DEFINITIONS = (
764 | "DEBUG=1",
765 | "$(inherited)",
766 | );
767 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
768 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
769 | GCC_WARN_UNDECLARED_SELECTOR = YES;
770 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
771 | GCC_WARN_UNUSED_FUNCTION = YES;
772 | GCC_WARN_UNUSED_VARIABLE = YES;
773 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
774 | MTL_ENABLE_DEBUG_INFO = YES;
775 | ONLY_ACTIVE_ARCH = YES;
776 | SDKROOT = iphoneos;
777 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
778 | SWIFT_VERSION = 3.0;
779 | TARGETED_DEVICE_FAMILY = "1,2";
780 | VERSIONING_SYSTEM = "apple-generic";
781 | VERSION_INFO_PREFIX = "";
782 | };
783 | name = Debug;
784 | };
785 | 52D6D98F1BEFF229002C0205 /* Release */ = {
786 | isa = XCBuildConfiguration;
787 | buildSettings = {
788 | ALWAYS_SEARCH_USER_PATHS = NO;
789 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
790 | CLANG_CXX_LIBRARY = "libc++";
791 | CLANG_ENABLE_MODULES = YES;
792 | CLANG_ENABLE_OBJC_ARC = YES;
793 | CLANG_WARN_BOOL_CONVERSION = YES;
794 | CLANG_WARN_CONSTANT_CONVERSION = YES;
795 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
796 | CLANG_WARN_EMPTY_BODY = YES;
797 | CLANG_WARN_ENUM_CONVERSION = YES;
798 | CLANG_WARN_INFINITE_RECURSION = YES;
799 | CLANG_WARN_INT_CONVERSION = YES;
800 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
801 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
802 | CLANG_WARN_UNREACHABLE_CODE = YES;
803 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
804 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
805 | COPY_PHASE_STRIP = NO;
806 | CURRENT_PROJECT_VERSION = 1;
807 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
808 | ENABLE_NS_ASSERTIONS = NO;
809 | ENABLE_STRICT_OBJC_MSGSEND = YES;
810 | GCC_C_LANGUAGE_STANDARD = gnu99;
811 | GCC_NO_COMMON_BLOCKS = YES;
812 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
813 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
814 | GCC_WARN_UNDECLARED_SELECTOR = YES;
815 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
816 | GCC_WARN_UNUSED_FUNCTION = YES;
817 | GCC_WARN_UNUSED_VARIABLE = YES;
818 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
819 | MTL_ENABLE_DEBUG_INFO = NO;
820 | SDKROOT = iphoneos;
821 | SWIFT_VERSION = 3.0;
822 | TARGETED_DEVICE_FAMILY = "1,2";
823 | VALIDATE_PRODUCT = YES;
824 | VERSIONING_SYSTEM = "apple-generic";
825 | VERSION_INFO_PREFIX = "";
826 | };
827 | name = Release;
828 | };
829 | 52D6D9911BEFF229002C0205 /* Debug */ = {
830 | isa = XCBuildConfiguration;
831 | buildSettings = {
832 | APPLICATION_EXTENSION_API_ONLY = YES;
833 | CLANG_ENABLE_MODULES = YES;
834 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
835 | DEFINES_MODULE = YES;
836 | DYLIB_COMPATIBILITY_VERSION = 1;
837 | DYLIB_CURRENT_VERSION = 1;
838 | DYLIB_INSTALL_NAME_BASE = "@rpath";
839 | INFOPLIST_FILE = Configs/Stated.plist;
840 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
841 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
842 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
843 | ONLY_ACTIVE_ARCH = NO;
844 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-iOS";
845 | PRODUCT_NAME = Stated;
846 | SKIP_INSTALL = YES;
847 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
848 | SWIFT_VERSION = 3.0;
849 | };
850 | name = Debug;
851 | };
852 | 52D6D9921BEFF229002C0205 /* Release */ = {
853 | isa = XCBuildConfiguration;
854 | buildSettings = {
855 | APPLICATION_EXTENSION_API_ONLY = YES;
856 | CLANG_ENABLE_MODULES = YES;
857 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
858 | DEFINES_MODULE = YES;
859 | DYLIB_COMPATIBILITY_VERSION = 1;
860 | DYLIB_CURRENT_VERSION = 1;
861 | DYLIB_INSTALL_NAME_BASE = "@rpath";
862 | INFOPLIST_FILE = Configs/Stated.plist;
863 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
864 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
865 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
866 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-iOS";
867 | PRODUCT_NAME = Stated;
868 | SKIP_INSTALL = YES;
869 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
870 | SWIFT_VERSION = 3.0;
871 | };
872 | name = Release;
873 | };
874 | 52D6D9941BEFF229002C0205 /* Debug */ = {
875 | isa = XCBuildConfiguration;
876 | buildSettings = {
877 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
878 | CLANG_ENABLE_MODULES = YES;
879 | INFOPLIST_FILE = Configs/StatedTests.plist;
880 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
881 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-iOS-Tests";
882 | PRODUCT_NAME = "$(TARGET_NAME)";
883 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
884 | SWIFT_VERSION = 3.0;
885 | };
886 | name = Debug;
887 | };
888 | 52D6D9951BEFF229002C0205 /* Release */ = {
889 | isa = XCBuildConfiguration;
890 | buildSettings = {
891 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
892 | CLANG_ENABLE_MODULES = YES;
893 | INFOPLIST_FILE = Configs/StatedTests.plist;
894 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
895 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-iOS-Tests";
896 | PRODUCT_NAME = "$(TARGET_NAME)";
897 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
898 | SWIFT_VERSION = 3.0;
899 | };
900 | name = Release;
901 | };
902 | 52D6D9E81BEFFF6E002C0205 /* Debug */ = {
903 | isa = XCBuildConfiguration;
904 | buildSettings = {
905 | APPLICATION_EXTENSION_API_ONLY = YES;
906 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
907 | DEFINES_MODULE = YES;
908 | DYLIB_COMPATIBILITY_VERSION = 1;
909 | DYLIB_CURRENT_VERSION = 1;
910 | DYLIB_INSTALL_NAME_BASE = "@rpath";
911 | INFOPLIST_FILE = Configs/Stated.plist;
912 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
913 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
914 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-watchOS";
915 | PRODUCT_NAME = Stated;
916 | SDKROOT = watchos;
917 | SKIP_INSTALL = YES;
918 | SWIFT_VERSION = 3.0;
919 | TARGETED_DEVICE_FAMILY = 4;
920 | WATCHOS_DEPLOYMENT_TARGET = 2.0;
921 | };
922 | name = Debug;
923 | };
924 | 52D6D9E91BEFFF6E002C0205 /* Release */ = {
925 | isa = XCBuildConfiguration;
926 | buildSettings = {
927 | APPLICATION_EXTENSION_API_ONLY = YES;
928 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
929 | DEFINES_MODULE = YES;
930 | DYLIB_COMPATIBILITY_VERSION = 1;
931 | DYLIB_CURRENT_VERSION = 1;
932 | DYLIB_INSTALL_NAME_BASE = "@rpath";
933 | INFOPLIST_FILE = Configs/Stated.plist;
934 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
935 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
936 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-watchOS";
937 | PRODUCT_NAME = Stated;
938 | SDKROOT = watchos;
939 | SKIP_INSTALL = YES;
940 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
941 | SWIFT_VERSION = 3.0;
942 | TARGETED_DEVICE_FAMILY = 4;
943 | WATCHOS_DEPLOYMENT_TARGET = 2.0;
944 | };
945 | name = Release;
946 | };
947 | 52D6DA021BEFFFBE002C0205 /* Debug */ = {
948 | isa = XCBuildConfiguration;
949 | buildSettings = {
950 | APPLICATION_EXTENSION_API_ONLY = YES;
951 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
952 | DEFINES_MODULE = YES;
953 | DYLIB_COMPATIBILITY_VERSION = 1;
954 | DYLIB_CURRENT_VERSION = 1;
955 | DYLIB_INSTALL_NAME_BASE = "@rpath";
956 | INFOPLIST_FILE = Configs/Stated.plist;
957 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
958 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
959 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-tvOS";
960 | PRODUCT_NAME = Stated;
961 | SDKROOT = appletvos;
962 | SKIP_INSTALL = YES;
963 | SWIFT_VERSION = 3.0;
964 | TARGETED_DEVICE_FAMILY = 3;
965 | TVOS_DEPLOYMENT_TARGET = 9.0;
966 | };
967 | name = Debug;
968 | };
969 | 52D6DA031BEFFFBE002C0205 /* Release */ = {
970 | isa = XCBuildConfiguration;
971 | buildSettings = {
972 | APPLICATION_EXTENSION_API_ONLY = YES;
973 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
974 | DEFINES_MODULE = YES;
975 | DYLIB_COMPATIBILITY_VERSION = 1;
976 | DYLIB_CURRENT_VERSION = 1;
977 | DYLIB_INSTALL_NAME_BASE = "@rpath";
978 | INFOPLIST_FILE = Configs/Stated.plist;
979 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
980 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
981 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-tvOS";
982 | PRODUCT_NAME = Stated;
983 | SDKROOT = appletvos;
984 | SKIP_INSTALL = YES;
985 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
986 | SWIFT_VERSION = 3.0;
987 | TARGETED_DEVICE_FAMILY = 3;
988 | TVOS_DEPLOYMENT_TARGET = 9.0;
989 | };
990 | name = Release;
991 | };
992 | 52D6DA211BF000BD002C0205 /* Debug */ = {
993 | isa = XCBuildConfiguration;
994 | buildSettings = {
995 | APPLICATION_EXTENSION_API_ONLY = YES;
996 | CODE_SIGN_IDENTITY = "-";
997 | COMBINE_HIDPI_IMAGES = YES;
998 | DEFINES_MODULE = YES;
999 | DYLIB_COMPATIBILITY_VERSION = 1;
1000 | DYLIB_CURRENT_VERSION = 1;
1001 | DYLIB_INSTALL_NAME_BASE = "@rpath";
1002 | FRAMEWORK_VERSION = A;
1003 | INFOPLIST_FILE = Configs/Stated.plist;
1004 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1005 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
1006 | MACOSX_DEPLOYMENT_TARGET = 10.10;
1007 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-macOS";
1008 | PRODUCT_NAME = Stated;
1009 | SDKROOT = macosx;
1010 | SKIP_INSTALL = YES;
1011 | SWIFT_VERSION = 3.0;
1012 | };
1013 | name = Debug;
1014 | };
1015 | 52D6DA221BF000BD002C0205 /* Release */ = {
1016 | isa = XCBuildConfiguration;
1017 | buildSettings = {
1018 | APPLICATION_EXTENSION_API_ONLY = YES;
1019 | CODE_SIGN_IDENTITY = "-";
1020 | COMBINE_HIDPI_IMAGES = YES;
1021 | DEFINES_MODULE = YES;
1022 | DYLIB_COMPATIBILITY_VERSION = 1;
1023 | DYLIB_CURRENT_VERSION = 1;
1024 | DYLIB_INSTALL_NAME_BASE = "@rpath";
1025 | FRAMEWORK_VERSION = A;
1026 | INFOPLIST_FILE = Configs/Stated.plist;
1027 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1028 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
1029 | MACOSX_DEPLOYMENT_TARGET = 10.10;
1030 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-macOS";
1031 | PRODUCT_NAME = Stated;
1032 | SDKROOT = macosx;
1033 | SKIP_INSTALL = YES;
1034 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
1035 | SWIFT_VERSION = 3.0;
1036 | };
1037 | name = Release;
1038 | };
1039 | DD7502831C68FCFC006590AF /* Debug */ = {
1040 | isa = XCBuildConfiguration;
1041 | buildSettings = {
1042 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
1043 | CODE_SIGN_IDENTITY = "-";
1044 | COMBINE_HIDPI_IMAGES = YES;
1045 | INFOPLIST_FILE = Configs/StatedTests.plist;
1046 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
1047 | MACOSX_DEPLOYMENT_TARGET = 10.11;
1048 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-macOS-Tests";
1049 | PRODUCT_NAME = "$(TARGET_NAME)";
1050 | SDKROOT = macosx;
1051 | SWIFT_VERSION = 3.0;
1052 | };
1053 | name = Debug;
1054 | };
1055 | DD7502841C68FCFC006590AF /* Release */ = {
1056 | isa = XCBuildConfiguration;
1057 | buildSettings = {
1058 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
1059 | CODE_SIGN_IDENTITY = "-";
1060 | COMBINE_HIDPI_IMAGES = YES;
1061 | INFOPLIST_FILE = Configs/StatedTests.plist;
1062 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
1063 | MACOSX_DEPLOYMENT_TARGET = 10.11;
1064 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-macOS-Tests";
1065 | PRODUCT_NAME = "$(TARGET_NAME)";
1066 | SDKROOT = macosx;
1067 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
1068 | SWIFT_VERSION = 3.0;
1069 | };
1070 | name = Release;
1071 | };
1072 | DD7502961C690C7A006590AF /* Debug */ = {
1073 | isa = XCBuildConfiguration;
1074 | buildSettings = {
1075 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
1076 | INFOPLIST_FILE = Configs/StatedTests.plist;
1077 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
1078 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-tvOS-Tests";
1079 | PRODUCT_NAME = "$(TARGET_NAME)";
1080 | SDKROOT = appletvos;
1081 | SWIFT_VERSION = 3.0;
1082 | TVOS_DEPLOYMENT_TARGET = 9.1;
1083 | };
1084 | name = Debug;
1085 | };
1086 | DD7502971C690C7A006590AF /* Release */ = {
1087 | isa = XCBuildConfiguration;
1088 | buildSettings = {
1089 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
1090 | INFOPLIST_FILE = Configs/StatedTests.plist;
1091 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
1092 | PRODUCT_BUNDLE_IDENTIFIER = "com.Stated.Stated-tvOS-Tests";
1093 | PRODUCT_NAME = "$(TARGET_NAME)";
1094 | SDKROOT = appletvos;
1095 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
1096 | SWIFT_VERSION = 3.0;
1097 | TVOS_DEPLOYMENT_TARGET = 9.1;
1098 | };
1099 | name = Release;
1100 | };
1101 | /* End XCBuildConfiguration section */
1102 |
1103 | /* Begin XCConfigurationList section */
1104 | 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "Stated" */ = {
1105 | isa = XCConfigurationList;
1106 | buildConfigurations = (
1107 | 52D6D98E1BEFF229002C0205 /* Debug */,
1108 | 52D6D98F1BEFF229002C0205 /* Release */,
1109 | );
1110 | defaultConfigurationIsVisible = 0;
1111 | defaultConfigurationName = Release;
1112 | };
1113 | 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Stated-iOS" */ = {
1114 | isa = XCConfigurationList;
1115 | buildConfigurations = (
1116 | 52D6D9911BEFF229002C0205 /* Debug */,
1117 | 52D6D9921BEFF229002C0205 /* Release */,
1118 | );
1119 | defaultConfigurationIsVisible = 0;
1120 | defaultConfigurationName = Release;
1121 | };
1122 | 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Stated-iOS Tests" */ = {
1123 | isa = XCConfigurationList;
1124 | buildConfigurations = (
1125 | 52D6D9941BEFF229002C0205 /* Debug */,
1126 | 52D6D9951BEFF229002C0205 /* Release */,
1127 | );
1128 | defaultConfigurationIsVisible = 0;
1129 | defaultConfigurationName = Release;
1130 | };
1131 | 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "Stated-watchOS" */ = {
1132 | isa = XCConfigurationList;
1133 | buildConfigurations = (
1134 | 52D6D9E81BEFFF6E002C0205 /* Debug */,
1135 | 52D6D9E91BEFFF6E002C0205 /* Release */,
1136 | );
1137 | defaultConfigurationIsVisible = 0;
1138 | defaultConfigurationName = Release;
1139 | };
1140 | 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "Stated-tvOS" */ = {
1141 | isa = XCConfigurationList;
1142 | buildConfigurations = (
1143 | 52D6DA021BEFFFBE002C0205 /* Debug */,
1144 | 52D6DA031BEFFFBE002C0205 /* Release */,
1145 | );
1146 | defaultConfigurationIsVisible = 0;
1147 | defaultConfigurationName = Release;
1148 | };
1149 | 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "Stated-macOS" */ = {
1150 | isa = XCConfigurationList;
1151 | buildConfigurations = (
1152 | 52D6DA211BF000BD002C0205 /* Debug */,
1153 | 52D6DA221BF000BD002C0205 /* Release */,
1154 | );
1155 | defaultConfigurationIsVisible = 0;
1156 | defaultConfigurationName = Release;
1157 | };
1158 | DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "Stated-macOS Tests" */ = {
1159 | isa = XCConfigurationList;
1160 | buildConfigurations = (
1161 | DD7502831C68FCFC006590AF /* Debug */,
1162 | DD7502841C68FCFC006590AF /* Release */,
1163 | );
1164 | defaultConfigurationIsVisible = 0;
1165 | defaultConfigurationName = Release;
1166 | };
1167 | DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "Stated-tvOS Tests" */ = {
1168 | isa = XCConfigurationList;
1169 | buildConfigurations = (
1170 | DD7502961C690C7A006590AF /* Debug */,
1171 | DD7502971C690C7A006590AF /* Release */,
1172 | );
1173 | defaultConfigurationIsVisible = 0;
1174 | defaultConfigurationName = Release;
1175 | };
1176 | /* End XCConfigurationList section */
1177 | };
1178 | rootObject = 52D6D9731BEFF229002C0205 /* Project object */;
1179 | }
1180 |
--------------------------------------------------------------------------------