Skip to content

Commit

Permalink
87
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Jan 20, 2020
1 parent f616817 commit 3bdd72e
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 1 deletion.
142 changes: 142 additions & 0 deletions 0087-the-case-for-case-paths-pt1/CasePath.playground/Contents.swift
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
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
}
}
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>
5 changes: 5 additions & 0 deletions 0087-the-case-for-case-paths-pt1/README.md
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.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,5 @@ This repository is the home of code written on episodes of
1. [Effectful State Management: Effects](0083-testable-state-management-effects)
1. [Effectful State Management: Ergonomics](0084-testable-state-management-ergonomics)
1. [Effectful State Management: The Point](0085-testable-state-management-the-point)
1. [Effectful State Management: The Point](0086-swiftui-snapshot-testing)
1. [SwiftUI Snapshot Testing](0086-swiftui-snapshot-testing)
1. [The Case for Case Paths: Introduction](0087-the-case-for-case-paths-pt1)

0 comments on commit 3bdd72e

Please sign in to comment.