1 /** 2 License: 3 Boost Software License - Version 1.0 - August 17th, 2003 4 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 27 Authors: 28 aermicioi 29 **/ 30 module aermicioi.aedi_property_reader.helper.help_decorating_container; 31 32 import aermicioi.aedi_property_reader.helper.help_decorating_information_provider; 33 import aermicioi.aedi_property_reader.helper.help_decorating_exception; 34 import aermicioi.aedi_property_reader.helper.help_needing_exception; 35 import aermicioi.aedi.exception.not_found_exception; 36 import aermicioi.aedi.exception.di_exception; 37 import aermicioi.aedi.storage.storage; 38 import aermicioi.aedi.storage.locator; 39 import aermicioi.aedi.storage.alias_aware; 40 import aermicioi.aedi.storage.decorator; 41 import aermicioi.aedi.container.container; 42 import aermicioi.aedi.factory.factory; 43 import std.range.interfaces; 44 import std.typecons; 45 import std.algorithm; 46 47 /** 48 An interface for class that can toggle on or off help information. 49 **/ 50 interface HelpInformationToggable { 51 @property { 52 /** 53 Set on or off help information displaying. 54 55 Params: 56 helpEnabled = whether help info is enabled or not 57 58 Returns: 59 typeof(this) 60 **/ 61 HelpInformationToggable helpEnabled(bool helpEnabled) @safe nothrow; 62 } 63 } 64 65 /** 66 Templated help decorating container. 67 68 Templated help decorating container. This decorated will 69 decorate a container, and add help information logic 70 to it. Depending if help information is on or off, it 71 will display or not help information on stdout for end user. 72 This decorated will inherit following interfaces only and only if the 73 T also implements them: 74 $(UL 75 $(LI $(D_INLINECODE Storage!(ObjectFactory, string))) 76 $(LI $(D_INLINECODE Container)) 77 $(LI $(D_INLINECODE AliasAware!string)) 78 $(LI $(D_INLINECODE FactoryLocator!ObjectFactory)) 79 ) 80 81 Following interface is a must for decorated container: 82 $(UL 83 $(LI $(D_INLINECODE Locator!())), 84 ) 85 86 Params: 87 T = The decorated that switchable decorated will decorate. 88 89 **/ 90 template HelpDecoratingContainer(T) { 91 import std.meta; 92 import std.traits; 93 import aermicioi.util.traits; 94 95 /** 96 Set which the switchable decorated will decorate for T. By default 97 Locator!() and Switchable is included. 98 **/ 99 alias InheritanceSet = NoDuplicates!(Filter!( 100 templateOr!( 101 partialSuffixed!( 102 isDerived, 103 Storage!(ObjectFactory, string) 104 ), 105 partialSuffixed!( 106 isDerived, 107 AliasAware!string 108 ), 109 partialSuffixed!( 110 isDerived, 111 FactoryLocator!ObjectFactory 112 ), 113 partialSuffixed!( 114 isDerived, 115 Container 116 ) 117 ), 118 InterfacesTuple!T), 119 Locator!(), 120 MutableDecorator!T, 121 HelpInformationToggable, 122 ); 123 124 /** 125 Templated help decorating container. 126 **/ 127 class HelpDecoratingContainer : InheritanceSet { 128 private { 129 T decorated_; 130 HelpInformationProvider[] providers_; 131 132 bool helpEnabled_; 133 } 134 135 public { 136 137 /** 138 Set on or off help information displaying. 139 140 Params: 141 helpEnabled = whether help info is enabled or not 142 143 Returns: 144 typeof(this) 145 **/ 146 HelpDecoratingContainer helpEnabled(bool helpEnabled) @safe nothrow { 147 this.helpEnabled_ = helpEnabled; 148 149 return this; 150 } 151 152 /** 153 Get helpEnabled 154 155 Returns: 156 bool 157 **/ 158 bool helpEnabled() @safe nothrow { 159 return this.helpEnabled_; 160 } 161 162 /** 163 Set the decorated container 164 165 Params: 166 decorated = container to be decorated 167 168 Returns: 169 HelpDecoratingContainer!T decorating container. 170 **/ 171 HelpDecoratingContainer!T decorated(T decorated) @safe nothrow { 172 this.decorated_ = decorated; 173 174 return this; 175 } 176 177 178 /** 179 Get the decorated container. 180 181 Returns: 182 inout(T) decorated container 183 **/ 184 T decorated() @safe nothrow { 185 return this.decorated_; 186 } 187 188 /** 189 Add a help provider 190 191 Params: 192 provider = help provider that supplies help text 193 194 Returns: 195 typeof(this) 196 **/ 197 HelpDecoratingContainer addHelpProvider(HelpInformationProvider provider) { 198 this.providers_ ~= provider; 199 200 return this; 201 } 202 203 /** 204 Remove a help provider from help decorating container 205 206 Params: 207 key = index of provider to be removed 208 209 Returns: 210 typeof(this) 211 **/ 212 HelpDecoratingContainer removeHelpProvider(size_t key) { 213 import std.algorithm; 214 this.providers_ = this.providers_.remove(key); 215 216 return this; 217 } 218 219 /** 220 Get help provider used by help decorating container 221 222 Params: 223 key = index of fetched provider 224 Throws: 225 NotFoundException when no decorator is present 226 Returns: 227 HelpInformationProvider 228 **/ 229 HelpInformationProvider getHelpProvider(size_t key) { 230 231 if (key >= this.providers_.length) { 232 throw new NotFoundException("Help provider not found"); 233 } 234 235 return this.providers_[key]; 236 } 237 238 static if (is(T : Container)) { 239 240 /** 241 Prepare decorated to be used. 242 243 Prepare decorated to be used. 244 245 Returns: 246 HelpDecoratingContainer!T decorating container 247 **/ 248 HelpDecoratingContainer instantiate() { 249 try { 250 decorated.instantiate(); 251 } catch (AediException e) { 252 253 Throwable t = e; 254 255 do { 256 HelpDecoratingException signaler = cast(HelpDecoratingException) t; 257 258 if (signaler !is null) { 259 if (this.helpEnabled) { 260 throw new HelpNeedingException(this.providers_, signaler.next); 261 } 262 } 263 264 t = t.next; 265 } while (t !is null); 266 267 throw e.next; 268 } 269 270 return this; 271 } 272 } 273 274 static if (is(T : Storage!(ObjectFactory, string))) { 275 /** 276 Set factory in decorated by identity. 277 278 Params: 279 identity = identity of factory. 280 element = factory that is to be saved in decorated. 281 282 Return: 283 HelpDecoratingContainer!T decorating decorated. 284 **/ 285 HelpDecoratingContainer!T set(ObjectFactory element, string identity) { 286 decorated.set(element, identity); 287 288 return this; 289 } 290 291 /** 292 Remove factory from decorated with identity. 293 294 Remove factory from decorated with identity. 295 296 Params: 297 identity = the identity of factory to be removed. 298 299 Return: 300 HelpDecoratingContainer!T decorating decorated 301 **/ 302 HelpDecoratingContainer!T remove(string identity) { 303 decorated.remove(identity); 304 305 return this; 306 } 307 } 308 309 static if (is(T : AliasAware!string)) { 310 /** 311 Alias identity to an alias_. 312 313 Params: 314 identity = originial identity which is to be aliased. 315 alias_ = alias of identity. 316 317 Returns: 318 HelpDecoratingContainer!T decorating decorated 319 **/ 320 HelpDecoratingContainer!T link(string identity, string alias_) { 321 decorated.link(identity, alias_); 322 323 return this; 324 } 325 326 /** 327 Removes alias. 328 329 Params: 330 alias_ = alias to remove. 331 332 Returns: 333 HelpDecoratingContainer!T decorating decorated 334 **/ 335 HelpDecoratingContainer!T unlink(string alias_) { 336 decorated.unlink(alias_); 337 338 return this; 339 } 340 341 /** 342 Resolve an alias to original identity, if possible. 343 344 Params: 345 alias_ = alias of original identity 346 347 Returns: 348 const(string) the last identity in alias chain if decorated is enabled, or alias_ when not. 349 350 **/ 351 const(string) resolve(in string alias_) const { 352 return decorated_.resolve(alias_); 353 } 354 } 355 356 static if (is(T : FactoryLocator!ObjectFactory)) { 357 358 /** 359 Get factory for constructed component identified by identity. 360 361 Get factory for constructed component identified by identity. 362 Params: 363 identity = the identity of data that factory constructs. 364 365 Throws: 366 NotFoundException when factory for it is not found. 367 368 Returns: 369 T the factory for constructed data. 370 **/ 371 ObjectFactory getFactory(string identity) { 372 return this.decorated.getFactory(identity); 373 } 374 375 /** 376 Get all factories available in container. 377 378 Get all factories available in container. 379 380 Returns: 381 InputRange!(Tuple!(T, string)) a tuple of factory => identity. 382 **/ 383 InputRange!(Tuple!(ObjectFactory, string)) getFactories() { 384 return this.decorated.getFactories(); 385 } 386 } 387 388 /** 389 Get object that is associated with identity. 390 391 Params: 392 identity = the object identity. 393 394 Throws: 395 NotFoundException in case if the object wasn't found or decorated is not enabled. 396 397 Returns: 398 Object if it is available. 399 **/ 400 Object get(string identity) { 401 402 try { 403 404 return decorated.get(identity); 405 } catch (AediException e) { 406 407 Throwable t = e; 408 409 do { 410 HelpDecoratingException signaler = cast(HelpDecoratingException) t; 411 412 if (signaler !is null) { 413 if (this.helpEnabled) { 414 throw new HelpNeedingException(this.providers_, signaler.next); 415 } 416 } 417 418 t = t.next; 419 } while (t !is null); 420 421 throw e.next; 422 } 423 } 424 425 /** 426 Check if object is present in HelpDecoratingContainer!T by key identity. 427 428 Note: 429 This check should be done for elements that locator actually contains, and 430 not in chained locator (when locator is also a DelegatingLocator) for example. 431 Params: 432 identity = identity of object. 433 434 Returns: 435 bool true if decorated is enabled and has object by identity. 436 **/ 437 bool has(in string identity) inout { 438 return decorated_.has(identity); 439 } 440 } 441 } 442 }