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 At certian point of time the manufacturer decided that their car factory should provide cars with different engines,
13 electric/diesel/gasoline based on user preference. Therefore the application itself needed to be reconfigured to
14 satisfy user needs.
15 
16 The workflow needed to implement in application in order to allow 3 different configurations is
17 shown below and consists of following steps:
18 $(OL
19     $(LI read profile argument from command line or environment )
20     $(LI switch on it, and register diesel/gasoline/electric engine by Engine interface depending on selected profile )
21 )
22 
23 Aedi does provide basic containers singleton and prototype, which can be combined into some-
24 thing more complex. Though, on top of their behavior additional one can be built, such as a container
25 that can be enabled/disabled, or a container that adds observer pattern. Out of the box framework does provide
26 following decorating containers:
27 
28 $(UL
29     $(LI aliasing - provides aliasing functions)
30     $(LI gc rigistered - registers instantiated components with gc, when other that gc allocator are used)
31     $(LI subscribable - provides observable pattern on container events)
32     $(LI typed - serves components based on their implemented interfaces)
33     $(LI proxy - serves component proxies instead of original ones)
34     $(LI deffered - provides deffered construction of components)
35     $(LI describing - allows to register description for components that can be used later for help information)
36 )
37 
38 Following snippet of code shows all decorating containers in use except of proxy one.
39 ------------------
40 auto decorated() {
41     auto gasoline = singleton.typed.switchable.enabled(false);
42     auto electric = singleton.typed.switchable.enabled(false);
43     auto diesel = singleton.typed.switchable.enabled(false);
44 
45     auto cont = aggregate(
46         singleton, "singleton",
47         prototype, "prototype",
48         values, "parameters",
49         gasoline, "gasoline",
50         electric, "electric",
51         diesel, "diesel"
52     ).aliasing.gcRegistered.deffered.describing("Car factory", "Car factory, please see available contents of our factory");
53 
54     return cont
55         .subscribable
56         .subscribe(
57             ContainerInstantiationEventType.pre,
58             {
59                 cont.locate!Switchable(cont.locate!string("profile")).enabled = true;
60             }
61         );
62 }
63 ------------------
64 
65 The profile based container is assembled from 3 typed and switchable containers joined together into a subscribable
66 composite container with gc component registration, construction of deffered components and describing capabilities.
67 When the application is booted up, the code from $(D_INLINECODE main(string[] args)) loads into container
68 "profile" argument. Afterwards components are registered into container, and for each profile,
69 the right engine is registered in respective gasoline, electric, diesel containers. Once this
70 is finished, the container is instantiated using $(D_INLINECODE intantiate) method. During instantiation phase,
71 subscribable composite container fires an pre-instantiation event on which, a delegate is attached, that
72 checks for "profile" argument, and enables the container identified by value in profile container.
73 Afterwards construction of components proceeds. When car is constructed typed container jumps in and
74 provides an implenentation of $(D_INLINECODE Engine) for car depending on enabled container. When
75 construction arrives at a Tire, a circular dependency is detected, and construction of a component is
76 deffered at later stage in order to break dependency chain. Once component is constructed, it is registered
77 with global gc instance in order to avoid destruction of gc managed components while they are still referenced
78 by non-gc-managed components. Once instantiation is finished, car is fetched from container and displayed in console.
79 
80 Each of decorating container shown in example above will be explained in detail below.
81 
82 Aliasing:
83 
84 The aliasing container decorator adds ability to add aliases to existing components in container. Therefore
85 a "foo" component can have multiple aliases "moo", "boo" etc. Each alias will resolve to same component in container.
86 Such feature is useful when an existing component in container for compatibility reasons should have another identity as
87 well. To use aliasing container simply wrap any container in $(D_INLINECODE aliasing) method which will decorate existing one.
88 UFCS syntax is desired for fluent like style.
89 
90 -----------------
91 auto cont = aggregate(
92     singleton, "singleton",
93     prototype, "prototype",
94     values, "parameters",
95     gasoline, "gasoline",
96     electric, "electric",
97     diesel, "diesel"
98 ).aliasing;
99 -----------------
100 
101 GcRegistered:
102 
103 GC registered decorating container registers any created component with global gc available in D. Since any component can have customized
104 memory allocation strategy through std.experimental.allocator, were one of strategy is to use garbage collector, and each component
105 can have dependencies to other components, in some cases, gc on collection cycle could deallocate a component (which technically isn't
106 referenced by anyone) even if it is still referenced by other component of which gc is not aware of. GC registered container aims to register
107 all public components provided by underlying container into GC in order to avoid the case from above. To use it, just suffix any container with $(D_INLINECODE gcRegistered).
108 
109 -----------------
110 auto cont = aggregate(
111     singleton, "singleton",
112     prototype, "prototype",
113     values, "parameters",
114     gasoline, "gasoline",
115     electric, "electric",
116     diesel, "diesel"
117 ).aliasing.gcRegistered;
118 -----------------
119 
120 Subscribable:
121 
122 Subscribable container offers a list of events to which a listener can subscribe and perform operations on. Currently only two events are provided:
123 $(OL
124     $(LI instantiation pre event - fired before instantiation of container)
125     $(LI instantiation post event - fired after instantiation of container)
126 )
127 An example of such listeners can be like in listing below, which will enable a container before instantiation based on profile argument
128 -----------------
129 cont.subscribable
130     .subscribe(
131         ContainerInstantiationEventType.pre,
132         {
133             cont.locate!Switchable(cont.locate!string("profile")).enabled = true;
134         }
135     );
136 -----------------
137 
138 Typed:
139 
140 Typed container decorates underlying container with ability to provide a component based on interface it implements.
141 Code using typed container attempts to get a component by an interface such as $(D_INLINECODE Engine) in this example,
142 typed container will check if underlying container has a component identified by provided interface. If yes it will give
143 the component from decorated container. If not, it will search for all registered components that implement the required interface
144 and use first found component to serve it. Notice that in this example, no $(D_INLINECODE Engine) was registered in container by
145 $(D_INLINECODE Engine) interface. Each instance $(D_INLINECODE GasolineEngine), $(D_INLINECODE ElectricEngine), and $(D_INLINECODE DieselEngine)
146 are registered by their type only. No attempt to alias one of them to $(D_INLINECODE Engine) is done, yet when Car is instantiated, a component
147 implementing $(D_INLINECODE Engine) interface is supplied. This magic is done by typed container, which supplied first available component implementing
148 $(D_INLINECODE Engine) interface.
149 
150 Proxy:
151 
152 A proxy container proxies all components supplied by decorated container. It will supply proxy objects instead of real components, which in turn
153 will on each public call of a proxy will redirect it to component in redirected container, and return a value from it. The proxy container
154 alone is not much useful. It is intended to be used along with containers that are dependendet on some global state to provide components.
155 An example of such containers could be containers that provide different instances of same component per thread or fiber, or in case of
156 web application, a container that gives new instances of same component for each new available request web application receives.
157 
158 Deffered:
159 
160 Deffered container, executes delayed components construction and configuration. Construction and configuration of a component can occur in cases
161 when there is a circular dependency between a set of components. In such case to resolve it, injection of one dependency can be delayed.
162 Delaying of construction or configuration is left to component factory, while execution of delayed action is enforced upon Deffered container.
163 To enable circular dependency resolution, decorate container with $(D_INLINECODE deffered) decorator, and register components using $(D_INLINECODE withConfigurationDefferring)
164 configuration context (simply append it after $(D_INLINECODE container.configure) method). This exampe shows a typical example of circular
165 dependency. A car has a dependency on four tires, while each tire has a dependency on a car instance, resulting in a circular dependency.
166 Removing $(D_INLINECODE deffered) or $(D_INLINECODE withConfigurationDefferring) will result in circular dependency exception thrown by container.
167 
168 Describing:
169 
170 Describing container, adds ability to store description for the container itself, and components that are managed in decorated container. Main purpose
171 of this type of container is to be used in storing description that will be used for help information (usually displayed in command line).
172 --------------------------
173 auto cont = aggregate(
174         singleton, "singleton",
175         prototype, "prototype",
176         values, "parameters",
177         gasoline, "gasoline",
178         electric, "electric",
179         diesel, "diesel"
180     ).aliasing.gcRegistered.deffered.describing("Car factory", "Car factory, please see available contents of our factory");
181 --------------------------
182 
183 Registering a description can happen in two ways:
184 $(OL
185     $(LI By using $(D_INLINECODE .describe) that adds a description on registered component))
186     $(LI adding description directly to identity describer)
187 )
188 
189 Both ways are shown in example below:
190 --------------------------
191 with (cont.configureValueContainer("parameters")) {
192 
193     register(verbose, "verbose").describe("verbose errors", "whether to show or not appearing errors.");
194 
195     if (profile !is null) {
196         register(profile, "profile");
197     }
198 
199     with (cont.locate!(IdentityDescriber!())) {
200         register("profile", "Car enginge type", "Type of engine to select while building a car (gasoline|diesel|electric|ecological).");
201     }
202 }
203 --------------------------
204 
205 The first line is using first option for registering descriptions, where $(D_INLINECODE .describe) method will query locator for $(D_INLINECODE IdentityDescriber!())
206 component which hosts those descriptions and then will register the description in it if found. If not a $(D_INLINECODE NotFoundException)  will be thrown.
207 
208 Notice that $(D_INLINECODE profile) is wrapped in a if conditional. This is done intenionally in the example to simulate a missing profile setting
209 when none is passed through command line, however the same situation could happen with $(D_INLINECODE switchable) container where even if component
210 is registered it could not be available at run time.
211 
212 Last $(D_INLINECODE with) statement is the second variant of configuration, where instead of using $(D_INLINECODE .describe) entire registration of description
213 is done manually. It is better to use first method for registering descriptions, while the latter only in cases when first is not possible, just like in the
214 example where missing property is simulated. This will work with $(D_INLINECODE switchable) container since we do register those components, yet they won't
215 be available at runtime.
216 
217 Second registration version used $(D_INLINECODE IdentityDescriber!()) component, which itself is a component that describing container delegates the task of
218 describing components. Besides $(D_INLINECODE IdentityDescriber!()) used as main describer, container has also a describer for itself or decorated container,
219 and a fallback describer that is used in case main one can't describe a component. All three of them are of $(D_INLINECODE Describer!()) interface, and it is
220 possible to pass them in $(D_INLINECODE describing) container as arguments. By default following implementations are available:
221 $(OL
222     $(LI $(D_INLINECODE IdentityDescriber!()) - a describer that describes data based upon identity of component)
223     $(LI $(D_INLINECODE TypeDescriber!()) - a describer that uses a template and formatter for identity and component itself to generate a description)
224     $(LI $(D_INLINECODE StaticDescriber!()) - a describer that will provide same description no matter what is passed)
225     $(LI $(D_INLINECODE NullDescriber!()) - a describer that does not describe anyhting)
226 )
227 
228 Rendering of stored description can happen like in example below:
229 --------------------------
230 if (help.helpWanted) {
231     defaultGetoptPrinter(
232         cont.locate!(Describer!()).describe(null, cont).description,
233         cont.locate!(DescriptionsProvider!string)
234             .provide
235             .map!(description => Option(null, description.identity, text(description.title, " - ", description.description)))
236             .array
237     );
238     return;
239 }
240 
241 try {
242 
243     cont.instantiate();
244 
245     cont.locate!Car.drive(profile);
246 } catch (AediException e) {
247     foreach (throwable; e.exceptions.filterByInterface!NotFoundException) {
248         defaultGetoptPrinter(
249             text("Missing \"", e.identity, "\" for proper functioning, please see detailed info of missing piece below. For more detailed options run with --help"),
250             cont.locate!(Describer!()).describe(e.identity, null)
251                 .only
252                 .filter!(description => !description.isNull)
253                 .map!(description => Option(null, description.identity, text(description.title, " - ", description.description), true))
254                 .array
255         );
256 
257         break;
258     }
259 
260     if (cont.locate!bool("verbose")) {
261         throw e;
262     }
263 }
264 --------------------------
265 
266 In case if help is required, or in other words all descriptions registered at certain point, a $(D_INLINECODE DescriptionsProvider!string) should be
267 located fetched from container and asked to provide all available descriptions. Coincidentally $(D_INLINECODE IdentityDescriber!()) implements also
268 $(D_INLINECODE DescriptionsProvider!string) and therefore it will be fetched from container once asked by provider interface it implements.
269 
270 Since $(D_INLINECODE describing) container is mostly geared towards being queried for description based on identity of a component and component itself,
271 it is also possible to provide targeted info per problematic aspect encountered during application running, such as missing component in container, profile for
272 example. Try - catch statement in example uses this functionality to print message about missing component, and its description.
273 
274 Try running this example, pass as argument $(D_INLINECODE --profile) with value of
275 $(D_INLINECODE gasoline), $(D_INLINECODE electric), $(D_INLINECODE diesel).
276 Experiment with it, to understand decorating containers.
277 
278 License:
279 	Boost Software License - Version 1.0 - August 17th, 2003
280 
281 	Permission is hereby granted, free of charge, to any person or organization
282 	obtaining a copy of the software and accompanying documentation covered by
283 	this license (the "Software") to use, reproduce, display, distribute,
284 	execute, and transmit the Software, and to prepare derivative works of the
285 	Software, and to permit third-parties to whom the Software is furnished to
286 	do so, all subject to the following:
287 
288 	The copyright notices in the Software and this entire statement, including
289 	the above license grant, this restriction and the following disclaimer,
290 	must be included in all copies of the Software, in whole or in part, and
291 	all derivative works of the Software, unless such copies or derivative
292 	works are solely in the form of machine-executable object code generated by
293 	a source language processor.
294 
295 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
296 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
297 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
298 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
299 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
300 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
301 	DEALINGS IN THE SOFTWARE.
302 
303 Authors:
304 	aermicioi
305 **/
306 
307 module decorating_containers;
308 
309 import aermicioi.aedi;
310 import aermicioi.aedi.util.range : exceptions, filterByInterface;
311 import std.stdio;
312 import std.algorithm;
313 import std.range;
314 import std.array;
315 import std.conv : text;
316 import std.experimental.allocator.mallocator;
317 import std.experimental.allocator;
318 
319 /**
320 A struct that should be managed by container.
321 **/
322 struct Color {
323     ubyte r;
324     ubyte g;
325     ubyte b;
326 }
327 
328 /**
329 Size of a car.
330 **/
331 struct Size {
332 
333     ulong width;
334     ulong height;
335     ulong length;
336 }
337 
338 /**
339 Interface for engines.
340 
341 An engine should implement it, in order to be installable in a car.
342 **/
343 interface Engine {
344 
345     public {
346 
347         void turnOn();
348         void run();
349         void turnOff();
350     }
351 }
352 
353 /**
354 A concrete implementation of Engine that uses gasoline for propelling.
355 **/
356 class GasolineEngine : Engine {
357 
358     public {
359 
360         void turnOn() {
361             writeln("pururukVrooomVrrr");
362 
363         }
364 
365         void run() {
366             writeln("vrooom");
367         }
368 
369         void turnOff() {
370             writeln("vrrrPrrft");
371         }
372     }
373 }
374 
375 /**
376 A concrete implementation of Engine that uses diesel for propelling.
377 **/
378 class DieselEngine : Engine {
379 
380     public {
381 
382         void turnOn() {
383             writeln("pururukVruumVrrr");
384 
385         }
386 
387         void run() {
388             writeln("vruum");
389         }
390 
391         void turnOff() {
392             writeln("vrrrPft");
393         }
394     }
395 }
396 
397 /**
398 A concrete implementation of Engine that uses electricity for propelling.
399 **/
400 class ElectricEngine : Engine {
401     public {
402 
403         void turnOn() {
404             writeln("pzt");
405 
406         }
407 
408         void run() {
409             writeln("vvvvvvvvv");
410         }
411 
412         void turnOff() {
413             writeln("tzp");
414         }
415     }
416 }
417 
418 /**
419 Tire, what it can represent else?
420 **/
421 class Tire {
422     private {
423         int size_;
424         float pressure_;
425         string vendor_;
426         Car car_;
427     }
428 
429     public @property {
430         @autowired
431         Tire car(Car car) {
432             this.car_ = car;
433             return this;
434         }
435 
436         Car car() {
437             return this.car_;
438         }
439 
440         Tire size(int size) @safe nothrow {
441         	this.size_ = size;
442 
443         	return this;
444         }
445 
446         int size() @safe nothrow {
447         	return this.size_;
448         }
449 
450         Tire pressure(float pressure) @safe nothrow {
451         	this.pressure_ = pressure;
452 
453         	return this;
454         }
455 
456         float pressure() @safe nothrow {
457         	return this.pressure_;
458         }
459 
460         Tire vendor(string vendor) @safe nothrow {
461         	this.vendor_ = vendor;
462 
463         	return this;
464         }
465 
466         string vendor() @safe nothrow {
467         	return this.vendor_;
468         }
469     }
470 
471     public override string toString() {
472         import std.algorithm;
473         import std.range;
474         import std.conv;
475         import std.utf;
476 
477         return only("Tire(", this.size.to!string, " inch, ", this.pressure.to!string, " atm, ", this.vendor, ")")
478             .joiner
479             .byChar
480             .array;
481     }
482 }
483 
484 /**
485 A class representing a car.
486 **/
487 class Car {
488 
489     private {
490         Color color_; // Car color
491         Size size_; // Car size
492         Engine engine_; // Car engine
493 
494         Tire frontLeft_;
495         Tire frontRight_;
496         Tire backLeft_;
497         Tire backRight_;
498     }
499 
500     public {
501 
502         /**
503         Constructor of car.
504 
505         Constructs a car with a set of sizes. A car cannot of course have
506         undefined sizes, so we should provide it during construction.
507 
508         Params:
509             size = size of a car.
510         **/
511         this(Size size, Engine engine) {
512             this.size_ = size;
513             this.engine = engine;
514         }
515 
516         @property {
517 
518             /**
519             Set color of car
520 
521             Set color of car. A car can live with undefined color (physics allow it).
522 
523             Params:
524             	color = color of a car.
525 
526             Returns:
527             	Car
528             **/
529             Car color(Color color) @safe nothrow {
530             	this.color_ = color;
531 
532             	return this;
533             }
534 
535             Color color() @safe nothrow {
536             	return this.color_;
537             }
538 
539             Size size() @safe nothrow {
540             	return this.size_;
541             }
542 
543             /**
544             Set engine used in car.
545 
546             Params:
547             	engine = engine used in car to propel it.
548 
549             Returns:
550             	Car
551             **/
552             Car engine(Engine engine) @safe nothrow {
553             	this.engine_ = engine;
554 
555             	return this;
556             }
557 
558             Engine engine() @safe nothrow {
559             	return this.engine_;
560             }
561 
562             Car frontLeft(Tire frontLeft) @safe nothrow {
563             	this.frontLeft_ = frontLeft;
564 
565             	return this;
566             }
567 
568             Tire frontLeft() @safe nothrow {
569             	return this.frontLeft_;
570             }
571 
572             Car frontRight(Tire frontRight) @safe nothrow {
573             	this.frontRight_ = frontRight;
574 
575             	return this;
576             }
577 
578             Tire frontRight() @safe nothrow {
579             	return this.frontRight_;
580             }
581 
582             Car backLeft(Tire backLeft) @safe nothrow {
583             	this.backLeft_ = backLeft;
584 
585             	return this;
586             }
587 
588             Tire backLeft() @safe nothrow {
589             	return this.backLeft_;
590             }
591 
592             Car backRight(Tire backRight) @safe nothrow {
593             	this.backRight_ = backRight;
594 
595             	return this;
596             }
597 
598             Tire backRight() @safe nothrow {
599             	return this.backRight_;
600             }
601 
602         }
603 
604         void start() {
605             engine.turnOn();
606         }
607 
608         void run() {
609             engine.run();
610         }
611 
612         void stop() {
613             engine.turnOff();
614         }
615     }
616 }
617 
618 void drive(Car car, string name) {
619     writeln("Uuh, what a nice ", name," car, with following specs:");
620     writeln("Size:\t", car.size);
621     writeln("Color:\t", car.color);
622     writeln("Engine:\t", car.engine);
623     writeln("Tire front left:\t", car.frontLeft, "\t located at memory ", cast(void*) car.frontLeft());
624     writeln("Tire front right:\t", car.frontRight, "\t located at memory ", cast(void*) car.frontRight());
625     writeln("Tire back left: \t", car.backLeft, "\t located at memory ", cast(void*) car.backLeft());
626     writeln("Tire back right:\t", car.backRight, "\t located at memory ", cast(void*) car.backRight());
627 }
628 
629 auto decorated() {
630     auto gasoline = singleton.typed.switchable.enabled(false);
631     auto electric = singleton.typed.switchable.enabled(false);
632     auto diesel = singleton.typed.switchable.enabled(false);
633 
634     auto cont = aggregate(
635         singleton, "singleton",
636         prototype, "prototype",
637         values, "parameters",
638         gasoline, "gasoline",
639         electric, "electric",
640         diesel, "diesel"
641     ).aliasing.gcRegistered.deferred.describing("Car factory", "Car factory, please see available contents of our factory");
642 
643     return cont
644         .subscribable
645         .subscribe(
646             ContainerInstantiationEventType.pre,
647             {
648                 cont.locate!Switchable(cont.locate!string("profile")).enabled = true;
649             }
650         );
651 }
652 
653 void main(string[] args) {
654 
655     auto cont = decorated();
656     scope(exit) container.terminate();
657 
658     import std.getopt;
659     string profile;
660     bool verbose;
661 
662     auto help = getopt(args,
663         "p|profile", &profile,
664         "v|verbose", &verbose
665     );
666 
667     with (cont.configureValueContainer("parameters")) {
668 
669         register(verbose, "verbose").describe("verbose errors", "whether to show or not appearing errors.");
670 
671         if (profile !is null) {
672             register(profile, "profile");
673         }
674 
675         with (cont.locate!(IdentityDescriber!())) {
676             register("profile", "Car enginge type", "Type of engine to select while building a car (gasoline|diesel|electric|ecological).");
677         }
678     }
679 
680     with (cont.configure("singleton", Mallocator.instance.allocatorObject)) {
681         register!Color;
682 
683         register!Size
684             .set!"width"(200UL)
685             .set!"height"(150UL)
686             .set!"length"(300UL)
687             .describe("Car size", "Rough estimations of car size that will be produced");
688 
689         register!Car
690             .autowire
691             .autowire!"color"
692             .set!"frontLeft"(lref!Tire)
693             .set!"frontRight"(lref!Tire)
694             .set!"backLeft"(lref!Tire)
695             .set!"backRight"(lref!Tire)
696             .describe("The car", "The car our factory constructed");
697     }
698 
699     with (cont.configure("prototype")) {
700         register!Tire
701             .autowire!"car"
702             .set!"size"(17)
703             .set!"pressure"(3.0)
704             .set!"vendor"("Divine tire")
705             .describe("Divine tire", "A template of a divine tire used in our car.");
706     }
707 
708     cont.configure("diesel").register!DieselEngine;
709     cont.configure("gasoline").register!GasolineEngine;
710     cont.configure("electric").register!ElectricEngine;
711 
712     cont.link("electric", "ecological");
713 
714     if (help.helpWanted) {
715         defaultGetoptPrinter(
716             cont.locate!(Describer!()).describe(null, cont).description,
717             cont.locate!(DescriptionsProvider!string)
718                 .provide
719                 .map!(description => Option(null, description.identity, text(description.title, " - ", description.description)))
720                 .array
721         );
722         return;
723     }
724 
725     try {
726 
727         cont.instantiate();
728 
729         cont.locate!Car.drive(profile);
730     } catch (AediException e) {
731         foreach (throwable; e.exceptions.filterByInterface!NotFoundException) {
732             defaultGetoptPrinter(
733                 text("Missing \"", e.identity, "\" for proper functioning, please see detailed info of missing piece below. For more detailed options run with --help"),
734                 cont.locate!(Describer!()).describe(e.identity, null)
735                     .only
736                     .filter!(description => !description.isNull)
737                     .map!(description => Option(null, description.identity, text(description.title, " - ", description.description), true))
738                     .array
739             );
740 
741             break;
742         }
743 
744         if (cont.locate!bool("verbose")) {
745             throw e;
746         }
747     }
748 }