Skip to content

Commit

Permalink
Mutatingcopyable keypath (#41)
Browse files Browse the repository at this point in the history
* Added a method to MutatingCopyable to use a KeyPath instead of a closure

* Added mutating copyable unit tests

* grammar

---------

Co-authored-by: Bill Dunay <wdunay@wayfair.com>
Co-authored-by: Albert Bori <github@albertbori.com>
  • Loading branch information
3 people authored Dec 6, 2023
1 parent ea8bae3 commit bb6249a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 5 deletions.
28 changes: 23 additions & 5 deletions Sources/VSM/MutatingCopyable.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

/// Extend a value type with the ability to copy and mutate in a single line of code
/// Extend a value type with the ability to copy and mutate in a single line of code.
///
/// Example Usage
/// ```swift
Expand All @@ -11,19 +11,37 @@ import Foundation
/// // Save username
/// return self.copy(mutating: { $0.username = username })
/// }
///
/// // OR
///
/// func update(username newValue: String) -> Self {
/// // Save username
/// return self.copy(mutating: \.username, value: newValue)
/// }
/// }
/// ```
public protocol MutatingCopyable { }

public extension MutatingCopyable {

/// Creates a mutated copy of this type
///
/// - Parameter mutator: The function that mutates the copy of this type
/// - Returns: A mutated copy of this type
/// Creates a mutated copy of this type.
///
/// - Parameter mutator: The function that mutates the copy of this type.
/// - Returns: A mutated copy of this type.
func copy(mutating mutator: (inout Self) -> Void) -> Self {
var copy = self
mutator(&copy)
return copy
}

/// Creates a mutated copy of this type while simultaneously mutating the value at the provided KeyPath.
///
/// - Parameter keyPath: The KeyPath of the property you want to mutate. Please not that this property MUST be a `var` in order to change its value using this method.
/// - Parameter value: The new value you want set on the property.
/// - Returns: A mutated copy of this type.
func copy<T>(mutatingPath keyPath: WritableKeyPath<Self, T>, value: T) -> Self {
var copy = self
copy[keyPath: keyPath] = value
return copy
}
}
35 changes: 35 additions & 0 deletions Tests/VSMTests/MutatingCopyableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// MutatingCopyableTests.swift
//
//
// Created by Albert Bori on 12/6/23.
//

@testable import VSM
import XCTest

final class MutatingCopyableTests: XCTestCase {
struct Subject: MutatingCopyable {
var bar: String
var baz: Bool
}

func testMutatingCopyableClosure() {
let subject = Subject(bar: "old", baz: false)
let result = subject.copy {
$0.bar = "new"
$0.baz = true
}
XCTAssertEqual(result.bar, "new")
XCTAssertEqual(result.baz, true)
}

func testMutatingCopyableKeyPath() {
let subject = Subject(bar: "old", baz: false)
let result = subject
.copy(mutatingPath: \.bar, value: "new")
.copy(mutatingPath: \.baz, value: true)
XCTAssertEqual(result.bar, "new")
XCTAssertEqual(result.baz, true)
}
}

0 comments on commit bb6249a

Please sign in to comment.