Merge pull request #5 from 0xLeif/develop

0.3.0 Release
This commit is contained in:
Zach Eriksen 2021-03-02 20:36:53 -06:00 committed by GitHub
commit e693d4dcc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 192 additions and 66 deletions

View File

@ -23,9 +23,14 @@ let package = Package(
name: "Chain", name: "Chain",
dependencies: [ dependencies: [
"E" "E"
]), ]
),
.testTarget( .testTarget(
name: "ChainTests", name: "ChainTests",
dependencies: ["Chain"]), dependencies: [
"E",
"Chain"
]
),
] ]
) )

View File

@ -13,62 +13,115 @@ public extension Chain {
func run( func run(
name: String? = nil, name: String? = nil,
input: Variable? = nil, input: Variable? = nil,
shouldFlattenOutput: Bool = false logging: Bool = false
) -> Variable { ) -> Variable {
var logInfo: String {
"[\(Date())] Chain\(name.map { " (\($0)) "} ?? ""):"
}
var output: Variable = .array([]) var output: Variable = .array([])
log(functionName: "run",
name: name,
logging: logging)
switch self { switch self {
case .end: case .end:
print("\(logInfo) End")
output = output.update { output = output.update {
.array($0 + [Variable.void]) .array($0 + [Variable.void])
} }
case .complete(let completion): case .complete(let completion):
print("\(logInfo) Complete")
output = output.update { output = output.update {
.array($0 + [completion?.run(input) ?? Variable.void]) .array($0 + [completion?.run(input) ?? Variable.void])
} }
case .link(let action, case .link(let action,
let next): let next):
print("\(logInfo) Link")
let actionOutput: Variable = action.run(input) ?? Variable.void let actionOutput: Variable = action.run(input) ?? Variable.void
output = output.update { output = output.update {
.array($0 + [actionOutput] + [next.run(name: name, input: actionOutput)]) .array($0 + [actionOutput] + [next.run(name: name,
input: actionOutput,
logging: logging)])
} }
case .background(let action, case .background(let action,
let next): let next):
print("\(logInfo) Background")
DispatchQueue.global().async { DispatchQueue.global().async {
let actionOutput: Variable = action.run(input) ?? Variable.void let actionOutput: Variable = action.run(input) ?? Variable.void
output = output.update {
.array($0 + [actionOutput])
}
DispatchQueue.main.async { DispatchQueue.main.async {
output = output.update { _ = next.run(name: name,
.array($0 + [next.run(name: name, input: actionOutput)]) input: actionOutput,
} logging: logging)
} }
} }
case .multi(let links): case .multi(let links):
print("\(logInfo) Multi")
output = output.update { output = output.update {
.array($0 + links.map { $0.run(name: name) }) .array($0 + links.map { $0.run(name: name,
logging: logging) })
} }
} }
// Flatten Output
if shouldFlattenOutput {
return output.flatten
}
return output return output
} }
func runHead(
name: String? = nil,
input: Variable? = nil,
logging: Bool = false
) -> Variable {
log(functionName: "runHead",
name: name,
logging: logging)
switch self {
case .end:
return .void
case .complete(let function):
return function?.run(input) ?? .void
case .background(let function, _):
return Chain.background(function, .end).run(name: name, input: input, logging: logging)
case .link(let function, _):
return function.run(input) ?? .void
case .multi(let chains):
return .array(chains.compactMap { $0.runHead(input: input) })
}
}
func dropHead() -> Chain? {
switch self {
case .end, .complete(_):
return nil
case .background(_, let next), .link(_, let next):
return next
case .multi(let chains):
guard !chains.isEmpty else {
return nil
}
return .multi(chains.compactMap { $0.dropHead() })
}
}
}
internal extension Chain {
func log(
functionName: String,
name: String?,
logging: Bool
) {
var logInfo: String {
"[\(Date())] Chain.\(functionName)\(name.map { " (\($0))"} ?? ""):"
}
if logging {
switch self {
case .end:
print("\(logInfo) End")
case .complete:
print("\(logInfo) Complete")
case .link:
print("\(logInfo) Link")
case .background:
print("\(logInfo) Background")
case .multi:
print("\(logInfo) Multi")
}
}
}
} }

