From e19c1176e0cc4ed49fd1296a9471f481fd2a676e Mon Sep 17 00:00:00 2001 From: Orkhan Alikhanov Date: Sat, 29 May 2021 20:46:40 +0400 Subject: [PATCH] Initial commit --- .gitignore | 6 ++ Package.swift | 15 ++++ README.md | 3 + Sources/ChainSwift/ChainSwift.swift | 52 +++++++++++++ Tests/ChainSwiftTests/ChainSwiftTests.swift | 86 +++++++++++++++++++++ Tests/ChainSwiftTests/XCTestManifests.swift | 9 +++ Tests/LinuxMain.swift | 7 ++ 7 files changed, 178 insertions(+) create mode 100644 .gitignore create mode 100644 Package.swift create mode 100644 README.md create mode 100644 Sources/ChainSwift/ChainSwift.swift create mode 100644 Tests/ChainSwiftTests/ChainSwiftTests.swift create mode 100644 Tests/ChainSwiftTests/XCTestManifests.swift create mode 100644 Tests/LinuxMain.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6cb6e6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +/.build +/.swiftpm +/Packages +/*.xcodeproj +xcuserdata/ diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..9d312f0 --- /dev/null +++ b/Package.swift @@ -0,0 +1,15 @@ +// swift-tools-version:5.3 + +import PackageDescription + +let package = Package( + name: "ChainSwift", + products: [ + .library(name: "ChainSwift", targets: ["ChainSwift"]), + ], + + targets: [ + .target(name: "ChainSwift", dependencies: []), + .testTarget(name: "ChainSwiftTests", dependencies: ["ChainSwift"]), + ] +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..753b103 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# ChainSwift + +A description of this package. diff --git a/Sources/ChainSwift/ChainSwift.swift b/Sources/ChainSwift/ChainSwift.swift new file mode 100644 index 0000000..9977595 --- /dev/null +++ b/Sources/ChainSwift/ChainSwift.swift @@ -0,0 +1,52 @@ +// +// Chain.swift +// ChainSwift +// +// Created by Orkhan Alikhanov on 5/29/21. +// + +@dynamicMemberLookup +public struct Chain { + public var ch: Base + + init(_ base: Base) { + self.ch = base + } + + public subscript(dynamicMember keyPath: WritableKeyPath) -> Callable { + Callable(ch, keyPath: keyPath) + } +} + +public class Callable { + var base: Base + var keyPath: WritableKeyPath + + init(_ base: Base, keyPath: WritableKeyPath) { + self.base = base + self.keyPath = keyPath + } + + @discardableResult + public func callAsFunction(_ value: T) -> Chain { + base[keyPath: keyPath] = value + return Chain(base) + } +} + +public protocol Chainable { + associatedtype ChainableBase + + static var ch: Chain.Type { get } + var ch: Chain { get } +} + +public extension Chainable { + static var ch: Chain.Type { + Chain.self + } + + var ch: Chain { + Chain(self) + } +} diff --git a/Tests/ChainSwiftTests/ChainSwiftTests.swift b/Tests/ChainSwiftTests/ChainSwiftTests.swift new file mode 100644 index 0000000..3174221 --- /dev/null +++ b/Tests/ChainSwiftTests/ChainSwiftTests.swift @@ -0,0 +1,86 @@ +import XCTest +import ChainSwift + +enum MyEnum { + case value1 + case value2 +} + +class MyClass { + var text = "" + var int = 0 + var myEnum: MyEnum = .value1 +} + +struct MyStruct { + var text = "" + var int = 0 + var myEnum: MyEnum = .value1 +} + +extension MyClass: Chainable { } +extension MyStruct: Chainable { } + + +/// Ensure compiles with NSObject +import Foundation +extension NSObject: Chainable { } + +final class ChainSwiftTests: XCTestCase { + func testClassWorks() { + let myClass = MyClass() + + XCTAssertEqual(myClass.text, "") + XCTAssertEqual(myClass.int, 0) + XCTAssertEqual(myClass.myEnum, .value1) + + myClass.ch + .text("It works") + .int(99) + .myEnum(.value2) + + XCTAssertEqual(myClass.text, "It works") + XCTAssertEqual(myClass.int, 99) + XCTAssertEqual(myClass.myEnum, .value2) + } + + func testTakingChValueWorks() { + let myClass = MyClass().ch + .text("It works") + .int(99) + .myEnum(.value2) + .ch + + XCTAssertEqual(myClass.text, "It works") + XCTAssertEqual(myClass.int, 99) + XCTAssertEqual(myClass.myEnum, .value2) + } + + func testStructWorks() { + let myStruct = MyStruct() + + XCTAssertEqual(myStruct.text, "") + XCTAssertEqual(myStruct.int, 0) + XCTAssertEqual(myStruct.myEnum, .value1) + + let updatedMyStruct = myStruct.ch + .text("It works") + .int(99) + .myEnum(.value2) + .ch + + XCTAssertEqual(myStruct.text, "") + XCTAssertEqual(myStruct.int, 0) + XCTAssertEqual(myStruct.myEnum, .value1) + + XCTAssertEqual(updatedMyStruct.text, "It works") + XCTAssertEqual(updatedMyStruct.int, 99) + XCTAssertEqual(updatedMyStruct.myEnum, .value2) + } + + static var allTests = [ + ("testClassWorks", testClassWorks), + ("testTakingChValueWorks", testTakingChValueWorks), + ("testStructWorks", testStructWorks), + ] +} diff --git a/Tests/ChainSwiftTests/XCTestManifests.swift b/Tests/ChainSwiftTests/XCTestManifests.swift new file mode 100644 index 0000000..7e08ac4 --- /dev/null +++ b/Tests/ChainSwiftTests/XCTestManifests.swift @@ -0,0 +1,9 @@ +import XCTest + +#if !canImport(ObjectiveC) +public func allTests() -> [XCTestCaseEntry] { + return [ + testCase(ChainSwiftTests.allTests), + ] +} +#endif diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..03c7eef --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest + +import ChainSwiftTests + +var tests = [XCTestCaseEntry]() +tests += ChainSwiftTests.allTests() +XCTMain(tests)