Swiftpack.co - Package - JosephDuffy/Partial

Partial

Build Status Documentation Compatible with macOS, iOS, watchOS, tvOS, and Linux SwiftPM Compatible Carthage Compatible CocoaPods Compatible MIT License

Partial is a type-safe wrapper that makes a type's properties optional, allowing for the type to be constructed with multiple pieces of code contributing values.

⚠️️ The current version of Partial is less than 1.0; the API may change and there may be bugs. Where possible types will be deprecated to aid with upgrades, although this cannot be guaranteed ️️⚠️

Installation

SwiftPM

To install via SwiftPM add the package to the dependencies section and as the dependency of a target:

let package = Package(
    ...
    dependencies: [
        .package(url: "https://github.com/JosephDuffy/Partial.git", from: "1.0.0"),
    ],
    targets: [
        .target(name: "MyApp", dependencies: ["Partial"]),
    ],
    ...
)

Carthage

To install via Carthage add to following to your Cartfile:

github "JosephDuffy/Partial"

Run carthage update Partial to build the framework and then drag the built framework file in to your Xcode project. Partial provides pre-compiled binaries, which can cause some issues with symbols. Use the --no-use-binaries flag if this is an issue.

Remember to add Partial to your Carthage build phase:

$(SRCROOT)/Carthage/Build/iOS/Partial.framework

and

$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Partial.framework

CocoaPods

To install via CocoaPods add the following line to your Podfile:

pod 'Partial'

and then run pod install.

Documentation

Partial is fully documented, with documentation available online. The online documentation is generated from the source code with every release, so it is up-to-date with the latest release, but may be different to the code in master.

Usage

Partial has a KeyPath-based API so is fully type-safe. Reading and writing of values is possible via subscripting, although functions are also provided.

var partialSize = Partial<CGSize>()
// Properties can be set via a function or subscript
partialSize.set(value: 6016, for: \.width)
partialSize[\.height] = 3384
// And unwrapped with a convenience function
let size = try partialSize.unwrappedValue() // A CGSize with width 6016, height 3384
// Properties can be retrieved via a function call
partialSize.value(for: \.width) // Optional(6016)
try partialSize.value(for: \.width) // 6016
// Properties can be removed via a function for the subscript
partialSize.removeValue(for: \.width)
partialSize[\.width] = nil

Swift 5.1 Features

⚠️️ Swift 5.1 is currently in beta, so these features may break and Partial may not work with future versions of the beta ⚠️

KeyPath-based dynamic member lookup is supported in Partial, allowing for properties to be read and set directly on the Partial or PartialBuilder instance. For example, the main example in Swift 5.1 would be:

var partialSize = Partial<CGSize>()
partialSize.width = 6016
partialSize.height = 3384
let size = try! partialSize.unwrappedValue() // A CGSize with width 6016, height 3384

Setting values

Values can be set via a subscript, or via the set(value:for:) function:


Building an instance with multiple pieces of code contributing values

Since Partial is a value type it is not suitable for being passed between multiple pieces of code. To allow for a single instance of a type to be constructed the PartialBuilder class is provided. PartialBuilder also provides the ability to be notified when properties are updated.

let sizeBuilder = PartialBuilder<CGSize>()
sizeBuilder.addUpdateListener { (partial: Partial<CGSize>) in
    print("A value was set")
}
sizeBuilder.addUpdateListener(for: .width) { newWidth in
    print("width has been updated to \(newWidth)")
}

func setWidth(on partial: PartialBuilder<CGSize>) {
    partial[\.width] = 6016
}

func setHeight(on partial: PartialBuilder<CGSize>) {
    partial[\.height] = 3384
}

// Notifies both update listeners
setWidth(on: sizeBuilder)

// Notifies first update listener
setHeight(on: sizeBuilder)

let size = try! sizeBuilder.unwrappedValue() // A CGSize with width 6016, height 3384

Adding support to your own types

Adopting the PartialConvertible protocol makes it easy to unwrap a partial value. The protocol has a single requirement:

public protocol PartialConvertible {
    init(partial: Partial<Self>) throws
}

For example, to add PartialConvertible conformance to a CGSize requires a single function with only a few lines of code:

extension CGSize: PartialConvertible {
    public init(partial: Partial<Self>) throws {
        let width = try partial.value(for: \.width)
        let height = try partial.value(for: \.height)
        self.init(width: width, height: height)
    }
}

As a convenience it's then possible to unwrap partial values that wrap a type that conforms to PartialConvertible:

let sizeBuilder = PartialBuilder<CGSize>()
// ...
let size = try! sizeBuilder.unwrappedValue()

License

The project is released under the MIT license. View the LICENSE file for the full license.

Github

link
Stars: 1
Help us keep the lights on

Used By

Total:

Releases

v0.1.1 - Jun 16, 2019

v0.1.0 - Jun 15, 2019

Initial release with Partial, PartialBuilder, and Swift 5.1 beta support