๐Ÿ‘”HasMirrors

๐Ÿ’พ ็จ‹ๅผ๏ผšreplit โฌ†๏ธ ้œ€่ฆ๏ผšMirror, Logger

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// 2022.01.27 * v.1 + log, reflect, mirror
// 2022.01.28 / log, reflect, mirrorChildren: use `Logger`
//            - rename `item` as `HasMirrors`
//            + default conformances: Int, Double
//            + extend [HasMirrors]: `items.log()`
//            + Bool.log(): custom conformance
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    HasMirrors    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

public protocol HasMirrors {
    /// `item.log()`
    func log() -> Self              // for chaining
    /// `item.reflect()`
    func reflect() -> Self          // for chaining
    /// `item.mirror()`
    func mirror() -> Self           // for chaining
}

// โญ default behaviors
extension HasMirrors {

    /// `item.log()`
    @discardableResult
    public func log() -> Self { 
        Logger.log(String(describing: self), dot: "๐Ÿ„")
        return self 
    }
    
    /// `item.reflect()`
    @discardableResult
    public func reflect() -> Self { 
        Logger.log(String(reflecting: self), dot: "๐Ÿ„")
        return self 
    }
    
    // mirrorChildren (object tree)
    @discardableResult
    func mirrorChildren<T>(of subject: T) -> Self {
    
        let title = "\(String(describing: subject))"
        Logger.box(title)
        
        
        // โญ mirror children
        let children = Mirror(reflecting: subject).children
        if children.count == 0 { print("  // no children") }
        
        children.forEach { child in
            let label = "\(child.label ?? "_")"
            let value = " \(child.value)"
            let valueType = " (\(type(of: child.value)))"
            Logger.log(label + ":" + value + valueType, dot: "๐Ÿ”ธ")
        }
        
        Logger.line(title.count + 10)
        return self
    }
    
    /// `item.mirror()`
    @discardableResult
    public func mirror() -> Self {
        return mirrorChildren(of: self)
    }
}

// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    [HasMirrors] extension    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

extension Array where Element == HasMirrors {
    /// `items.log()`
    @discardableResult
    public func log() -> Array { 
        self.forEach { _ = $0.log() }  // _: silence compiler warning.
        return self 
    }
}

// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    default conformances    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

extension String: HasMirrors {}
extension Int   : HasMirrors {}
extension Double: HasMirrors {}

extension Bool  : HasMirrors {
    public func log() -> Bool {
        Logger.log(self ? "โœ…" : "โŒ")
        return self
    }
}

History

  1. (2022.01.27) - original post

Last updated