1 /**
2  * Environment variable-based
3  * provider.
4  *
5  * You should use this if you
6  * intend on filling up your
7  * config with values that are
8  * available as environment
9  * variables
10  *
11  * Authors: Tristan Brice Velloza Kildaire (deavmi)
12  */
13 module hummus.providers.env;
14 
15 import hummus.provider : Provider;
16 import std.process : environment;
17 
18 /**
19  * A provider which will look for
20  * environment variables based
21  * on a _transformed_ version of
22  * their name.
23  *
24  * This transformation replaces all
25  * `.` with a character of your
26  * choice (default is `__`) and
27  * also ensures all parts of the
28  * name are upper-case.
29  */
30 public class EnvironmentProvider : Provider
31 {
32 	private string _dp;
33 
34 	/**
35 	 * Constructs a new environment
36 	 * provider and uses the given
37 	 * token to replace all occurrences
38      * of `.` in names
39      *
40      * Params:
41      *   dotReplace = the replaceent token
42      */
43 	this(string dotReplace)
44 	{
45 		this._dp = dotReplace;
46 	}
47 
48 	/**
49 	 * Constructs a new environment
50      * provider and uses the `__`
51      * token as the replacement
52      * token
53      */
54 	this()
55 	{
56 		this("__");
57 	}
58 
59     /**
60      * Implementation
61      */
62     protected bool provideImpl(string n, ref string v)
63     {
64 		// upper-case everything
65 		import std.string : toUpper;
66 		auto trans_n = toUpper(n);
67 
68     	// replace `.` with `_dp`
69         import std.string : replace;
70         trans_n = replace(trans_n, ".", this._dp);
71 
72         // todo: switch to nothrow version
73         try
74         {
75             v = environment[trans_n];
76             return true;
77         }
78         catch(Exception e)
79         {
80             return false;
81         }
82     }
83 }
84 
85 private version(unittest)
86 {
87     import hummus.cfg : fieldsOf;
88     import std.stdio : writeln;
89 }
90 
91 unittest
92 {
93 	writeln();
94 	scope(exit)
95 	{
96 		writeln();
97 	}
98 
99     struct Inner
100     {
101         int z;
102     }
103 
104     struct Cfg
105     {
106         string v;
107         Inner i;
108     }
109 
110     auto cfg = Cfg();
111     writeln("Before provisioning: ", cfg);
112 
113     // envvars `v` and `i.z` should be present
114     fieldsOf(cfg, new EnvironmentProvider());
115 
116 	writeln("After provisioning: ", cfg);
117 
118     assert(cfg.v == "1");
119     assert(cfg.i.z == 2);
120 }