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