Closed cbh2000 closed 6 years ago
Plan:
//: Playground - noun: a place where people can play import UIKit enum PropertyCustomizations { case ignored case nullable case mapped(to: String) case transformed(TransformerType) } class Config { internal var storage = [String: [PropertyCustomizations]]() subscript(property: String) -> [PropertyCustomizations] { get { return storage[property] ?? [] } set { storage[property] = newValue } } } protocol Reflectable: NSObjectProtocol { static func config(_ c: Config) } class Reflection: NSObject, Reflectable { class func config(_ c: Config) { } } protocol TransformerType { var propertyType: Any.Type { get } var dataType: Any.Type { get } func set(value: Any, propertyName: String, instance: Reflectable) func getValue(propertyName: String, instance: Reflectable) -> Any } class Transformer<PropertyType, DataType>: TransformerType { var propertyType: Any.Type { return PropertyType.self } var dataType: Any.Type { return DataType.self } private let setter: (DataType) -> PropertyType private let getter: (PropertyType) -> DataType init(setter: @escaping (DataType) -> PropertyType, getter: @escaping (PropertyType) -> DataType) { self.setter = setter self.getter = getter } func set(value: Any, propertyName: String, instance: Reflectable) { let transformed = setter(value as! DataType) (instance as! NSObject).setValue(transformed, forKey: propertyName) } func getValue(propertyName: String, instance: Reflectable) -> Any { return getter((instance as! NSObject).value(forKey: propertyName) as! PropertyType) } } class CustomTransformer<ClassType, PropertyType, DataType>: TransformerType { var propertyType: Any.Type { return PropertyType.self } var dataType: Any.Type { return DataType.self } init(setter: @escaping (ClassType, DataType) -> Void, getter: @escaping (ClassType, PropertyType) -> DataType) { } func set(value: Any, propertyName: String, instance: Reflectable) { } func getValue(propertyName: String, instance: Reflectable) -> Any { return () as Any } } let dateTransformer: TransformerType = Transformer<Date, String>(setter: { (value) -> Date in print("input: \(value)") let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'hh:mm:ssZ" return formatter.date(from: value as! String)! }, getter: { (value: Date) -> String in let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'hh:mm:ssZ" return formatter.string(from: value) }) class Person: Reflection { var name = "" var age = Data() var born = Date() override class func config(_ c: Config) { c["name"] = [.ignored] c["born"] = [.transformed(dateTransformer)] let customTransformer = CustomTransformer<Person, Data, Int>(setter: { (person, value) in person.age = Data() }, getter: { _ in Int() }) c["age"] = [.nullable, .mapped(to: "user_age"), .transformed(customTransformer)] } } let config = Config() let p = Person() let type: Reflectable.Type = type(of: p) type.config(config) config["name"] if case PropertyCustomizations.transformed(let transformer) = PropertyCustomizations.transformed(dateTransformer) { let value: Any = "2005-04-03T12:00:00Z" if type(of: value) == transformer.dataType || transformer.dataType == Any.self { transformer.set(value: value, propertyName: "born", instance: p) } else { print("Type \(type(of: value)) is not supported type. Should be \(transformer.dataType).") } print("person.born:", p.born) let gotBack = transformer.getValue(propertyName: "born", instance: p) print("Value back was: \(gotBack)") }
Plan: