1 /**
2 Aedi, a dependency injection library.
3 
4 Aedi is a dependency injection library. It does provide a set of containers that do
5 IoC, and an interface to configure application components (structs, objects, etc.)
6 
7 Aim:
8 
9 The aim of library is to provide a dependency injection solution that is
10 feature rich, easy to use, easy to learn, and easy to extend up to your needs.
11 
12 Having a framework that creates and wire components is quite good. In previous tutorials,
13 was explained how to inject compile time known data, and how to reference dependent components,
14 but while designing a framework, or a library in conjunction with AEDI framework, exposing a set
15 of parameters might be desired.
16 To expose a set of configuration parameters, framework provides a special version of container,
17 that stores in those parameters, and serves them to the requestor. To use this container it
18 should be attached to a composite container along the rest of containers, as in previous tutorial and used
19 along them. The process of adding parameters into container is easy as with rest of shown containers,
20 the only difference is, that $(D_INLINECODE register) method doesn’t require an explicit component type, since it
21 is inferred from passed value. Example below shows basic usage of value container:
22 
23 --------------------
24 auto container = aggregate( // Create a joint container hosting other two containers
25     singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity
26     prototype(), "prototype", // Create prototype container, and store it in joint container by "prototype" identity
27     values(), "parameters"  // Create value container, and store it in joint container by "prototype" identity
28 );
29 
30 with (container.configure("singleton")) {
31 
32     // ...
33 
34 }
35 
36 with (container.configure("prototype")) {
37 
38     // ...
39 }
40 
41 with (container.locate!ValueContainer("parameters").configure) {
42 
43     register(Size(200, 150, 300), "size.smarty");
44 }
45 --------------------
46 
47 As seen the configuration for value containers differs from other containers.
48 In case of value containers $(D_INLINECODE configure) method should know exactly
49 what kind of configuration context to create.
50 
51 Try running example. Add, modify it to understand usage of containers for already
52 available values.
53 
54 License:
55 	Boost Software License - Version 1.0 - August 17th, 2003
56 
57 	Permission is hereby granted, free of charge, to any person or organization
58 	obtaining a copy of the software and accompanying documentation covered by
59 	this license (the "Software") to use, reproduce, display, distribute,
60 	execute, and transmit the Software, and to prepare derivative works of the
61 	Software, and to permit third-parties to whom the Software is furnished to
62 	do so, all subject to the following:
63 
64 	The copyright notices in the Software and this entire statement, including
65 	the above license grant, this restriction and the following disclaimer,
66 	must be included in all copies of the Software, in whole or in part, and
67 	all derivative works of the Software, unless such copies or derivative
68 	works are solely in the form of machine-executable object code generated by
69 	a source language processor.
70 
71 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
72 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
74 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
75 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
76 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
77 	DEALINGS IN THE SOFTWARE.
78 
79 Authors:
80 	aermicioi
81 **/
82 
83 module value_container;
84 
85 import aermicioi.aedi;
86 import std.stdio;
87 
88 /**
89 A struct that should be managed by container.
90 **/
91 struct Color {
92     ubyte r;
93     ubyte g;
94     ubyte b;
95 }
96 
97 /**
98 Size of a car.
99 **/
100 struct Size {
101 
102     ulong width;
103     ulong height;
104     ulong length;
105 }
106 
107 /**
108 Interface for engines.
109 
110 An engine should implement it, in order to be installable in a car.
111 **/
112 interface Engine {
113 
114     public {
115 
116         void turnOn();
117         void run();
118         void turnOff();
119     }
120 }
121 
122 /**
123 A concrete implementation of Engine that uses gasoline for propelling.
124 **/
125 class GasolineEngine : Engine {
126 
127     public {
128 
129         void turnOn() {
130             writeln("pururukVrooomVrrr");
131 
132         }
133 
134         void run() {
135             writeln("vrooom");
136         }
137 
138         void turnOff() {
139             writeln("vrrrPrrft");
140         }
141     }
142 }
143 
144 /**
145 A concrete implementation of Engine that uses diesel for propelling.
146 **/
147 class DieselEngine : Engine {
148 
149     public {
150 
151         void turnOn() {
152             writeln("pururukVruumVrrr");
153 
154         }
155 
156         void run() {
157             writeln("vruum");
158         }
159 
160         void turnOff() {
161             writeln("vrrrPft");
162         }
163     }
164 }
165 
166 /**
167 A concrete implementation of Engine that uses electricity for propelling.
168 **/
169 class ElectricEngine : Engine {
170     public {
171 
172         void turnOn() {
173             writeln("pzt");
174 
175         }
176 
177         void run() {
178             writeln("vvvvvvvvv");
179         }
180 
181         void turnOff() {
182             writeln("tzp");
183         }
184     }
185 }
186 
187 /**
188 Tire, what it can represent else?
189 **/
190 class Tire {
191     private {
192         int size_;
193         float pressure_;
194         string vendor_;
195     }
196 
197     public @property {
198         Tire size(int size) @safe nothrow {
199         	this.size_ = size;
200 
201         	return this;
202         }
203 
204         int size() @safe nothrow {
205         	return this.size_;
206         }
207 
208         Tire pressure(float pressure) @safe nothrow {
209         	this.pressure_ = pressure;
210 
211         	return this;
212         }
213 
214         float pressure() @safe nothrow {
215         	return this.pressure_;
216         }
217 
218         Tire vendor(string vendor) @safe nothrow {
219         	this.vendor_ = vendor;
220 
221         	return this;
222         }
223 
224         string vendor() @safe nothrow {
225         	return this.vendor_;
226         }
227     }
228 
229     public override string toString() {
230         import std.algorithm;
231         import std.range;
232         import std.conv;
233         import std.utf;
234 
235         return only("Tire(", this.size.to!string, " inch, ", this.pressure.to!string, " atm, ", this.vendor, ")")
236             .joiner
237             .byChar
238             .array;
239     }
240 }
241 
242 /**
243 A class representing a car.
244 **/
245 class Car {
246 
247     private {
248         Color color_; // Car color
249         Size size_; // Car size
250         Engine engine_; // Car engine
251 
252         Tire frontLeft_;
253         Tire frontRight_;
254         Tire backLeft_;
255         Tire backRight_;
256     }
257 
258     public {
259 
260         /**
261         Constructor of car.
262 
263         Constructs a car with a set of sizes. A car cannot of course have
264         undefined sizes, so we should provide it during construction.
265 
266         Params:
267             size = size of a car.
268         **/
269         this(Size size, Engine engine) {
270             this.size_ = size;
271             this.engine = engine;
272         }
273 
274         @property {
275 
276             /**
277             Set color of car
278 
279             Set color of car. A car can live with undefined color (physics allow it).
280 
281             Params:
282             	color = color of a car.
283 
284             Returns:
285             	Car
286             **/
287             Car color(Color color) @safe nothrow {
288             	this.color_ = color;
289 
290             	return this;
291             }
292 
293             Color color() @safe nothrow {
294             	return this.color_;
295             }
296 
297             Size size() @safe nothrow {
298             	return this.size_;
299             }
300 
301             /**
302             Set engine used in car.
303 
304             Params:
305             	engine = engine used in car to propel it.
306 
307             Returns:
308             	Car
309             **/
310             Car engine(Engine engine) @safe nothrow {
311             	this.engine_ = engine;
312 
313             	return this;
314             }
315 
316             Engine engine() @safe nothrow {
317             	return this.engine_;
318             }
319 
320             Car frontLeft(Tire frontLeft) @safe nothrow {
321             	this.frontLeft_ = frontLeft;
322 
323             	return this;
324             }
325 
326             Tire frontLeft() @safe nothrow {
327             	return this.frontLeft_;
328             }
329 
330             Car frontRight(Tire frontRight) @safe nothrow {
331             	this.frontRight_ = frontRight;
332 
333             	return this;
334             }
335 
336             Tire frontRight() @safe nothrow {
337             	return this.frontRight_;
338             }
339 
340             Car backLeft(Tire backLeft) @safe nothrow {
341             	this.backLeft_ = backLeft;
342 
343             	return this;
344             }
345 
346             Tire backLeft() @safe nothrow {
347             	return this.backLeft_;
348             }
349 
350             Car backRight(Tire backRight) @safe nothrow {
351             	this.backRight_ = backRight;
352 
353             	return this;
354             }
355 
356             Tire backRight() @safe nothrow {
357             	return this.backRight_;
358             }
359 
360         }
361 
362         void start() {
363             engine.turnOn();
364         }
365 
366         void run() {
367             engine.run();
368         }
369 
370         void stop() {
371             engine.turnOff();
372         }
373     }
374 }
375 
376 /**
377 A manufacturer of cars.
378 **/
379 class CarManufacturer {
380 
381     public {
382         Car manufacture(Size size) {
383             return new Car(size, new DieselEngine()); // Manufacture a car.
384         }
385     }
386 }
387 
388 void drive(Car car, string name) {
389     writeln("Uuh, what a nice car, ", name," with following specs:");
390     writeln("Size:\t", car.size());
391     writeln("Color:\t", car.color());
392     writeln("Engine:\t", car.engine());
393     writeln("Tire front left:\t", car.frontLeft(), "\t located at memory ", cast(void*) car.frontLeft());
394     writeln("Tire front right:\t", car.frontRight(), "\t located at memory ", cast(void*) car.frontRight());
395     writeln("Tire back left: \t", car.backLeft(), "\t located at memory ", cast(void*) car.backLeft());
396     writeln("Tire back right:\t", car.backRight(), "\t located at memory ", cast(void*) car.backRight());
397 }
398 
399 void main() {
400     auto container = aggregate( // Create a joint container hosting other two containers
401         singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity
402         prototype(), "prototype", // Create prototype container, and store it in joint container by "prototype" identity
403         values(), "parameters"  // Create value container, and store it in joint container by "prototype" identity
404     );
405 
406     scope(exit) container.terminate();
407 
408     with (container.configure("singleton")) {
409 
410         register!Color; // Let's register a default implementation of Color
411 
412 
413         register(Color(0, 255, 0), "color.green");
414         register("divine tire", "tire.vendor");
415 
416         register!Size // Register a size of a generic "sedan" into container
417             .set!"width"(200UL)
418             .set!"height"(150UL)
419             .set!"length"(500UL);
420 
421         register!(Engine, ElectricEngine);
422 
423         register!Car
424             .autowire
425             .set!"color"("color.green".lref)
426             .set!"frontLeft"(lref!Tire)
427             .set!"frontRight"(lref!Tire)
428             .set!"backLeft"(lref!Tire)
429             .set!"backRight"(lref!Tire);
430     }
431 
432     with (container.configure("prototype")) {
433         register!Tire // Registering Tire into "prototype" container used by aggregate container
434             .set!"size"(17)
435             .set!"pressure"(3.0)
436             .set!"vendor"("tire.vendor".lref);
437     }
438 
439     with (container.locate!ValueContainer("parameters").configure) {
440 
441         register(Size(200, 150, 300), "size.smarty");
442     }
443 
444     container.instantiate(); // Boot container (or prepare managed code/data).
445 
446     container.locate!Car.drive("Electric car");
447 }