-
Notifications
You must be signed in to change notification settings - Fork 299
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f616817
commit 3bdd72e
Showing
5 changed files
with
168 additions
and
1 deletion.
There are no files selected for viewing
142 changes: 142 additions & 0 deletions
142
0087-the-case-for-case-paths-pt1/CasePath.playground/Contents.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import Foundation | ||
|
||
struct User { | ||
var id: Int | ||
let isAdmin: Bool | ||
var name: String | ||
} | ||
|
||
\User.id as WritableKeyPath<User, Int> | ||
\User.isAdmin as KeyPath<User, Bool> | ||
\User.name | ||
|
||
var user = User(id: 42, isAdmin: true, name: "Blob") | ||
|
||
user[keyPath: \.id] | ||
|
||
user[keyPath: \.id] = 57 | ||
|
||
user.id = 57 | ||
user.name = "Blob Jr." | ||
|
||
class Label: NSObject { | ||
@objc dynamic var font = "Helvetica" | ||
@objc dynamic var fontSize = 12 | ||
@objc dynamic var text = "" | ||
} | ||
|
||
class Model: NSObject { | ||
@objc dynamic var userName = "" | ||
} | ||
|
||
let model = Model() | ||
let label = Label() | ||
|
||
bind(model: model, \.userName, to: label, \.text) | ||
|
||
//bind(model: model, get: { $0.userName }, to: label, get: { $0.text }, set: { $0.text = $1 }) | ||
|
||
label.text | ||
model.userName = "blob" | ||
label.text | ||
model.userName = "XxFP_FANxX93" | ||
label.text | ||
|
||
import Combine | ||
|
||
let subject = PassthroughSubject<String, Never>() | ||
subject.assign(to: \.text, on: label) | ||
|
||
subject.send("MaTh_FaN96") | ||
label.text | ||
|
||
|
||
typealias Reducer<Value, Action> = (inout Value, Action) -> Void | ||
|
||
[1, 2, 3] | ||
.reduce(into: 0, { $0 += $1 }) | ||
[1, 2, 3] | ||
.reduce(into: 0, +=) | ||
|
||
|
||
func pullback<GlobalValue, LocalValue, Action>( | ||
_ reducer: @escaping Reducer<LocalValue, Action>, | ||
value: WritableKeyPath<GlobalValue, LocalValue> | ||
) -> Reducer<GlobalValue, Action> { | ||
|
||
return { globalValue, action in | ||
// var localValue = globalValue[keyPath: value] | ||
// reducer(&localValue, action) | ||
// globalValue[keyPath: value] = localValue | ||
reducer(&globalValue[keyPath: value], action) | ||
} | ||
} | ||
|
||
func pullback<GlobalValue, LocalValue, Action>( | ||
_ reducer: @escaping Reducer<LocalValue, Action>, | ||
getLocalValue: @escaping (GlobalValue) -> LocalValue, | ||
setLocalValue: @escaping (inout GlobalValue, LocalValue) -> Void | ||
) -> Reducer<GlobalValue, Action> { | ||
|
||
return { globalValue, action in | ||
var localValue = getLocalValue(globalValue) | ||
reducer(&localValue, action) | ||
setLocalValue(&globalValue, localValue) | ||
} | ||
} | ||
|
||
let counterReducer: Reducer<Int, Void> = { count, _ in count += 1 } | ||
|
||
pullback(counterReducer, value: \User.id) | ||
|
||
[1, 2, 3] | ||
.map(String.init) | ||
|
||
pullback( | ||
counterReducer, | ||
getLocalValue: { (user: User) in user.id }, | ||
setLocalValue: { $0.id = $1 } | ||
) | ||
|
||
|
||
struct _WritableKeyPath<Root, Value> { | ||
let get: (Root) -> Value | ||
let set: (inout Root, Value) -> Void | ||
} | ||
|
||
|
||
// [user valueForKeyPath:@"location.city"] | ||
|
||
struct CasePath<Root, Value> { | ||
let extract: (Root) -> Value? | ||
let embed: (Value) -> Root | ||
} | ||
|
||
extension Result { | ||
static var successCasePath: CasePath<Result, Success> { | ||
CasePath<Result, Success>( | ||
extract: { result -> Success? in | ||
if case let .success(value) = result { | ||
return value | ||
} | ||
return nil | ||
}, | ||
embed: Result.success | ||
) | ||
} | ||
|
||
static var failureCasePath: CasePath<Result, Failure> { | ||
CasePath<Result, Failure>( | ||
extract: { result -> Failure? in | ||
if case let .failure(value) = result { | ||
return value | ||
} | ||
return nil | ||
}, | ||
embed: Result.failure | ||
) | ||
} | ||
} | ||
|
||
Result<Int, Error>.successCasePath | ||
Result<Int, Error>.failureCasePath |
15 changes: 15 additions & 0 deletions
15
0087-the-case-for-case-paths-pt1/CasePath.playground/Sources/Bind.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import Foundation | ||
|
||
public func bind<Model: NSObject, Target, Value>( | ||
model: Model, | ||
_ modelKeyPath: KeyPath<Model, Value>, | ||
to target: Target, | ||
_ targetKeyPath: ReferenceWritableKeyPath<Target, Value> | ||
) { | ||
var observation: NSKeyValueObservation! | ||
observation = model.observe(modelKeyPath, options: [.initial, .new]) { _, change in | ||
guard let newValue = change.newValue else { return } | ||
target[keyPath: targetKeyPath] = newValue | ||
_ = observation | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
0087-the-case-for-case-paths-pt1/CasePath.playground/contents.xcplayground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
<playground version='5.0' target-platform='macos'> | ||
<timeline fileName='timeline.xctimeline'/> | ||
</playground> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
## [Point-Free](https://www.pointfree.co) | ||
|
||
> #### This directory contains code from Point-Free Episode: [The Case for Case Paths: Introduction](https://www.pointfree.co/episodes/ep86-swiftui-snapshot-testing) | ||
> | ||
> You've heard of key paths, but…case paths!? Today we introduce the concept of "case paths," a tool that helps you generically pick apart an enum just like key paths allow you to do for structs. It's the tool you never knew you needed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters