Skip to content

Commit

Permalink
📦 Rename to Swift Builder (#10)
Browse files Browse the repository at this point in the history
* Update README.md

* change package name to SwiftBuilder

* 📦 rename inline document

* 🧾 SwiftBuilder now have an associate readme

* ⚒ codecov xcode scheme name update

* 🦄 update readme badge icon
  • Loading branch information
ytyubox authored Aug 15, 2020
1 parent 52a3b53 commit d41bb87
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 129 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- name: Generate xcode project
run: swift package generate-xcodeproj --enable-code-coverage
- name: Generate xcode test report
run: xcodebuild -scheme FluentInterface-Package clean test
run: xcodebuild -scheme SwiftBuilder-Package clean test
- name: Codecov
uses: codecov/[email protected]
with:
Expand Down
12 changes: 6 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import PackageDescription

let package = Package(
name: "FluentInterface",
name: "SwiftBuilder",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "FluentInterface",
targets: ["FluentInterface"]),
name: "SwiftBuilder",
targets: ["SwiftBuilder"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
Expand All @@ -19,10 +19,10 @@ let package = Package(
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "FluentInterface",
name: "SwiftBuilder",
dependencies: []),
.testTarget(
name: "FluentInterfaceTests",
dependencies: ["FluentInterface"]),
name: "SwiftBuilderTests",
dependencies: ["SwiftBuilder"]),
]
)
36 changes: 16 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Fluent Interface
# SwiftBuilder

