1 module glued.scan;
2 
3 import std.conv: to;
4 import std.traits;
5 import std.meta;
6 import std.string;
7 
8 import glued.mirror;
9 import glued.utils;
10 
11 public import glued.scannable;
12 
13 string scanModule(string name, alias consumer)(){
14     StringBuilder builder;
15     static if (!isGluedImplModule(name))
16         {
17         mixin("static import "~name~";");
18         mixin("alias mod_ = "~name~";");
19         builder.append("static import "~name~";");
20         //builder.append("alias mod_ = "~name~";");
21         static foreach (alias mem; __traits(allMembers, mod_)){
22             static if (__traits(compiles, __traits(getMember, mod_, mem))){
23                 static if (is(__traits(getMember, mod_, mem))){// && !is(__traits(getMember, mod_, mem) == enum)){
24                     builder.append(consumer!(name, mem));
25 //                    BackboneContext.get().track!(Alias!(__traits(getMember, mod_, mem)))();
26                 }
27             }
28         }
29     }
30     return builder.result;
31 }
32 
33 string scanIndexModule(string index, alias consumer)(){
34     StringBuilder builder;
35     mixin("static import "~index~";");
36     mixin("alias mod_ = "~index~";");
37     
38     static if (mod_.Index.importablePackage)
39         builder.append(scanModule!(mod_.Index.packageName, consumer)());
40     static foreach (string submodule; EnumMembers!(mod_.Index.submodules)){
41         builder.append(scanModule!(submodule, consumer)());
42     }
43     static foreach (string subpackage; EnumMembers!(mod_.Index.subpackages)){
44         builder.append(prepareScan!(subpackage, NoOp, NoOp, consumer, qualifier, testQualifier)()); //todo qualifiers
45     }
46     return builder.result;
47 }
48 
49 bool isGluedImplModule(string name)
50 {
51     auto parts = name.split(".");
52     if (parts.length == 2)
53         return parts[0] == "glued";
54     return false;
55 }
56 
57 string prepareScan(alias roots, string setup, alias consumer, string teardown)(){
58     StringBuilder builder;
59     builder.append(setup);
60     static foreach (alias scannable; roots) {
61         
62         static assert(is(typeof(scannable) == Scannable)); //todo could be smartly expressed with conditional method 
63         builder.append(scanIndexModule!(scannable.root~"."~scannable.prefix~"_index", consumer)());
64         version(unittest){
65             builder.append(scanIndexModule!(scannable.root~"."~scannable.testPrefix~"_index", consumer)());
66         }
67     }
68     builder.append(teardown);
69     return builder.result;
70 }
71 
72 enum NoOp = "";
73 
74 Scannable[] listScannables(Scannable s) {
75     return [s];
76 }
77 
78 Scannable[] listScannables(Scannable[] s){
79     return s;
80 }
81 
82 //not the nicest way, but it makes non-debug code nicer
83 //IMPORTANT modify both branches if you do anything here!
84 version(glued_debug) {
85     mixin template unrollLoopThrough(alias roots, string setup, alias consumer, string teardown, string f=__FILE__, int l=__LINE__){
86         pragma(msg, "MIXING IN @",f, ":", l);
87         pragma(msg, prepareScan!(listScannables(roots), setup, consumer, teardown)());
88         mixin(prepareScan!(listScannables(roots), setup, consumer, teardown)());
89     }
90 }
91 else 
92 {
93     mixin template unrollLoopThrough(alias roots, string setup, alias consumer, string teardown){
94         mixin(prepareScan!(listScannables(roots), setup, consumer, teardown)());
95     }
96 }
97 
98