# HasMirrors

{% tabs %}
{% tab title="👔 HasMirrors" %}
💾 程式：[replit](https://replit.com/@pegasusroe/Swift-Playground#Logs/Loggable.swift)    ⬆️ 需要：[mirror](mirror "mention"), [logger](logger "mention")

```swift
// ────────────────────────────────────────────────────────────
// 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
    }
}
```
{% endtab %}

{% tab title="💈範例" %}
💾 程式： [replit](https://replit.com/@pegasusroe/Swift-Playground#test/testHasMirrors.swift)

```swift
struct Person: HasMirrors {
    let name: String
    let age : Int
}

func testHasMirrors() {
    let joe = Person(name: "Joe", age: 8)
    joe.log().reflect().mirror()
}
```

#### Result:

```swift
// 🍄 Person(name: "Joe", age: 8)
// 🍄 main.Person(name: "Joe", age: 8)
// ┌───────────────────────────────────┐
// │    Person(name: "Joe", age: 8)    │
// └───────────────────────────────────┘
// 🔸 name: Joe (String)
// 🔸 age: 8 (Int)
// ─────────────────────────────────────
```
{% endtab %}

{% tab title="📗 參考" %}
* [ ] Sarun ⟩ [What is @discardableResult](https://sarunw.com/posts/what-is-discardableresult/)
{% endtab %}

{% tab title="⬇️ 應用" %}
* [casereflectable](casereflectable "mention") (<mark style="color:red;">**protocol**</mark>) - inherits from Loggable.
* [nonnominaltypewrapper](nonnominaltypewrapper "mention") (<mark style="color:red;">**struct**</mark>) - conforms to Loggable.
{% endtab %}

{% tab title="👥 相關" %}
* uses [mirror](mirror "mention").
* uses [logger](logger "mention").
* used by [log](log "mention").
* [view](../../swiftui/view/view/view "mention")
{% endtab %}
{% endtabs %}

## History

{% tabs %}
{% tab title="contents" %}
1. (2022.01.27) - original post
{% endtab %}

{% tab title="1" %}
💾 程式：[paiza.io](https://paiza.io/projects/BgeXldbalSZcvt3C_5qcQg)    ⬆️ 需要：[mirror](mirror "mention")

```swift
// 2022.01.27 * first version

// -------------------
//     ⭐ Loggable
// -------------------

public protocol Loggable {
    /// show `String(describing: self)` by default
    func log() -> Self
    /// show `String(reflecting: self)` by default
    func reflect() -> Self
    /// show `Mirror(reflecting: self).children` by default
    func mirror() -> Self
}

// ⭐ default behaviors
extension Loggable {

    @discardableResult
    public func log() -> Self { print(String(describing: self)) ; return self }
    
    @discardableResult
    public func reflect() -> Self { print(String(reflecting: self)) ; return self }
    
    // mirrorChildren (object tree)
    @discardableResult
    func mirrorChildren<T>(of subject: T) -> Self {
    
        let selfDesc = "    children of \(String(describing: subject))    "
        let line = String(repeating: "-", count: selfDesc.count)
        
        print()
        print(line)
        print("\(selfDesc)")
        print(line)
        
        // ⭐ mirror children
        let children = Mirror(reflecting: subject).children
        if children.count == 0 { print("  // no children") }
        
        children.forEach { child in
            print("  • \(child.label ?? "_"): \(child.value) (\(type(of: child.value)))")
        }
        
        print(line)
        print()
        
        return self
    }
    
    @discardableResult
    public func mirror() -> Self {
        mirrorChildren(of: self)
    }
}
```
{% endtab %}
{% endtabs %}
