-
-
Save honood/4edde421f4523667963e6a8629081655 to your computer and use it in GitHub Desktop.
Implementing a Ruby `tap` equivalent in 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
// I wanted an equivalent to Ruby's `tap` (http://ruby-doc.org/core-2.3.0/Object.html#method-i-tap) in Swift which I could mix into any type to tap into method chains. | |
// Define the interface we want to provide as a protocol | |
private protocol Tap { | |
func tap(block: (Self) -> Void) -> Self | |
} | |
// Extend the `Tap` protocol with a default implementation | |
private extension Tap { | |
func tap(block: (Self) -> Void) -> Self { | |
block(self) | |
return self | |
} | |
} | |
// -------- | |
// Each type must declare adoption of the protocol with an extension | |
extension Array : Tap {} | |
let squares = [1, 2, 3, 4, 5].tap({ print($0) }).map({ $0*$0 }).tap({ print($0) }) | |
// > [1, 2, 3, 4, 5] | |
// > [1, 4, 9, 16, 25] | |
// -------- | |
// Suppose we had a class with some functions we wish we could chain together... | |
class Door : CustomDebugStringConvertible { | |
enum DoorState: String { | |
case open | |
case closed | |
} | |
enum LockState: String { | |
case locked | |
case unlocked | |
} | |
private var state = DoorState.open | |
private var lockState = LockState.unlocked | |
var debugDescription: String { | |
get { | |
return "The Door is: \(state) and \(lockState)" | |
} | |
} | |
func open() { | |
state = .open | |
} | |
func close() { | |
state = .closed | |
} | |
func lock() { | |
lockState = .locked | |
} | |
func unlock() { | |
lockState = .unlocked | |
} | |
func tap(block: (Door) -> Void) -> Self { | |
block(self) | |
return self | |
} | |
} | |
// Declare adoption of the `Tap` protocol | |
extension Door: Tap {} | |
let door = Door() | |
// Use `tap` to access the object without breaking the chain: | |
door.tap({ $0.close() }).lock() | |
print(door) | |
// > The Door is: closed and locked |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is neat! However, it can not be adopted by non-final classes (at least in recent versions of Swift).