1 2 module witchcraft.classes; 3 4 import witchcraft; 5 6 import std.algorithm; 7 import std.array; 8 import std.range; 9 import std.traits; 10 11 12 interface ClassAccessor { 13 Class getMetaType(); 14 } 15 16 17 /++ 18 + Represents and grants access to a class's attributes, fields, methods, 19 + and constructors. 20 ++/ 21 abstract class Class : Aggregate 22 { 23 /++ 24 + Creates a new instance of the class, provided it has a default or 25 + zero-argument constructor. 26 + 27 + Returns: 28 + A new instance of the class. 29 ++/ 30 @property 31 abstract Object create() const; 32 33 /++ 34 + Ditto, but also casts the result to a type given by template parameter. 35 + 36 + Params: 37 + T = An Object type to which the result is cast. 38 + 39 + Returns: 40 + A new instance of the class. 41 ++/ 42 @property 43 T create(T : Object)() const 44 { 45 return cast(T) this.create; 46 } 47 48 /++ 49 + Returns an array of all constructors defined by this class. 50 + This does not include any constructors inherited from a base class, 51 + nor the default constructor. 52 + 53 + If a class declares no constructors, this method will return an empty 54 + array. To construct an Object of such a type, the `create()` method 55 + defined by `Class` should be used. 56 + 57 + Returns: 58 + And array of all constructors on the class. 59 + 60 + See_Also: 61 + create 62 ++/ 63 abstract override const(Constructor)[] getConstructors() const; 64 65 /++ 66 + Looks up a field by name, searching this class, and each of its super 67 + classes in turn. 68 + 69 + Params: 70 + name = The name of the field. 71 + 72 + Returns: 73 + The field object, or null if no such field exists. 74 ++/ 75 override const(Field) getField(string name) const 76 { 77 auto field = getLocalField(name); 78 79 if(field !is null) 80 { 81 return field; 82 } 83 else if(getSuperClass !is null) 84 { 85 return getSuperClass.getField(name); 86 } 87 else 88 { 89 return null; 90 } 91 } 92 93 /++ 94 + Returns an array of all fields defined by this class and classes that 95 + it inherits from. This only extends to super classes that also use 96 + `Witchcraft`. 97 + 98 + Returns: 99 + An array of all known field objects belonging to this class. 100 ++/ 101 override const(Field)[] getFields() const 102 { 103 if(getSuperClass !is null) 104 { 105 return getSuperClass.getFields ~ getLocalFields; 106 } 107 else 108 { 109 return getLocalFields; 110 } 111 } 112 113 /++ 114 + Returns an array of all interfaces that are declared directly on this 115 + class. Interfaces that appear multiple times on the class are only 116 + present once in the array. 117 + 118 + Returns: 119 + An array of interfaces on this class. 120 ++/ 121 abstract const(InterfaceType)[] getInterfaces() const; 122 123 const(Field) getLocalField(string name) const 124 { 125 return super.getField(name); 126 } 127 128 string[] getLocalFieldNames() const 129 { 130 return getLocalFields 131 .map!"a.getName" 132 .array; 133 } 134 135 const(Field)[] getLocalFields() const 136 { 137 return super.getFields; 138 } 139 140 const(Method) getLocalMethod(string name, TypeInfo[] parameterTypes...) const 141 { 142 return getLocalMethods(name) 143 .filter!(m => m.getParameterTypes == parameterTypes) 144 .takeOne 145 .chain(null.only) 146 .front; 147 } 148 149 const(Method) getLocalMethod(TList...)(string name) const 150 { 151 auto types = new TypeInfo[TList.length]; 152 153 foreach(index, type; TList) 154 { 155 types[index] = typeid(type); 156 } 157 158 return this.getLocalMethod(name, types); 159 } 160 161 string[] getLocalMethodNames() const 162 { 163 return getLocalMethods 164 .map!"a.getName" 165 .array; 166 } 167 168 const(Method)[] getLocalMethods() const 169 { 170 return super.getMethods; 171 } 172 173 const(Method)[] getLocalMethods(string name) const 174 { 175 return super.getMethods(name); 176 } 177 178 /++ 179 + Returns all methods declared on this class, and non-private methods in 180 + classes that it inherits from. This is restricted to classes for which 181 + reflective information is present. 182 + 183 + Methods that are declared by a base class and are overriden by another 184 + class appear in the array for every class that delcares them. 185 + 186 + Returns: 187 + All methods that are available to this class. 188 + 189 + See_Also: 190 + getDeclaringType 191 ++/ 192 override const(Method)[] getMethods() const 193 { 194 const(Class) superClassMeta = getSuperClass(); 195 if(superClassMeta !is null) 196 { 197 return superClassMeta.getMethods 198 .filter!`a.getProtection != "private"` 199 .chain(getLocalMethods) 200 .array; 201 } 202 else 203 { 204 return getLocalMethods; 205 } 206 } 207 208 /++ 209 + Ditto, but returns only methods that match the given name. 210 + 211 + Params: 212 + name = The name of the method to look for. 213 + 214 + Returns: 215 + All methods that match the given name. 216 ++/ 217 override const(Method)[] getMethods(string name) const 218 { 219 const(Class) superClassMeta = getSuperClass(); 220 if(superClassMeta !is null) 221 { 222 return superClassMeta.getMethods(name) 223 .filter!`a.getProtection != "private"` 224 .chain(getLocalMethods(name)) 225 .array; 226 } 227 else 228 { 229 return getLocalMethods(name); 230 } 231 } 232 233 /++ 234 + Returns the parent of this class. If the class doesn't declare a super 235 + class, the super class is `Object`, unless the class itself is `Object`. 236 + For `Object`, this method always returns `null`. 237 + 238 + Returns: 239 + This class's super class. 240 ++/ 241 abstract const(Class) getSuperClass() const; 242 243 /++ 244 + Ditto, but a `TypeInfo` object is returned instead. 245 + 246 + Returns: 247 + This class's super class. 248 ++/ 249 abstract const(TypeInfo) getSuperTypeInfo() const; 250 251 /++ 252 + Checks if this class is abstract. 253 + 254 + Returns: 255 + `true` if the class is abstract. 256 ++/ 257 @property 258 abstract bool isAbstract() const; 259 260 /++ 261 + Checks if this type is a class. For children of `Class`, this always 262 + returns `true`. 263 + 264 + Returns: 265 + `true` if the type is a class. 266 ++/ 267 @property 268 final override bool isClass() const 269 { 270 return true; 271 } 272 273 /++ 274 + Checks if this class is final. 275 + 276 + Returns: 277 + `true` if the type is final. 278 ++/ 279 @property 280 abstract bool isFinal() const; 281 282 abstract bool isSubClassOf(const Class other) const; 283 284 abstract bool isSuperClassOf(const Class other) const; 285 }