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 Usage:
13 
14 This tutorial will show how to register a component with custom identity in container, and
15 how to reference components with custom identities. The tutorial is based on car
16 simulation presented in previous example, and will continue to improve it.
17 
18 Except of a single implementation of a component, in some occurrences of an application,
19 multiple instances of same type of component, but with varying dependencies, are required. In case
20 of car simulation application, the simulator should not be limited to only a single car, it should be
21 able to have multiple cars with varying parameters, like cars of sedan or smart sizes with blue and
22 green colors.
23 
24 Previous section showed how to register only one version for each component including the car
25 itself. Attempting to add another car to container like in example below, will fail due to simple problem:
26 Both cars are identified in container by their type.
27 
28 -----------------
29     register!Car
30         .construct(lref!Size)
31         .set!"color"(lref!Color);
32 
33     register!Car
34         .construct(lref!Size)
35         .set!"color"(Color(0, 0, 0));
36 -----------------
37 
38 Running in modified container configuration in context of previous tutorial's example will end
39 in output from below, were last registered instance of Car component overrides the previously
40 defined.
41 
42 -----------------
43 You bought a new car with following specs:
44 Size:	Size(200, 150, 500)
45 Color:	Color(0, 0, 0)
46 -----------------
47 
48 Each registered component in a container is associated with an identity in it. In case with
49 car for previous examples, the Car component is associated with identity representing it’s Type. To
50 avoid associating a component by it’s type during registration, pass it’s identity as an argument to
51 $(D_INLINECODE register) method, like in example below. A component can also be associated with an interface it
52 implements by inserting desired interface before the type of registered component.
53 
54 -----------------
55 with (container.configure) {
56     register!Color("color.green") // Register "green" color into container.
57         .set!"r"(cast(ubyte) 0)
58         .set!"g"(cast(ubyte) 255)
59         .set!"b"(cast(ubyte) 0);
60 
61     register!Color("color.blue") // Register "blue" color into container.
62         .set!"r"(cast(ubyte) 0)
63         .set!"g"(cast(ubyte) 0)
64         .set!"b"(cast(ubyte) 255);
65 
66     register!Size("size.sedan") // Register a size of a generic "sedan" into container
67         .set!"width"(200UL)
68         .set!"height"(150UL)
69         .set!"length"(500UL);
70 
71     register!Size("size.smart_car") // Register a size of a generic smart car into container
72         .set!"width"(200UL)
73         .set!"height"(150UL)
74         .set!"length"(300UL);
75 
76     register!Car("sedan.green") // Register a car with sedan sizes and of green color.
77         .construct("size.sedan".lref)
78         .set!"color"("color.green".lref);
79 
80     register!Car("smarty.blue") // Register a car with smart car sizes and of a blue color.
81         .construct("size.smart_car".lref)
82         .set!"color"("color.blue".lref);
83 
84     register!Car("sedan.blue") // Register a car with sedan car sizes and of a blue color.
85         .construct("size.sedan".lref)
86         .set!"color"("color.blue".lref);
87 }
88 -----------------
89 
90 To reference a component that has custom identity, in a configuration or reliant component,
91 use $(D_INLINECODE lref("custom-associated-identity")) notation. Seeing this type of reference, framework
92 will attempt to search component by this identity, and serve it to component that is in con-
93 struction. Thanks to unified function call syntax (UFCS) available in D programming language,
94 lref("custom-associated-identity") can be rewritten into a more pleasant view $(D_INLINECODE "custom-associated-identity".lref).
95 To extract manually a component with custom identity pass the identity to $(D_INLINECODE locate)
96 method as first argument, along with type of component.
97 
98 Running fixed version of configuration, will yield in printing all three cars from code above into
99 stdout in output below. To be sure that all modifications done in this tutorial are working, run the
100 application to see following output:
101 
102 -----------------
103 You bough a new car sedan green with following specs:
104 Size:	Size(200, 150, 500)
105 Color:	Color(0, 255, 0)
106 You bough a new car sedan blue with following specs:
107 Size:	Size(200, 150, 500)
108 Color:	Color(0, 0, 255)
109 You bough a new car smarty blue with following specs:
110 Size:	Size(200, 150, 300)
111 Color:	Color(0, 0, 255)
112 -----------------
113 
114 Check example below. Play with it, to get the gist of named components.
115 
116 License:
117 	Boost Software License - Version 1.0 - August 17th, 2003
118 
119 	Permission is hereby granted, free of charge, to any person or organization
120 	obtaining a copy of the software and accompanying documentation covered by
121 	this license (the "Software") to use, reproduce, display, distribute,
122 	execute, and transmit the Software, and to prepare derivative works of the
123 	Software, and to permit third-parties to whom the Software is furnished to
124 	do so, all subject to the following:
125 
126 	The copyright notices in the Software and this entire statement, including
127 	the above license grant, this restriction and the following disclaimer,
128 	must be included in all copies of the Software, in whole or in part, and
129 	all derivative works of the Software, unless such copies or derivative
130 	works are solely in the form of machine-executable object code generated by
131 	a source language processor.
132 
133 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
134 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
135 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
136 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
137 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
138 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
139 	DEALINGS IN THE SOFTWARE.
140 
141 Authors:
142 	aermicioi
143 **/
144 
145 module named_dependencies;
146 
147 import aermicioi.aedi;
148 import std.stdio;
149 
150 /**
151 A struct that should be managed by container.
152 **/
153 struct Color {
154     ubyte r;
155     ubyte g;
156     ubyte b;
157 }
158 
159 /**
160 Size of a car.
161 **/
162 struct Size {
163 
164     ulong width;
165     ulong height;
166     ulong length;
167 }
168 
169 /**
170 A class representing a car.
171 **/
172 class Car {
173 
174     private {
175         Color color_; // Car color
176         Size size_; // Car size
177     }
178 
179     public {
180 
181         /**
182         Constructor of car.
183 
184         Constructs a car with a set of sizes. A car cannot of course have
185         undefined sizes, so we should provide it during construction.
186 
187         Params:
188             size = size of a car.
189         **/
190         this(Size size) {
191             this.size_ = size;
192         }
193 
194         @property {
195 
196             /**
197             Set color of car
198 
199             Set color of car. A car can live with undefined color (physics allow it).
200 
201             Params:
202             	color = color of a car.
203 
204             Returns:
205             	Car
206             **/
207             Car color(Color color) @safe nothrow {
208             	this.color_ = color;
209 
210             	return this;
211             }
212 
213             Color color() @safe nothrow {
214             	return this.color_;
215             }
216 
217             Size size() @safe nothrow {
218             	return this.size_;
219             }
220         }
221     }
222 }
223 
224 void print(Car car, string name) {
225     writeln("You bought a new car ", name," with following specs:");
226     writeln("Size:\t", car.size());
227     writeln("Color:\t", car.color());
228 }
229 
230 void main() {
231     SingletonContainer container = singleton(); // Creating container that will manage a color
232     scope(exit) container.terminate();
233 
234     with (container.configure) {
235         register!Color("color.green") // Register "green" color into container.
236             .set!"r"(cast(ubyte) 0)
237             .set!"g"(cast(ubyte) 255)
238             .set!"b"(cast(ubyte) 0);
239 
240         register!Color("color.blue") // Register "blue" color into container.
241             .set!"r"(cast(ubyte) 0)
242             .set!"g"(cast(ubyte) 0)
243             .set!"b"(cast(ubyte) 255);
244 
245         register!Size("size.sedan") // Register a size of a generic "sedan" into container
246             .set!"width"(200UL)
247             .set!"height"(150UL)
248             .set!"length"(500UL);
249 
250         register!Size("size.smart_car") // Register a size of a generic smart car into container
251             .set!"width"(200UL)
252             .set!"height"(150UL)
253             .set!"length"(300UL);
254 
255         register!Car("sedan.green") // Register a car with sedan sizes and of green color.
256             .construct("size.sedan".lref)
257             .set!"color"("color.green".lref);
258 
259         register!Car("smarty.blue") // Register a car with smart car sizes and of a blue color.
260             .construct("size.smart_car".lref)
261             .set!"color"("color.blue".lref);
262 
263         register!Car("sedan.blue") // Register a car with sedan car sizes and of a blue color.
264             .construct("size.sedan".lref)
265             .set!"color"("color.blue".lref);
266     }
267 
268 
269     container.instantiate(); // Boot container (or prepare managed code/data).
270 
271     container.locate!Car("sedan.green").print("sedan green");
272     container.locate!Car("sedan.blue").print("sedan blue");
273     container.locate!Car("smarty.blue").print("smarty blue");
274 }