View File

@ -1,4 +1,5 @@
import XCTest import XCTest
import E
@testable import Chain @testable import Chain
final class ChainTests: XCTestCase { final class ChainTests: XCTestCase {
@ -7,39 +8,51 @@ final class ChainTests: XCTestCase {
var isLooping = false var isLooping = false
let output = Chain.link( let output = Chain.link(
.void { print(0) }, .out {
print(0)
return 0
},
.link( .link(
.void { print(1) }, .out {
print(1)
return 1
},
.multi( .multi(
[ [
.background( .background(
.void { .void {
print("Loading...") print("Loading...")
sleep(5) sleep(1)
print("Loading Done!") print("Loading Done!")
isLooping = false isLooping = false
}, },
.complete(.void { .complete(
XCTAssertEqual(isLooping, false) .out {
}) XCTAssertEqual(isLooping, false)
return .string("Done Loading")
}
)
), ),
.link( .link(
.void { .out {
isLooping = true isLooping = true
while isLooping { } while isLooping { }
return .string("Done Looping")
}, },
.complete(.void { .complete(
text = "Hello, World!" .out {
}) text = "Hello, World!"
return "Complete"
}
)
) )
] ]
) )
) )
) )
.run(name: "ChainTests-testExample") .run(name: "ChainTests-testExample", logging: true)
XCTAssertEqual(text, "Hello, World!") XCTAssertEqual(text, "Hello, World!")
@ -54,33 +67,41 @@ final class ChainTests: XCTestCase {
func testOutput() { func testOutput() {
let output = Chain.link( let output = Chain.link(
.out { "First" }, .out { "First" },
.link( .in { .link(
print("Value: \($0)") .in {
}, .multi( print("Value: \($0)")
[ },
.multi([ .multi(
.end, [
.end, .multi(
.end [
]), .end,
.link(.out { .end,
"Link" .end
}, .link( ]
.out { "Last" }, ),
.complete(.inout { value in .link(
guard case .string(let value) = value else { .out { "Link" },
XCTFail() .link(
return .void .out { "Last" },
} .complete(
.inout { value in
return .string("\(value) !!!") guard case .string(let value) = value else {
}) XCTFail()
)) return .void
] }
))
return .string("\(value) !!!")
}
)
)
)
]
)
)
) )
.run(name: "ChainTests-testOutput", shouldFlattenOutput: true) .run(name: "ChainTests-testOutput", logging: true)
.flatten
guard case .array(let values) = output else { guard case .array(let values) = output else {
XCTFail() XCTFail()
@ -92,7 +113,54 @@ final class ChainTests: XCTestCase {
XCTAssertEqual(values.count, 8) XCTAssertEqual(values.count, 8)
} }
func testChainStep() {
let chain = Chain.link(
.out {
"First"
},
.link(
.inout {
.string("Value: \($0)")
},
.end
)
)
XCTAssertEqual(chain.run(logging: true).flatten, .array([.string("First"), .string("Value: string(\"First\")"), .void]))
XCTAssertEqual(chain.runHead(logging: true), .string("First"))
XCTAssertEqual(chain.dropHead()?.runHead(input: .float(3.14), logging: true), .string("Value: float(3.14)"))
}
func testBackgroundOutput() {
let chain = Chain.link(
.out {
"First"
},
.background(
.inout {
sleep(3)
return .string("Value: \($0)")
},
.complete(
.inout {
print("HERE: \($0)")
return "HERE"
}
)
)
)
XCTAssertEqual(chain.run(name: "chain.run", logging: true).flatten, .array([.string("First")]))
XCTAssertEqual(chain.runHead(name: "chain.runHead", logging: true), .string("First"))
XCTAssertEqual(chain.dropHead()?.runHead(name: "chain.dropHead()?.runHead", input: .float(3.14), logging: true), .array([]))
sleep(6)
}
static var allTests = [ static var allTests = [
("testExample", testExample), ("testExample", testExample),
("testOutput", testOutput),
("testChainStep", testChainStep),
("testBackgroundOutput", testBackgroundOutput)
] ]
} }