1 module bolts.reflection.metaaggregate; 2 3 import bolts.reflection.metafunction; 4 5 static mixin template ModuleAggregateCommonCode() 6 { 7 import std.meta : staticMap, AliasSeq; 8 import bolts.reflection.metafunction; 9 10 alias functions = staticMap!(collectMembers, __traits(allMembers, origin)); 11 12 private alias collectMembers(string name) = collectOverloads!( 13 name, 0, __traits(getOverloads, origin, name)); 14 15 private alias collectOverloads(string name, int index, Fun...) = 16 AliasSeq!( 17 Function!(Fun[0], source, name, index), 18 collectOverloads!(name, index + 1, Fun[1..$])); 19 20 private alias collectOverloads(string name, int index) = AliasSeq!(); 21 } 22 23 template Aggregate(alias Aggregate_, string Source = __traits(identifier, Aggregate_)) 24 { 25 alias origin = Aggregate_; 26 alias source = Source; 27 mixin ModuleAggregateCommonCode; 28 } 29 30 unittest 31 { 32 import std.format; 33 import bolts.reflection.metafunction; 34 import std.traits; // needed by expansion or Function.returnType 35 36 interface TheFullMonty 37 { 38 pure int foo() immutable; 39 @nogc @trusted nothrow ref int foo(out real, return ref int, lazy int) const; 40 @safe shared scope void foo(scope Object); 41 } 42 43 template Mocker(alias F) 44 { 45 static if (is(F.returnType.origin == void)) { 46 enum Mocker = F.setBody!("").mixture; 47 } else static if (F.isRef) { 48 enum Mocker = F.setBody!(q{ 49 static %s rv; 50 return rv; 51 }.format(F.returnType.mixture)).mixture; 52 } else { 53 enum Mocker = F.setBody!(q{ 54 return %s.init; 55 }.format(F.returnType.mixture)).mixture; 56 } 57 } 58 59 class Mock(Interface) : Interface 60 { 61 mixin(staticMap!(Mocker, Aggregate!Interface.functions)); 62 } 63 64 TheFullMonty mock = new Mock!TheFullMonty; 65 real x; 66 int i, l; 67 mock.foo(x, i, l++) = 1; 68 assert(mock.foo(x, i, l++) == 1); 69 assert(l == 0); 70 }