Created
October 30, 2024 11:49
-
-
Save hamsternik/2672e3b86d5d9da04a98a1048f7bdc71 to your computer and use it in GitHub Desktop.
Simple closure wrapper allows to log, compare, bind into the chain and write much more fun Swift code.
This file contains hidden or 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
import Foundation | |
/// Command is a developer friendly wrapper around a closure | |
/// Every command always have Void result type, which do it less composable, | |
/// but also more focused | |
final class CommandWith<T> { | |
private let action: (T) -> () // underlying closure | |
// Block of `context` defined variables. Allows Command to be debugged | |
private let file: StaticString | |
private let function: StaticString | |
private let line: Int | |
private let id: String | |
init(id: String = "unnamed", | |
file: StaticString = #file, | |
function: StaticString = #function, | |
line: Int = #line, | |
action: @escaping (T) -> ()) { | |
self.id = id | |
self.action = action | |
self.function = function | |
self.file = file | |
self.line = line | |
} | |
func perform(with value: T) { | |
action(value) | |
} | |
/// Placeholder for do nothing command | |
static var nop: CommandWith { return CommandWith(id: "nop") { _ in } } | |
/// Support for Xcode quick look feature. | |
@objc | |
func debugQuickLookObject() -> AnyObject? { | |
return """ | |
type: \(String(describing: type(of: self))) | |
id: \(id) | |
file: \(file) | |
function: \(function) | |
line: \(line) | |
""" as NSString | |
} | |
} | |
/// Less code = less errors | |
typealias Command = CommandWith<Void> | |
/// Also pure simplification | |
extension CommandWith where T == Void { | |
func perform() { | |
perform(with: ()) | |
} | |
} | |
/// Allows commands to be compared and stored in sets and dicts. | |
/// Uses `ObjectIdentifier` to distinguish between commands | |
extension CommandWith: Hashable { | |
static func ==(left: CommandWith, right: CommandWith) -> Bool { | |
return ObjectIdentifier(left) == ObjectIdentifier(right) | |
} | |
var hashValue: Int { return ObjectIdentifier(self).hashValue } | |
} | |
extension CommandWith { | |
/// Allows to pin some value to some command | |
func bind(to value: T) -> Command { | |
return Command { self.perform(with: value) } | |
} | |
} | |
extension CommandWith { | |
func map<U>(transform: @escaping (U) -> T) -> CommandWith<U> { | |
return CommandWith<U> { u in self.perform(with: transform(u)) } | |
} | |
} | |
extension CommandWith { | |
// Allows to easily move commands between queues | |
func dispatched(on queue: DispatchQueue) -> CommandWith { | |
return CommandWith { value in | |
queue.async { | |
self.perform(with: value) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment