Skip to content

Commit

Permalink
Refactor code by separating event-only-driven Machine and `StateMac…
Browse files Browse the repository at this point in the history
…hine`.

- Add `Machine` (event-only-driven state machine).
- Add `Disposable` derived from ReactiveCocoa.
- Add Package.swift & change directory structure for Swift-Package-Manager.
  • Loading branch information
inamiy committed Dec 5, 2015
1 parent 2986012 commit f7ce748
Show file tree
Hide file tree
Showing 43 changed files with 2,061 additions and 1,393 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ DerivedData
*.xcuserstate

Carthage/Build
.build
Packages/
13 changes: 13 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// Package.swift
// SwiftState
//
// Created by Yasuhiro Inami on 2015-12-05.
// Copyright © 2015 Yasuhiro Inami. All rights reserved.
//

import PackageDescription

let package = Package(
name: "SwiftState"
)
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ enum MyEvent: EventType {
let machine = StateMachine<MyState, MyEvent>(state: .State0) { machine in

// add 0 => 1 => 2
machine.addRouteEvent(.Event0, transitions: [
machine.addRoute(event: .Event0, transitions: [
.State0 => .State1,
.State1 => .State2,
])
Expand All @@ -89,9 +89,8 @@ machine <-! .Event0
XCTAssertEqual(machine.state, MyState.State2)

// tryEvent
let success = machine <-! .Event0
XCTAssertEqual(machine.state, MyState.State2)
XCTAssertFalse(success, "Event0 doesn't have 2 => Any")
machine <-! .Event0
XCTAssertEqual(machine.state, MyState.State2, "Event0 doesn't have 2 => Any")
```

If there is no `Event`-based transition, use built-in `NoEvent` instead.
Expand Down Expand Up @@ -126,8 +125,9 @@ State Machine | `Machine` | State transition manager which c
Transition | `Transition` | `From-` and `to-` states represented as `.State1 => .State2`. Also, `.Any` can be used to represent _any state_.
Route | `Route` | `Transition` + `Condition`.
Condition | `Context -> Bool` | Closure for validating transition. If condition returns `false`, transition will fail and associated handlers will not be invoked.
Route Mapping | `(event: E?, fromState: S, userInfo: Any?) -> S?` | Another way of defining routes **using closure instead of transition arrows (`=>`)**. This is useful when state & event are enum with associated values. Return value (`S?`) means "preferred-toState", where passing `nil` means no routes available. See [#36](https://github.com/ReactKit/SwiftState/pull/36) for more info.
Handler | `Context -> Void` | Transition callback invoked after state has been changed.
Event Route Mapping | `(event: E?, fromState: S, userInfo: Any?) -> S?` | Another way of defining routes **using closure instead of transition arrows (`=>`)**. This is useful when state & event are enum with associated values. Return value (`S?`) means preferred-`toState`, where passing `nil` means no routes available. See [#36](https://github.com/ReactKit/SwiftState/pull/36) for more info.
State Route Mapping | `(fromState: S, userInfo: Any?) -> [S]?` | Another way of defining routes **using closure instead of transition arrows (`=>`)**. This is useful when state is enum with associated values. Return value (`[S]?`) means multiple `toState`s from single `fromState`. See [#36](https://github.com/ReactKit/SwiftState/pull/36) for more info.
Handler | `Context -> Void` | Transition callback invoked when state has been changed successfully.
Context | `(event: E?, fromState: S, toState: S, userInfo: Any?)` | Closure argument for `Condition` & `Handler`.
Chain | `TransitionChain` / `RouteChain` | Group of continuous routes represented as `.State1 => .State2 => .State3`

Expand Down
45 changes: 45 additions & 0 deletions Sources/Disposable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Disposable.swift
// ReactiveCocoa
//
// Created by Justin Spahr-Summers on 2014-06-02.
// Copyright (c) 2014 GitHub. All rights reserved.
//

//
// NOTE:
// This file is a partial copy from ReactiveCocoa v4.0.0-alpha.4 (removing `Atomic` dependency),
// which has not been taken out as microframework yet.
// https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2579
//
// Note that `ActionDisposable` also works as `() -> ()` wrapper to help suppressing warning:
// "Expression resolved to unused function", when returned function was not used.
//

/// Represents something that can be “disposed,” usually associated with freeing
/// resources or canceling work.
public protocol Disposable {
/// Whether this disposable has been disposed already.
var disposed: Bool { get }

func dispose()
}

/// A disposable that will run an action upon disposal.
public final class ActionDisposable: Disposable {
private var action: (() -> ())?

public var disposed: Bool {
return action == nil
}

/// Initializes the disposable to run the given action upon disposal.
public init(action: () -> ()) {
self.action = action
}

public func dispose() {
self.action?()
self.action = nil
}
}
62 changes: 62 additions & 0 deletions Sources/EventType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// EventType.swift
// SwiftState
//
// Created by Yasuhiro Inami on 2014/08/05.
// Copyright (c) 2014年 Yasuhiro Inami. All rights reserved.
//

public protocol EventType: Hashable {}

// MARK: Event

/// `EventType` wrapper for handling`.Any` event.
public enum Event<E: EventType>: Hashable
{
case Some(E)
case Any

public var value: E?
{
switch self {
case .Some(let x): return x
default: return nil
}
}

public var hashValue: Int
{
switch self {
case .Some(let x): return x.hashValue
case .Any: return _hashValueForAny
}
}
}

public func == <E: EventType>(lhs: Event<E>, rhs: Event<E>) -> Bool
{
switch (lhs, rhs) {
case let (.Some(x1), .Some(x2)) where x1 == x2:
return true
case (.Any, .Any):
return true
default:
return false
}
}

// MARK: NoEvent

/// Useful for creating StateMachine without events, i.e. `StateMachine<MyState, NoEvent>`.
public enum NoEvent: EventType
{
public var hashValue: Int
{
return 0
}
}

public func == (lhs: NoEvent, rhs: NoEvent) -> Bool
{
return true
}
File renamed without changes.
Loading

0 comments on commit f7ce748

Please sign in to comment.