Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Commit

Permalink
Add state-change-function support for syntax-sugar mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
inamiy committed Nov 25, 2016
1 parent 55f42c1 commit 3ac2a6f
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 4 deletions.
6 changes: 5 additions & 1 deletion RxAutomaton.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
1FA0AC461DE8AC2B007F01E0 /* StateFuncMappingSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FA0AC451DE8AC2B007F01E0 /* StateFuncMappingSpec.swift */; };
1FCAB4CD1DC7845200EA6EBF /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FCAB4CC1DC7845200EA6EBF /* RxCocoa.framework */; };
1FCAB4CF1DC7845700EA6EBF /* Pulsator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FCAB4CE1DC7845700EA6EBF /* Pulsator.framework */; };
1FCAB4D01DC784E400EA6EBF /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4822CC391D61961300783A77 /* RxSwift.framework */; };
Expand Down Expand Up @@ -73,6 +74,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
1FA0AC451DE8AC2B007F01E0 /* StateFuncMappingSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateFuncMappingSpec.swift; sourceTree = "<group>"; };
1FCAB4CC1DC7845200EA6EBF /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = RxCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1FCAB4CE1DC7845700EA6EBF /* Pulsator.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Pulsator.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1FCAB4E21DC7947400EA6EBF /* RxTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = RxTest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -200,8 +202,9 @@
children = (
4822CC3E1D61969C00783A77 /* Fixtures */,
4822CC301D6194FD00783A77 /* MappingSpec.swift */,
4822CC2F1D6194FD00783A77 /* AnyMappingSpec.swift */,
4822CC311D6194FD00783A77 /* NextMappingSpec.swift */,
4822CC2F1D6194FD00783A77 /* AnyMappingSpec.swift */,
1FA0AC451DE8AC2B007F01E0 /* StateFuncMappingSpec.swift */,
4822CC321D6194FD00783A77 /* StrategyLatestSpec.swift */,
4822CC331D6194FD00783A77 /* TerminatingSpec.swift */,
488738ED1D61689100BF70F4 /* Info.plist */,
Expand Down Expand Up @@ -439,6 +442,7 @@
buildActionMask = 2147483647;
files = (
4822CC351D6194FD00783A77 /* MappingSpec.swift in Sources */,
1FA0AC461DE8AC2B007F01E0 /* StateFuncMappingSpec.swift in Sources */,
4822CC401D61969C00783A77 /* Fixtures.swift in Sources */,
487BDE631D619D3200C86902 /* AnyMappingSpec.swift in Sources */,
487BDE6C1D61B03700C86902 /* NextMappingSpec.swift in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions Sources/Mapping+Helper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ public func | <State, Input: Equatable>(input: Input, transition: Transition<Sta
return { $0 == input } | transition
}

public func | <State, Input>(inputFunc: @escaping (Input) -> Bool, transition: @escaping (State) -> State) -> Automaton<State, Input>.Mapping
{
return { fromState, input in
if inputFunc(input) {
return transition(fromState)
}
else {
return nil
}
}
}

public func | <State, Input: Equatable>(input: Input, transition: @escaping (State) -> State) -> Automaton<State, Input>.Mapping
{
return { $0 == input } | transition
}

// MARK: `|` (Automaton.NextMapping constructor)

public func | <State, Input>(mapping: @escaping Automaton<State, Input>.Mapping, nextInputProducer: Observable<Input>) -> Automaton<State, Input>.NextMapping
Expand Down
16 changes: 16 additions & 0 deletions Tests/Fixtures/Fixtures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import RxSwift
import RxAutomaton

// MARK: AuthState/Input

enum AuthState: String, CustomStringConvertible
{
case loggedOut
Expand All @@ -33,6 +35,20 @@ enum AuthInput: String, CustomStringConvertible
var description: String { return self.rawValue }
}

// MARK: CountState/Input

typealias CountState = Int

enum CountInput: String, CustomStringConvertible
{
case increment
case decrement

var description: String { return self.rawValue }
}

// MARK: MyState/Input

enum MyState
{
case state0, state1, state2
Expand Down
52 changes: 52 additions & 0 deletions Tests/StateFuncMappingSpec.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// StateFuncMappingSpec.swift
// RxAutomaton
//
// Created by Yasuhiro Inami on 2016-11-26.
// Copyright © 2016 Yasuhiro Inami. All rights reserved.
//

import RxSwift
import RxTest
import RxAutomaton
import Quick
import Nimble

/// Tests for state-change function mapping.
class StateFuncMappingSpec: QuickSpec
{
override func spec()
{
describe("State-change function mapping") {

typealias Automaton = RxAutomaton.Automaton<CountState, CountInput>
typealias NextMapping = Automaton.NextMapping

let (signal, observer) = Observable<CountInput>.pipe()
var automaton: Automaton?

beforeEach {
let mappings: [Automaton.NextMapping] = [
.increment | { $0 + 1 } | .empty(),
.decrement | { $0 - 1 } | .empty(),
]

// strategy = `.merge`
automaton = Automaton(state: 0, input: signal, mapping: reduce(mappings), strategy: .merge)
}

it("`.increment` and `.decrement` succeed") {
expect(automaton?.state.value) == 0
observer.send(next: .increment)
expect(automaton?.state.value) == 1
observer.send(next: .increment)
expect(automaton?.state.value) == 2
observer.send(next: .decrement)
expect(automaton?.state.value) == 1
observer.send(next: .decrement)
expect(automaton?.state.value) == 0
}

}
}
}
3 changes: 0 additions & 3 deletions Tests/TerminatingSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,6 @@ class TerminatingSpec: QuickSpec
// `sendInput1And2AfterDelay` will automatically send `.input2` at this point.
testScheduler.advanceByInterval(2)

print(automaton?.state.value)
print(lastRepliesEvent)

// Last state & input should change.
expect(automaton?.state.value) == .state0
expect(lastReply?.input) == .input2
Expand Down

0 comments on commit 3ac2a6f

Please sign in to comment.