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 }