1 module deps; 2 3 import std.range; 4 import std.regex; 5 import std.stdio; 6 import std.typecons; 7 8 alias Dependency = Tuple!(string, "client", string, "supplier"); 9 10 auto moduleDependencies(alias predicate)(File file) 11 { 12 import std.algorithm : filter, map; 13 14 return reader(file.byLine) 15 .filter!predicate 16 .map!(dependency => Dependency(dependency.client.name, dependency.supplier.name)); 17 } 18 19 auto reader(R)(R input) 20 { 21 return Reader!R(input); 22 } 23 24 struct Reader(R) 25 if (isInputRange!R) 26 { 27 alias Module = Tuple!(string, "name", string, "path"); 28 alias Dependency = Tuple!(Module, "client", Module, "supplier"); 29 30 private R input; 31 32 public bool empty = false; 33 34 public Dependency front; 35 36 private this(R input) 37 { 38 this.input = input; 39 popFront; 40 } 41 42 public void popFront() 43 { 44 import std.conv : to; 45 import std.regex : matchFirst, regex; 46 47 enum pattern = regex(`^(depsImport\s)?` 48 ~ `(?P<clientName>[\w.]+)\s\((?P<clientPath>.*)\)` 49 ~ `\s:[^:]*:\s` 50 ~ `(?P<supplierName>[\w.]+)\s\((?P<supplierPath>.*)\)`); 51 52 while (!this.input.empty) 53 { 54 auto captures = this.input.front.matchFirst(pattern); 55 56 scope (exit) 57 this.input.popFront; 58 59 if (captures) 60 { 61 with (this.front.client) 62 { 63 name = captures["clientName"].to!string; 64 path = captures["clientPath"].to!string; 65 } 66 with (this.front.supplier) 67 { 68 name = captures["supplierName"].to!string; 69 path = captures["supplierPath"].to!string; 70 } 71 return; 72 } 73 } 74 this.empty = true; 75 } 76 } 77 78 /// reads module dependencies 79 unittest 80 { 81 import std.algorithm : equal; 82 83 const line = "depend (src/depend.d) : private : object (/usr/include/dmd/druntime/import/object.di)"; 84 const client = tuple("depend", "src/depend.d"); 85 const supplier = tuple("object", "/usr/include/dmd/druntime/import/object.di"); 86 87 assert(reader(only(line)).equal(only(tuple(client, supplier)))); 88 }