Skip to content

Commit fc65c98

Browse files
committed
Closure.init()
0 parents  commit fc65c98

File tree

6 files changed

+171
-0
lines changed

6 files changed

+171
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

Package.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// swift-tools-version:5.5
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "Closure",
8+
products: [
9+
.library(
10+
name: "Closure",
11+
targets: ["Closure"]
12+
),
13+
],
14+
targets: [
15+
.target(
16+
name: "Closure",
17+
dependencies: []
18+
),
19+
.testTarget(
20+
name: "ClosureTests",
21+
dependencies: ["Closure"]
22+
),
23+
]
24+
)

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Closure
2+
3+
*Define and chain Closures with Inputs and Outputs*
4+
5+
6+
## Examples
7+
8+
**No Scoped State**
9+
```swift
10+
let noStateCount = Closure<String, String> { text in
11+
String(repeating: text, count: 4)
12+
}
13+
.then { string in
14+
Int(string) ?? 0
15+
}
16+
17+
18+
XCTAssertEqual(noStateCount.method("5"), 5555)
19+
XCTAssertEqual(noStateCount.method("5"), 5555)
20+
XCTAssertEqual(noStateCount.method("5"), 5555)
21+
```
22+
23+
**Scoped State**
24+
```swift
25+
let stateCount: Closure<String, Int> = Closure<String, String> {
26+
var count = 1
27+
28+
return { text in
29+
defer {
30+
count += 1
31+
}
32+
33+
return String(repeating: text, count: count)
34+
}
35+
}
36+
.then { string in
37+
Int(string) ?? 0
38+
}
39+
40+
XCTAssertEqual(stateCount.method("5"), 5)
41+
XCTAssertEqual(stateCount.method("5"), 55)
42+
XCTAssertEqual(stateCount.method("5"), 555)
43+
```

Sources/Closure/Closure.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/// A Struct that defines a Closure with a given Input and a given Output
2+
public struct Closure<Input, Output> {
3+
/// The Closure passed in during initialization
4+
public let method: (Input) -> Output
5+
6+
/// Initialize a Closure without any scoped state
7+
public init(
8+
_ closure: @escaping (Input) -> Output
9+
) {
10+
method = closure
11+
}
12+
13+
/// Initialize a Closure with potential scoped state
14+
public init(
15+
_ closure: () -> ((Input) -> Output)
16+
) {
17+
method = closure()
18+
}
19+
}
20+
21+
public extension Closure {
22+
/// Return Void as the final Output
23+
var toVoid: Closure<Input, Void> {
24+
Closure<Input, Void> { input in
25+
_ = method(input)
26+
27+
return ()
28+
}
29+
}
30+
31+
/// Chain another Closure with a NewOutput
32+
func then<NewOutput>(
33+
_ closure: @escaping (Output) -> NewOutput
34+
) -> Closure<Input, NewOutput> {
35+
Closure<Input, NewOutput> { input in
36+
closure(method(input))
37+
}
38+
}
39+
40+
/// Run the Closure with Input and a Completion Handler
41+
func run(
42+
input: Input,
43+
onCompletion onCompletionHandler: () -> Void = {}
44+
) -> Output {
45+
defer {
46+
onCompletionHandler()
47+
}
48+
return method(input)
49+
}
50+
}

Tests/ClosureTests/ClosureTests.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import XCTest
2+
@testable import Closure
3+
4+
final class ClosureTests: XCTestCase {
5+
func testClosure() throws {
6+
let noStateCount = Closure<String, String> { text in
7+
String(repeating: text, count: 4)
8+
}
9+
.then { string in
10+
Int(string) ?? 0
11+
}
12+
13+
14+
XCTAssertEqual(noStateCount.method("5"), 5555)
15+
XCTAssertEqual(noStateCount.method("5"), 5555)
16+
XCTAssertEqual(noStateCount.method("5"), 5555)
17+
}
18+
19+
func testStateClosure() throws {
20+
let stateCount: Closure<String, Int> = Closure<String, String> {
21+
var count = 1
22+
23+
return { text in
24+
defer {
25+
count += 1
26+
}
27+
28+
return String(repeating: text, count: count)
29+
}
30+
}
31+
.then { string in
32+
Int(string) ?? 0
33+
}
34+
35+
XCTAssertEqual(stateCount.method("5"), 5)
36+
XCTAssertEqual(stateCount.method("5"), 55)
37+
XCTAssertEqual(stateCount.method("5"), 555)
38+
}
39+
}

0 commit comments

Comments
 (0)