Fluent interface is a fast way to assign new value to the property of the object. Thanks to [Hsu Li-Heng](https://lihenghsu.com/) and his great article [利用 Swift 5.1 新功能實作 Fluent Interface 讓程式碼更易讀流暢!](https://www.appcoda.com.tw/fluent-interface/).
Swift Builder is a fast way to assign new value to the property of the object. Thanks to [Hsu Li-Heng](https://lihenghsu.com/) and his great article [利用 Swift 5.1 新功能實作 Fluent Interface 讓程式碼更易讀流暢!](https://www.appcoda.com.tw/fluent-interface/).

![Swift](https://github.com/ytyubox/fluentinterface/workflows/Swift/badge.svg) [![codecov](https://codecov.io/gh/ytyubox/fluentinterface/branch/master/graph/badge.svg)](https://codecov.io/gh/ytyubox/fluentinterface) [![Platform](https://img.shields.io/badge/platform-macos%20%7C%20ios%20%7C%20watchos%20%7C%20ipados%20%7C%20tvos-lightgrey)](https://github.com/ytyubox/Weak) [![Swift](https://img.shields.io/badge/Swift-5.1-orange.svg)](https://swift.org) [![Xcode](https://img.shields.io/badge/Xcode-11-blue.svg)](https://developer.apple.com/xcode) [![SPM](https://img.shields.io/badge/SPM-Compatible-blue)](https://swift.org/package-manager) [![MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT)
![Swift bulid](https://github.com/ytyubox/SwiftBulider/workflows/Swift/badge.svg) [![codecov](https://codecov.io/gh/ytyubox/SwiftBuilder/branch/master/graph/badge.svg)](https://codecov.io/gh/ytyubox/SwiftBuilder) [![Platform](https://img.shields.io/badge/platform-macos%20%7C%20ios%20%7C%20watchos%20%7C%20ipados%20%7C%20tvos-lightgrey)](https://github.com/ytyubox/SwiftBuilder) [![Swift](https://img.shields.io/badge/Swift-5.1-orange.svg)](https://swift.org) [![Xcode](https://img.shields.io/badge/Xcode-11-blue.svg)](https://developer.apple.com/xcode) [![SPM](https://img.shields.io/badge/SPM-Compatible-blue)](https://swift.org/package-manager) [![MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT)


## Key Concept of Fluent Interface
Expand Down Expand Up @@ -53,15 +53,19 @@ let person = Person()
.set(favoriteQuote: "I like turtles")
```

## In Swift 5.1
## After Swift 5.1

By the power of Dynamic Member Lookup in Swift 4.2, and it's followed up evolve feature, Key Path Member Lookup in Swift 5.1 we can acheive Fluent Interface, by the article of Hsu Li-Heng: [[利用 Swift 5.1 新功能實作 Fluent Interface 讓程式碼更易讀流暢!]](https://www.appcoda.com.tw/fluent-interface/). I Highly recommend reading through.


## How to use

```swift
import FluentInterface
// SwiftBuilderExport.swift
@_exported import struct SwiftBuilder.Builder
```

```swift
struct Point {
var x:Int
var y:Int
Expand All @@ -71,21 +75,13 @@ struct Point {
}
}

let point = Point()+
let point = Builder(Point())
.x(1)
.y(2)
.unwrappingSubject()
.build()
// point now have x:1 and y: 2
```

using operator
```swift
let point2 = Point()+
.x(1)
.y(2)-

```

## Requirements

* Swift 5.1
Expand All @@ -103,30 +99,30 @@ The [Swift Package Manager](https://swift.org/package-manager/) is a decentraliz
...
dependencies: [
...
.Package(url: "https://github.com/ytyubox/fluentinterface", from: "1.0.0"),
.Package(url: "https://github.com/ytyubox/SwiftBuilder", from: "2.0.0"),
],
targets: [
.target(
name: "...",
dependencies: ["FluentInterface"])
dependencies: ["SwiftBuilder"])
)
```

## Using your operator
We can using Customize by adopt the prefix and postfix operator as follow:

```swift
import FluentInterface
import SwiftBuilder

postfix operator >|
public postfix func >| <T>(lhs: T) -> FluentInterface<T> {
return lhs+
return Builder(lhs)
}

postfix operator |>

public postfix func |> <T>(lhs: FluentInterface<T>) -> T {
return lhs-
return lhs.build()
}
```

Expand Down
101 changes: 101 additions & 0 deletions Sources/SwiftBuilder/SwiftBuilder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/// [SwiftBuilder] Assign poperty within a wrapper
/// ## before
/// ```swift
/// let point: CGPoint = {
/// var point = CGPoint()
/// point.x = 1
/// return point
/// }()
/// ```
/// ## after
/// ```swift
/// let point = CGPoint()+
/// .x(1)-
/// ```
/// resource https://www.appcoda.com.tw/fluent-interface/
@dynamicMemberLookup public struct Builder<Subject> {
/// [SwiftBuilder] create a Builder for Subject
/// - Parameter subject: The object that was created
@inlinable
public init(_ subject: Subject) {
self.subject = subject
}

// typealias FISetter<Value> = ((Value) -> Builder<Subject>)

/// the Subject than builder build for
public let subject: Subject

// 因為要動到 subject 的屬性,所以 keyPath 的型別必須是 WritableKeyPath
// 回傳值是一個 Setter 方法
@inlinable
public subscript<Value>(dynamicMember keyPath: WritableKeyPath<Subject, Value>)
-> FISetter<Subject, Value> {

// var subject = self.subject

return FISetter(target: subject, keyPath: keyPath)
}

/// [SwiftBuilder] get the subject.
@inlinable
public func build() -> Subject {
subject
}
/// [SwiftBuilder] Quick way to touch subject and remain fluent interface
/// - Parameter handlel: A cloure to get the subject
@inlinable
public nonmutating func handlingSubject(_ handle:
(Subject) -> Void) -> Self {
handle(subject)
return self
}
/// [SwiftBuilder] Quick way to manipulate subject and remain fluent interface
/// - Parameter handle: A cloure to inout set subject
@inlinable
public nonmutating func manipulateSubjct(_ handle:
(inout Subject) -> Void) -> Self {
var subject = self.subject
handle(&subject)
return Builder(subject)
}
/// Returns a new builder, mapping subject value using the given
/// transformation.
///
/// Use this method when you need to transform the value of a `Builder`
/// instance when it represents a object. The following example transforms
/// the integer value to a string:
///
/// func getBuilder() -> Builder<Int> { /* ... */ }
///
/// let integerBuilder = getNextBuilder()
/// // integerBuilder.subject == 5
/// let stringBuilder = integerBuilder.map({ String($0) })
/// // stringBuilder.subject == "5"
///
/// - Parameter transform: A closure that takes the success value of this
/// instance.
/// - Returns: A `Result` instance with the result of evaluating `transform`
/// as the new success value if this instance represents a success.
@inlinable
public func map<T>(_ transformer: (Subject) throws -> T) rethrows -> Builder<T> {
return try Builder<T>(transformer(self.subject))
}
}

public struct FISetter<Target,Value> {
@inlinable
internal init(target: Target, keyPath: WritableKeyPath<Target, Value>) {
self.target = target
self.keyPath = keyPath
}

public let target:Target
public let keyPath: WritableKeyPath<Target,Value>
nonmutating
public func callAsFunction(_ newValue:Value) -> Builder<Target> {
var newTarget = target
newTarget[keyPath: keyPath] = newValue
return Builder(newTarget)
}
}
65 changes: 0 additions & 65 deletions Sources/fluentinterface/FluentInterface.swift

This file was deleted.

8 changes: 0 additions & 8 deletions Tests/FluentInterfaceTests/fluentinterfaceTests.swift

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
//
// CustomOperatorTests.swift
//
//
// Created by 游宗諭 on 2020/2/18.
//

import XCTest
import FluentInterface
import SwiftBuilder



postfix operator >|
public postfix func >| <T>(lhs: T) -> FluentInterface<T> {
return lhs+
public postfix func >| <T>(lhs: T) -> Builder<T> {
return Builder(lhs)
}

postfix operator |>

public postfix func |> <T>(lhs: FluentInterface<T>) -> T {
return lhs-
public postfix func |> <T>(lhs: Builder<T>) -> T {
return lhs.build()
}

class CustomOperatorTests:XCTestCase {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import XCTest
import FluentInterface
import SwiftBuilder

final class fluentinterfaceDataTests: XCTestCase {
func testFlentInterfaceWithData() {
final class SwiftBuilderDataTests: XCTestCase {
func testSwiftBuilderWithData() {
struct TargetData:Equatable {
var value = 0
}
Expand All @@ -12,13 +12,13 @@ final class fluentinterfaceDataTests: XCTestCase {
object.value = value
return object
}()
let objectNewWay = TargetData()+
let objectNewWay = Builder(TargetData())
.value(value)
.unwrappingSubject()
.build()
XCTAssertEqual(objectOLDWay, objectNewWay)
}

static var allTests = [
("testFlentInterfaceWithData", testFlentInterfaceWithData),
("testSwiftBuilderWithData", testSwiftBuilderWithData),
]
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import FluentInterface
import XCTest
import SwiftBuilder

class FluentinterfaceHandlerTests: XCTestCase {

Expand All @@ -10,9 +10,9 @@ class FluentinterfaceHandlerTests: XCTestCase {
int *= 2
}
}
let target = TestTarget()+
let target = Builder(TestTarget())
.handlingSubject{$0.doubleIt()}
.unwrappingSubject()
.build()

XCTAssertEqual(target.int, 2)
}
Expand All @@ -23,9 +23,9 @@ class FluentinterfaceHandlerTests: XCTestCase {
int *= 2
}
}
let target = TestTarget()+
let target = Builder(TestTarget())
.manipulateSubjct{$0.doubleIt()}
.unwrappingSubject()
.build()

XCTAssertEqual(target.int, 2)
}
Expand Down
Loading

0 comments on commit d41bb87

Please sign in to comment.