Last active
October 3, 2024 14:09
-
-
Save mcmurrym/2870c2a5ac6fd790570b to your computer and use it in GitHub Desktop.
A default protocol implementation for CustomDebugStringConvertible that uses Mirror for introspection
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
public extension CustomDebugStringConvertible { | |
var debugDescription: String { | |
return debugDescription() | |
} | |
func debugDescription(_ indentationLevel: Int = 0, includeType: Bool = true) -> String { | |
let indentString = (0..<indentationLevel).reduce("") { tabs, _ in tabs + "\t" } | |
var s: String | |
if includeType { | |
s = "\(type(of: self))" | |
} else { | |
s = "" | |
} | |
let mirror = Mirror(reflecting: self) | |
let children = mirror.children | |
if children.count == 0 { | |
return s + " = \(debugDescription)," | |
} | |
if s.hasPrefix("Optional<") { | |
let child = children.first! | |
if let aChild = child.1 as? CustomDebugStringConvertible { | |
s += aChild.debugDescription(indentationLevel, includeType: false) | |
} else { | |
s += "\(child.1)," | |
} | |
s += "\(indentString)" | |
} else if let date = self as? Date { | |
s += " = \(date)," | |
} else { | |
s += " {" | |
var index = 0 | |
s = children.reduce(s) { reducedString, child in | |
var propertyName: String = "" | |
if self is Array<Any> { | |
propertyName = String(index) | |
index += 1 | |
} else { | |
propertyName = child.label ?? "<undefined>" | |
} | |
if let aChild = child.value as? CustomDebugStringConvertible { | |
let childDescription = aChild.debugDescription(indentationLevel + 1) | |
return reducedString + "\n\(indentString)\t\(propertyName): \(childDescription)" | |
} else { | |
return reducedString + "\n\(indentString)\t\(propertyName): \(type(of: child.value)) = \(child.value)," | |
} | |
} | |
s = s.substring(to: s.characters.index(before: s.characters.endIndex)) | |
s += "\n\(indentString)}" | |
} | |
return s | |
} | |
} | |
/* | |
// Sample usage | |
struct Person: CustomDebugStringConvertible { | |
let name: String | |
let address: Address | |
let children: [Person]? | |
} | |
struct Address: CustomDebugStringConvertible { | |
let city: String | |
let state: String | |
let zip: String | |
let streetNumber: String | |
let streetName: String | |
let suiteNumber: String? | |
let randomNumber: Int | |
init(city: String, state: String, zip: String, streetNumber: String, streetName: String, suiteNumber: String? = nil) { | |
self.city = city | |
self.state = state | |
self.zip = zip | |
self.streetNumber = streetNumber | |
self.streetName = streetName | |
self.suiteNumber = suiteNumber | |
self.randomNumber = Int(arc4random_uniform(1000)) | |
} | |
} | |
let address = Address(city: "Lehi", state: "UT", zip: "84043", streetNumber: "123", streetName: "Fake st") | |
print(address) | |
let child = Person(name: "joe", address: address, children: nil) | |
let person = Person(name: "matt", address: address, children: [child]) | |
print(person) | |
*/ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
+1. Thanks for this. Would be cool if it would also provide it's super class variables as an optional parameter in the function.