Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Workflow/Sources/AnyWorkflowConvertible.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,17 @@ extension AnyWorkflowConvertible where Output == Never {
return rendered(in: context, key: key)
}
}

extension AnyWorkflowConvertible {
/// Process an `Output`
///
/// - Parameter apply: On `Output`, mutate `State` as necessary and return new `Output` (or `nil`).
public func onOutput<Parent>(_ apply: @escaping ((inout Parent.State, Output) -> Parent.Output?)) -> AnyWorkflow<Rendering, AnyWorkflowAction<Parent>> {
return asAnyWorkflow()
.mapOutput { output in
AnyWorkflowAction { state -> Parent.Output? in
apply(&state, output)
}
}
}
}
54 changes: 54 additions & 0 deletions Workflow/Tests/AnyWorkflowTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ public class AnyWorkflowTests: XCTestCase {

XCTAssertEqual(node.render(), "fdsadsa")
}

func testOnOutput() {
let host = WorkflowHost(workflow: OnOutputWorkflow())

let renderingExpectation = expectation(description: "Waiting for rendering")
host.rendering.producer.startWithValues { rendering in
if rendering {
renderingExpectation.fulfill()
}
}

let outputExpectation = expectation(description: "Waiting for output")
host.output.observeValues { output in
if output {
outputExpectation.fulfill()
}
}
wait(for: [renderingExpectation, outputExpectation], timeout: 1)
}
}

/// Has no state or output, simply renders a reversed string
Expand Down Expand Up @@ -70,3 +89,38 @@ extension SimpleWorkflow {
return String(string.reversed())
}
}

private struct OnOutputWorkflow: Workflow {
typealias State = Bool
typealias Rendering = Bool
typealias Output = Bool

func makeInitialState() -> Bool {
false
}

func workflowDidChange(from previousWorkflow: OnOutputWorkflow, state: inout Bool) {}

func render(state: State, context: RenderContext<OnOutputWorkflow>) -> Bool {
OnOutputChildWorkflow()
.onOutput { state, output in
state = output
return output
}
.running(in: context)
return state
}
}

private struct OnOutputChildWorkflow: Workflow {
typealias State = Void
typealias Output = Bool
typealias Rendering = Void

func render(state: Void, context: RenderContext<OnOutputChildWorkflow>) {
let sink = context.makeOutputSink()
DispatchQueue.main.async {
sink.send(true)
}
}
}