1 
2 module autoloader.basic_autoloader;
3 
4 import autoloader.base;
5 import autoloader.util;
6 
7 import std.algorithm;
8 import std.conv;
9 import std.range;
10 
11 class BasicAutoloader : Autoloader
12 {
13 private:
14     string _basePath;
15     string[] _searchPaths;
16 
17 public:
18     /++
19      + Constructs an autoloader with a list of paths to search for classes.
20      ++/
21     this(string[] searchPaths)
22     {
23         _searchPaths = searchPaths;
24     }
25 
26     /++
27      + Constructs an autoloader with a base path to start searches from
28      + and a list of child paths to include in the search.
29      ++/
30     this(string basePath, string[] searchPaths = [])
31     {
32         _basePath = basePath;
33         _searchPaths = searchPaths;
34     }
35 
36     /++
37      + The base path to start searching from.
38      ++/
39     @property
40     string basePath()
41     {
42         return _basePath;
43     }
44 
45     /++
46      + Takes a number of path segments and constructs a path string.
47      ++/
48     string join(string[] paths...)
49     {
50         return paths.filter!(p => p.length > 0).joiner(".").text;
51     }
52 
53     /++
54      + Tries to load a class given by name, searching through the registered paths.
55      + This function does not cache located classes, hence the lookup is performed
56      + for every call.
57      +
58      + Classes are assumed to exist in a module that shares the name of the class,
59      + but is represented as lower_snake_case.
60      +
61      + Returns:
62      +   The ClassInfo object of the class given by name, or null if not found.
63      ++/
64     override const(ClassInfo) lookup(string name)
65     {
66         // Check modules named after the class.
67         foreach(path; [""].chain(searchPaths))
68         {
69             auto result = ClassInfo.find(join(basePath, path, name.toSnakeCase, name));
70             if(result !is null) return result;
71         }
72 
73         // Check the search paths directly.
74         foreach(path; [""].chain(searchPaths))
75         {
76             auto result = ClassInfo.find(join(basePath, path, name));
77             if(result !is null) return result;
78         }
79 
80         return null;
81     }
82 
83     /++
84      + The list of paths in which classes a searched for. If a base path is
85      + present, this represents a list of child paths.
86      ++/
87     @property
88     string[] searchPaths()
89     {
90         return _searchPaths;
91     }
92 }