Update copyrigths

And convert tabs to spaces
This commit is contained in:
Mike Bierlee 2018-01-01 15:54:32 +01:00
parent 9d0bbfd6cf
commit 4410206ec4
74 changed files with 2396 additions and 2384 deletions

1
.gitignore vendored
View file

@ -19,3 +19,4 @@
/.idea /.idea
/*.iml /*.iml
/out /out
/classes

View file

@ -1,4 +1,4 @@
Copyright (c) 2014-2017 Mike Bierlee Copyright (c) 2014-2018 Mike Bierlee
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,7 +1,7 @@
Poodinis Dependency Injection Framework Poodinis Dependency Injection Framework
======================================= =======================================
Version 8.0.1 Version 8.0.1
Copyright 2014-2017 Mike Bierlee Copyright 2014-2018 Mike Bierlee
Licensed under the terms of the MIT license - See [LICENSE.txt](LICENSE.txt) Licensed under the terms of the MIT license - See [LICENSE.txt](LICENSE.txt)
Master: [![Build Status](https://api.travis-ci.org/mbierlee/poodinis.png?branch=master)](https://travis-ci.org/mbierlee/poodinis) - Dev: [![Build Status](https://api.travis-ci.org/mbierlee/poodinis.png?branch=develop)](https://travis-ci.org/mbierlee/poodinis) Master: [![Build Status](https://api.travis-ci.org/mbierlee/poodinis.png?branch=master)](https://travis-ci.org/mbierlee/poodinis) - Dev: [![Build Status](https://api.travis-ci.org/mbierlee/poodinis.png?branch=develop)](https://travis-ci.org/mbierlee/poodinis)

View file

@ -83,7 +83,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -155,7 +155,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -101,7 +101,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -93,7 +93,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -106,7 +106,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -104,7 +104,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -177,7 +177,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -91,7 +91,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -207,7 +207,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -162,7 +162,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -97,7 +97,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -189,7 +189,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -109,7 +109,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -95,7 +95,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -95,7 +95,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -91,7 +91,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -91,7 +91,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -96,7 +96,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -96,7 +96,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -92,7 +92,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -107,7 +107,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -92,7 +92,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -116,7 +116,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -142,7 +142,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -92,7 +92,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -92,7 +92,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -92,7 +92,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -100,7 +100,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -83,7 +83,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -102,7 +102,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
Mike Bierlee (m.bierlee@lostmoment.com) Mike Bierlee (m.bierlee@lostmoment.com)
</p> </p>
<p>Copyright Digital Mars 2005 - 2009., Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-., 2014-2017 Mike Bierlee <p>Copyright Digital Mars 2005 - 2009., Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-., 2014-2018 Mike Bierlee
</p> </p>
<p>boost.org/LICENSE_1_0.txt, Boost License 1.0 <p>boost.org/LICENSE_1_0.txt, Boost License 1.0

View file

@ -121,7 +121,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -97,7 +97,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -95,7 +95,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -98,7 +98,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -156,7 +156,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -120,7 +120,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -106,7 +106,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -120,7 +120,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -106,7 +106,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -92,7 +92,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -103,7 +103,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -128,7 +128,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -92,7 +92,7 @@ document.getElementById('symbolSearchPane').style.display = 'block';</script>
<p>Mike Bierlee, m.bierlee@lostmoment.com <p>Mike Bierlee, m.bierlee@lostmoment.com
</p> </p>
<p>2014-2017 Mike Bierlee <p>2014-2018 Mike Bierlee
</p> </p>
<p>This software is licensed under the terms of the MIT license. <p>This software is licensed under the terms of the MIT license.

View file

@ -3,7 +3,7 @@
"description" : "A dependency injection framework with support for autowiring.", "description" : "A dependency injection framework with support for autowiring.",
"homepage": "http://lostmoment.com/open-source/poodinis", "homepage": "http://lostmoment.com/open-source/poodinis",
"authors": ["Mike Bierlee"], "authors": ["Mike Bierlee"],
"copyright": "Copyright 2014-2017 Mike Bierlee", "copyright": "Copyright 2014-2018 Mike Bierlee",
"license": "MIT", "license": "MIT",
"-ddoxTool": "scod", "-ddoxTool": "scod",
"configurations": [ "configurations": [

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -9,7 +9,7 @@
* *
* Authors: * Authors:
* Mike Bierlee, m.bierlee@lostmoment.com * Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2017 Mike Bierlee * Copyright: 2014-2018 Mike Bierlee
* License: * License:
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
@ -30,7 +30,7 @@ import std.string;
import std.traits; import std.traits;
import std.range; import std.range;
private struct UseMemberType {}; private struct UseMemberType {}
/** /**
* UDA for annotating class members as candidates for autowiring. * UDA for annotating class members as candidates for autowiring.
@ -66,15 +66,15 @@ private struct UseMemberType {};
* will also be autowired because the autowire mechanism knows that member "fuelEngine" is an instance of "FuelEngine" * will also be autowired because the autowire mechanism knows that member "fuelEngine" is an instance of "FuelEngine"
*/ */
struct Autowire(QualifierType) { struct Autowire(QualifierType) {
QualifierType qualifier; QualifierType qualifier;
}; }
/** /**
* UDA for marking autowired dependencies optional. * UDA for marking autowired dependencies optional.
* Optional dependencies will not lead to a resolveException when there is no type registered for them. * Optional dependencies will not lead to a resolveException when there is no type registered for them.
* The member will remain null. * The member will remain null.
*/ */
struct OptionalDependency {}; struct OptionalDependency {}
/** /**
* UDA for annotating class members to be autowired with a new instance regardless of their registration scope. * UDA for annotating class members to be autowired with a new instance regardless of their registration scope.
@ -92,7 +92,7 @@ struct OptionalDependency {};
struct AssignNewInstance {} struct AssignNewInstance {}
private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAddress) { private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAddress) {
writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress)); writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress));
} }
/** /**
@ -105,129 +105,129 @@ private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAd
* See_Also: Autowire * See_Also: Autowire
*/ */
public void autowire(Type)(shared(DependencyContainer) container, Type instance) { public void autowire(Type)(shared(DependencyContainer) container, Type instance) {
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugAutowiredInstance(typeid(Type), &instance); printDebugAutowiredInstance(typeid(Type), &instance);
} }
// Recurse into base class if there are more between Type and Object in the hierarchy // Recurse into base class if there are more between Type and Object in the hierarchy
static if(BaseClassesTuple!Type.length > 1) static if(BaseClassesTuple!Type.length > 1)
{ {
autowire!(BaseClassesTuple!Type[0])(container, instance); autowire!(BaseClassesTuple!Type[0])(container, instance);
} }
foreach(index, name; FieldNameTuple!Type) { foreach(index, name; FieldNameTuple!Type) {
autowireMember!(name, index, Type)(container, instance); autowireMember!(name, index, Type)(container, instance);
} }
} }
private void printDebugAutowiringCandidate(TypeInfo candidateInstanceType, void* candidateInstanceAddress, TypeInfo instanceType, void* instanceAddress, string member) { private void printDebugAutowiringCandidate(TypeInfo candidateInstanceType, void* candidateInstanceAddress, TypeInfo instanceType, void* instanceAddress, string member) {
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType, candidateInstanceAddress, instanceType, instanceAddress, member)); writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType, candidateInstanceAddress, instanceType, instanceAddress, member));
} }
private void printDebugAutowiringArray(TypeInfo superTypeInfo, TypeInfo instanceType, void* instanceAddress, string member) { private void printDebugAutowiringArray(TypeInfo superTypeInfo, TypeInfo instanceType, void* instanceAddress, string member) {
writeln(format("DEBUG: Autowired all registered instances of super type %s to [%s@%s].%s", superTypeInfo, instanceType, instanceAddress, member)); writeln(format("DEBUG: Autowired all registered instances of super type %s to [%s@%s].%s", superTypeInfo, instanceType, instanceAddress, member));
} }
private void autowireMember(string member, size_t memberIndex, Type)(shared(DependencyContainer) container, Type instance) { private void autowireMember(string member, size_t memberIndex, Type)(shared(DependencyContainer) container, Type instance) {
foreach(attribute; __traits(getAttributes, Type.tupleof[memberIndex])) { foreach(attribute; __traits(getAttributes, Type.tupleof[memberIndex])) {
static if (is(attribute == Autowire!T, T)) { static if (is(attribute == Autowire!T, T)) {
injectInstance!(member, memberIndex, typeof(attribute.qualifier))(container, instance); injectInstance!(member, memberIndex, typeof(attribute.qualifier))(container, instance);
} else static if (__traits(isSame, attribute, Autowire)) { } else static if (__traits(isSame, attribute, Autowire)) {
injectInstance!(member, memberIndex, UseMemberType)(container, instance); injectInstance!(member, memberIndex, UseMemberType)(container, instance);
} else static if (is(typeof(attribute) == Value)) { } else static if (is(typeof(attribute) == Value)) {
enum key = attribute.key; enum key = attribute.key;
injectValue!(member, memberIndex, key, false)(container, instance); injectValue!(member, memberIndex, key, false)(container, instance);
} else static if (is(typeof(attribute) == MandatoryValue)) { } else static if (is(typeof(attribute) == MandatoryValue)) {
enum key = attribute.key; enum key = attribute.key;
injectValue!(member, memberIndex, key, true)(container, instance); injectValue!(member, memberIndex, key, true)(container, instance);
} }
} }
} }
private void injectInstance(string member, size_t memberIndex, QualifierType, Type)(shared(DependencyContainer) container, Type instance) { private void injectInstance(string member, size_t memberIndex, QualifierType, Type)(shared(DependencyContainer) container, Type instance) {
if (instance.tupleof[memberIndex] is null) { if (instance.tupleof[memberIndex] is null) {
alias MemberType = typeof(Type.tupleof[memberIndex]); alias MemberType = typeof(Type.tupleof[memberIndex]);
enum isOptional = hasUDA!(Type.tupleof[memberIndex], OptionalDependency); enum isOptional = hasUDA!(Type.tupleof[memberIndex], OptionalDependency);
static if (isDynamicArray!MemberType) { static if (isDynamicArray!MemberType) {
injectMultipleInstances!(member, memberIndex, isOptional, MemberType)(container, instance); injectMultipleInstances!(member, memberIndex, isOptional, MemberType)(container, instance);
} else { } else {
injectSingleInstance!(member, memberIndex, isOptional, MemberType, QualifierType)(container, instance); injectSingleInstance!(member, memberIndex, isOptional, MemberType, QualifierType)(container, instance);
} }
} }
} }
private void injectMultipleInstances(string member, size_t memberIndex, bool isOptional, MemberType, Type)(shared(DependencyContainer) container, Type instance) { private void injectMultipleInstances(string member, size_t memberIndex, bool isOptional, MemberType, Type)(shared(DependencyContainer) container, Type instance) {
alias MemberElementType = ElementType!MemberType; alias MemberElementType = ElementType!MemberType;
static if (isOptional) { static if (isOptional) {
auto instances = container.resolveAll!MemberElementType(ResolveOption.noResolveException); auto instances = container.resolveAll!MemberElementType(ResolveOption.noResolveException);
} else { } else {
auto instances = container.resolveAll!MemberElementType; auto instances = container.resolveAll!MemberElementType;
} }
instance.tupleof[memberIndex] = instances; instance.tupleof[memberIndex] = instances;
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member); printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member);
} }
} }
private void injectSingleInstance(string member, size_t memberIndex, bool isOptional, MemberType, QualifierType, Type)(shared(DependencyContainer) container, Type instance) { private void injectSingleInstance(string member, size_t memberIndex, bool isOptional, MemberType, QualifierType, Type)(shared(DependencyContainer) container, Type instance) {
debug(poodinisVerbose) { debug(poodinisVerbose) {
TypeInfo qualifiedInstanceType = typeid(MemberType); TypeInfo qualifiedInstanceType = typeid(MemberType);
} }
enum assignNewInstance = hasUDA!(Type.tupleof[memberIndex], AssignNewInstance); enum assignNewInstance = hasUDA!(Type.tupleof[memberIndex], AssignNewInstance);
MemberType qualifiedInstance; MemberType qualifiedInstance;
static if (!is(QualifierType == UseMemberType)) { static if (!is(QualifierType == UseMemberType)) {
qualifiedInstance = createOrResolveInstance!(MemberType, QualifierType, assignNewInstance, isOptional)(container); qualifiedInstance = createOrResolveInstance!(MemberType, QualifierType, assignNewInstance, isOptional)(container);
debug(poodinisVerbose) { debug(poodinisVerbose) {
qualifiedInstanceType = typeid(QualifierType); qualifiedInstanceType = typeid(QualifierType);
} }
} else { } else {
qualifiedInstance = createOrResolveInstance!(MemberType, MemberType, assignNewInstance, isOptional)(container); qualifiedInstance = createOrResolveInstance!(MemberType, MemberType, assignNewInstance, isOptional)(container);
} }
instance.tupleof[memberIndex] = qualifiedInstance; instance.tupleof[memberIndex] = qualifiedInstance;
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member); printDebugAutowiringCandidate(qualifiedInstanceType, &qualifiedInstance, typeid(Type), &instance, member);
} }
} }
private QualifierType createOrResolveInstance(MemberType, QualifierType, bool createNew, bool isOptional)(shared(DependencyContainer) container) { private QualifierType createOrResolveInstance(MemberType, QualifierType, bool createNew, bool isOptional)(shared(DependencyContainer) container) {
static if (createNew) { static if (createNew) {
auto instanceFactory = new InstanceFactory(); auto instanceFactory = new InstanceFactory();
instanceFactory.factoryParameters = InstanceFactoryParameters(typeid(MemberType), CreatesSingleton.no); instanceFactory.factoryParameters = InstanceFactoryParameters(typeid(MemberType), CreatesSingleton.no);
return cast(MemberType) instanceFactory.getInstance(); return cast(MemberType) instanceFactory.getInstance();
} else { } else {
static if (isOptional) { static if (isOptional) {
return container.resolve!(MemberType, QualifierType)(ResolveOption.noResolveException); return container.resolve!(MemberType, QualifierType)(ResolveOption.noResolveException);
} else { } else {
return container.resolve!(MemberType, QualifierType); return container.resolve!(MemberType, QualifierType);
} }
} }
} }
private void injectValue(string member, size_t memberIndex, string key, bool mandatory, Type)(shared(DependencyContainer) container, Type instance) { private void injectValue(string member, size_t memberIndex, string key, bool mandatory, Type)(shared(DependencyContainer) container, Type instance) {
alias MemberType = typeof(Type.tupleof[memberIndex]); alias MemberType = typeof(Type.tupleof[memberIndex]);
try { try {
auto injector = container.resolve!(ValueInjector!MemberType); auto injector = container.resolve!(ValueInjector!MemberType);
instance.tupleof[memberIndex] = injector.get(key); instance.tupleof[memberIndex] = injector.get(key);
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugValueInjection(typeid(Type), &instance, member, typeid(MemberType), key); printDebugValueInjection(typeid(Type), &instance, member, typeid(MemberType), key);
} }
} catch (ResolveException e) { } catch (ResolveException e) {
throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s: value injector is missing for this type.", typeid(MemberType), typeid(Type), member)); throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s: value injector is missing for this type.", typeid(MemberType), typeid(Type), member));
} catch (ValueNotAvailableException e) { } catch (ValueNotAvailableException e) {
static if (mandatory) { static if (mandatory) {
throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s", typeid(MemberType), typeid(Type), member), e); throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s", typeid(MemberType), typeid(Type), member), e);
} }
} }
} }
private void printDebugValueInjection(TypeInfo instanceType, void* instanceAddress, string member, TypeInfo valueType, string key) { private void printDebugValueInjection(TypeInfo instanceType, void* instanceAddress, string member, TypeInfo valueType, string key) {
writeln(format("DEBUG: Injected value with key '%s' of type %s into [%s@%s].%s", key, valueType, instanceType, instanceAddress, member)); writeln(format("DEBUG: Injected value with key '%s' of type %s into [%s@%s].%s", key, valueType, instanceType, instanceAddress, member));
} }
/** /**
@ -237,48 +237,48 @@ private void printDebugValueInjection(TypeInfo instanceType, void* instanceAddre
* Deprecated: Using the global container is undesired. See DependencyContainer.getInstance(). * Deprecated: Using the global container is undesired. See DependencyContainer.getInstance().
*/ */
public deprecated void globalAutowire(Type)(Type instance) { public deprecated void globalAutowire(Type)(Type instance) {
DependencyContainer.getInstance().autowire(instance); DependencyContainer.getInstance().autowire(instance);
} }
class AutowiredRegistration(RegistrationType : Object) : Registration { class AutowiredRegistration(RegistrationType : Object) : Registration {
private shared(DependencyContainer) container; private shared(DependencyContainer) container;
public this(TypeInfo registeredType, InstanceFactory instanceFactory, shared(DependencyContainer) originatingContainer) { public this(TypeInfo registeredType, InstanceFactory instanceFactory, shared(DependencyContainer) originatingContainer) {
super(registeredType, typeid(RegistrationType), instanceFactory, originatingContainer); super(registeredType, typeid(RegistrationType), instanceFactory, originatingContainer);
} }
public override Object getInstance(InstantiationContext context = new AutowireInstantiationContext()) { public override Object getInstance(InstantiationContext context = new AutowireInstantiationContext()) {
enforce(!(originatingContainer is null), "The registration's originating container is null. There is no way to resolve autowire dependencies."); enforce(!(originatingContainer is null), "The registration's originating container is null. There is no way to resolve autowire dependencies.");
RegistrationType instance = cast(RegistrationType) super.getInstance(context); RegistrationType instance = cast(RegistrationType) super.getInstance(context);
AutowireInstantiationContext autowireContext = cast(AutowireInstantiationContext) context; AutowireInstantiationContext autowireContext = cast(AutowireInstantiationContext) context;
enforce(!(autowireContext is null), "Given instantiation context type could not be cast to an AutowireInstantiationContext. If you relied on using the default assigned context: make sure you're calling getInstance() on an instance of type AutowiredRegistration!"); enforce(!(autowireContext is null), "Given instantiation context type could not be cast to an AutowireInstantiationContext. If you relied on using the default assigned context: make sure you're calling getInstance() on an instance of type AutowiredRegistration!");
if (autowireContext.autowireInstance) { if (autowireContext.autowireInstance) {
originatingContainer.autowire(instance); originatingContainer.autowire(instance);
} }
this.preDestructor = getPreDestructor(instance); this.preDestructor = getPreDestructor(instance);
return instance; return instance;
} }
private void delegate() getPreDestructor(RegistrationType instance) { private void delegate() getPreDestructor(RegistrationType instance) {
void delegate() preDestructor = null; void delegate() preDestructor = null;
foreach (memberName; __traits(allMembers, RegistrationType)) { foreach (memberName; __traits(allMembers, RegistrationType)) {
mixin(createImportsString!RegistrationType); mixin(createImportsString!RegistrationType);
static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName)))
&& __traits(getProtection, __traits(getMember, instance, memberName)) == "public" && __traits(getProtection, __traits(getMember, instance, memberName)) == "public"
&& isFunction!(mixin(fullyQualifiedName!RegistrationType ~ `.` ~ memberName)) && isFunction!(mixin(fullyQualifiedName!RegistrationType ~ `.` ~ memberName))
&& hasUDA!(__traits(getMember, instance, memberName), PreDestroy)) { && hasUDA!(__traits(getMember, instance, memberName), PreDestroy)) {
preDestructor = &__traits(getMember, instance, memberName); preDestructor = &__traits(getMember, instance, memberName);
} }
} }
return preDestructor; return preDestructor;
} }
} }
class AutowireInstantiationContext : InstantiationContext { class AutowireInstantiationContext : InstantiationContext {
public bool autowireInstance = true; public bool autowireInstance = true;
} }

View file

@ -5,7 +5,7 @@
* *
* Authors: * Authors:
* Mike Bierlee, m.bierlee@lostmoment.com * Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2017 Mike Bierlee * Copyright: 2014-2018 Mike Bierlee
* License: * License:
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
@ -27,60 +27,60 @@ import std.concurrency;
import std.traits; import std.traits;
debug { debug {
import std.stdio; import std.stdio;
} }
/** /**
* Exception thrown when errors occur while resolving a type in a dependency container. * Exception thrown when errors occur while resolving a type in a dependency container.
*/ */
class ResolveException : Exception { class ResolveException : Exception {
this(string message, TypeInfo resolveType) { this(string message, TypeInfo resolveType) {
super(format("Exception while resolving type %s: %s", resolveType.toString(), message)); super(format("Exception while resolving type %s: %s", resolveType.toString(), message));
} }
this(Throwable cause, TypeInfo resolveType) { this(Throwable cause, TypeInfo resolveType) {
super(format("Exception while resolving type %s", resolveType.toString()), cause); super(format("Exception while resolving type %s", resolveType.toString()), cause);
} }
} }
/** /**
* Exception thrown when errors occur while registering a type in a dependency container. * Exception thrown when errors occur while registering a type in a dependency container.
*/ */
class RegistrationException : Exception { class RegistrationException : Exception {
this(string message, TypeInfo registrationType) { this(string message, TypeInfo registrationType) {
super(format("Exception while registering type %s: %s", registrationType.toString(), message)); super(format("Exception while registering type %s: %s", registrationType.toString(), message));
} }
} }
/** /**
* Options which influence the process of registering dependencies * Options which influence the process of registering dependencies
*/ */
public enum RegistrationOption { public enum RegistrationOption {
none = 0, none = 0,
/** /**
* Prevent a concrete type being registered on itself. With this option you will always need * Prevent a concrete type being registered on itself. With this option you will always need
* to use the supertype as the type of the dependency. * to use the supertype as the type of the dependency.
*/ */
doNotAddConcreteTypeRegistration = 1 << 0, doNotAddConcreteTypeRegistration = 1 << 0,
} }
/** /**
* Options which influence the process of resolving dependencies * Options which influence the process of resolving dependencies
*/ */
public enum ResolveOption { public enum ResolveOption {
none = 0, none = 0,
/** /**
* Registers the type you're trying to resolve before returning it. * Registers the type you're trying to resolve before returning it.
* This essentially makes registration optional for resolving by concerete types. * This essentially makes registration optional for resolving by concerete types.
* Resolinvg will still fail when trying to resolve a dependency by supertype. * Resolinvg will still fail when trying to resolve a dependency by supertype.
*/ */
registerBeforeResolving = 1 << 0, registerBeforeResolving = 1 << 0,
/** /**
* Does not throw a resolve exception when a type is not registered but will * Does not throw a resolve exception when a type is not registered but will
* return null instead. If the type is an array, an empty array is returned instead. * return null instead. If the type is an array, an empty array is returned instead.
*/ */
noResolveException = 1 << 1 noResolveException = 1 << 1
} }
/** /**
@ -112,358 +112,358 @@ struct PreDestroy {}
* You can still create new instances of this class for exceptional situations. * You can still create new instances of this class for exceptional situations.
*/ */
synchronized class DependencyContainer { synchronized class DependencyContainer {
private Registration[][TypeInfo] registrations; private Registration[][TypeInfo] registrations;
private Registration[] autowireStack; private Registration[] autowireStack;
private RegistrationOption persistentRegistrationOptions; private RegistrationOption persistentRegistrationOptions;
private ResolveOption persistentResolveOptions; private ResolveOption persistentResolveOptions;
~this() { ~this() {
clearAllRegistrations(); clearAllRegistrations();
} }
/** /**
* Register a dependency by concrete class type. * Register a dependency by concrete class type.
* *
* A dependency registered by concrete class type can only be resolved by concrete class type. * A dependency registered by concrete class type can only be resolved by concrete class type.
* No qualifiers can be used when resolving dependencies which are registered by concrete type. * No qualifiers can be used when resolving dependencies which are registered by concrete type.
* *
* The default registration scope is "single instance" scope. * The default registration scope is "single instance" scope.
* *
* Returns: * Returns:
* A registration is returned which can be used to change the registration scope. * A registration is returned which can be used to change the registration scope.
* *
* Examples: * Examples:
* Register and resolve a class by concrete type: * Register and resolve a class by concrete type:
* --- * ---
* class Cat : Animal { ... } * class Cat : Animal { ... }
* container.register!Cat; * container.register!Cat;
* --- * ---
* *
* See_Also: singleInstance, newInstance, existingInstance * See_Also: singleInstance, newInstance, existingInstance
*/ */
public Registration register(ConcreteType)(RegistrationOption options = RegistrationOption.none) { public Registration register(ConcreteType)(RegistrationOption options = RegistrationOption.none) {
return register!(ConcreteType, ConcreteType)(options); return register!(ConcreteType, ConcreteType)(options);
} }
/** /**
* Register a dependency by super type. * Register a dependency by super type.
* *
* A dependency registered by super type can only be resolved by super type. A qualifier is typically * A dependency registered by super type can only be resolved by super type. A qualifier is typically
* used to resolve dependencies registered by super type. * used to resolve dependencies registered by super type.
* *
* The default registration scope is "single instance" scope. * The default registration scope is "single instance" scope.
* *
* Examples: * Examples:
* Register and resolve by super type * Register and resolve by super type
* --- * ---
* class Cat : Animal { ... } * class Cat : Animal { ... }
* container.register!(Animal, Cat); * container.register!(Animal, Cat);
* --- * ---
* *
* See_Also: singleInstance, newInstance, existingInstance, RegistrationOption * See_Also: singleInstance, newInstance, existingInstance, RegistrationOption
*/ */
public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption options = RegistrationOption.none) { public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption options = RegistrationOption.none) {
TypeInfo registeredType = typeid(SuperType); TypeInfo registeredType = typeid(SuperType);
TypeInfo_Class concreteType = typeid(ConcreteType); TypeInfo_Class concreteType = typeid(ConcreteType);
debug(poodinisVerbose) { debug(poodinisVerbose) {
writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString())); writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString()));
} }
auto existingRegistration = getExistingRegistration(registeredType, concreteType); auto existingRegistration = getExistingRegistration(registeredType, concreteType);
if (existingRegistration) { if (existingRegistration) {
return existingRegistration; return existingRegistration;
} }
auto instanceFactory = new ConstructorInjectingInstanceFactory!ConcreteType(this); auto instanceFactory = new ConstructorInjectingInstanceFactory!ConcreteType(this);
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, instanceFactory, this); auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, instanceFactory, this);
newRegistration.singleInstance(); newRegistration.singleInstance();
static if (!is(SuperType == ConcreteType)) { static if (!is(SuperType == ConcreteType)) {
if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) { if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) {
auto concreteTypeRegistration = register!ConcreteType; auto concreteTypeRegistration = register!ConcreteType;
concreteTypeRegistration.linkTo(newRegistration); concreteTypeRegistration.linkTo(newRegistration);
} }
} }
registrations[registeredType] ~= cast(shared(Registration)) newRegistration; registrations[registeredType] ~= cast(shared(Registration)) newRegistration;
return newRegistration; return newRegistration;
} }
private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) { private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) {
return ((options | persistentOptions) & option) != 0; return ((options | persistentOptions) & option) != 0;
} }
private OptionType buildFlags(OptionType)(OptionType[] options) { private OptionType buildFlags(OptionType)(OptionType[] options) {
OptionType flags; OptionType flags;
foreach (option; options) { foreach (option; options) {
flags |= option; flags |= option;
} }
return flags; return flags;
} }
private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) { private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) {
auto existingCandidates = registrationType in registrations; auto existingCandidates = registrationType in registrations;
if (existingCandidates) { if (existingCandidates) {
return getRegistration(cast(Registration[]) *existingCandidates, qualifierType); return getRegistration(cast(Registration[]) *existingCandidates, qualifierType);
} }
return null; return null;
} }
private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) { private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) {
foreach(existingRegistration ; candidates) { foreach(existingRegistration ; candidates) {
if (existingRegistration.instanceType == concreteType) { if (existingRegistration.instanceType == concreteType) {
return existingRegistration; return existingRegistration;
} }
} }
return null; return null;
} }
/** /**
* Resolve dependencies. * Resolve dependencies.
* *
* Dependencies can only resolved using this method if they are registered by concrete type or the only * Dependencies can only resolved using this method if they are registered by concrete type or the only
* concrete type registered by super type. * concrete type registered by super type.
* *
* Resolved dependencies are automatically autowired before being returned. * Resolved dependencies are automatically autowired before being returned.
* *
* Returns: * Returns:
* An instance is returned which is created according to the registration scope with which they are registered. * An instance is returned which is created according to the registration scope with which they are registered.
* *
* Throws: * Throws:
* ResolveException when type is not registered. * ResolveException when type is not registered.
* *
* Examples: * Examples:
* Resolve dependencies registered by super type and concrete type: * Resolve dependencies registered by super type and concrete type:
* --- * ---
* class Cat : Animal { ... } * class Cat : Animal { ... }
* class Dog : Animal { ... } * class Dog : Animal { ... }
* *
* container.register!(Animal, Cat); * container.register!(Animal, Cat);
* container.register!Dog; * container.register!Dog;
* *
* container.resolve!Animal; * container.resolve!Animal;
* container.resolve!Dog; * container.resolve!Dog;
* --- * ---
* You cannot resolve a dependency when it is registered by multiple super types: * You cannot resolve a dependency when it is registered by multiple super types:
* --- * ---
* class Cat : Animal { ... } * class Cat : Animal { ... }
* class Dog : Animal { ... } * class Dog : Animal { ... }
* *
* container.register!(Animal, Cat); * container.register!(Animal, Cat);
* container.register!(Animal, Dog); * container.register!(Animal, Dog);
* *
* container.resolve!Animal; // Error: multiple candidates for type "Animal" * container.resolve!Animal; // Error: multiple candidates for type "Animal"
* container.resolve!Dog; // Error: No type is registered by concrete type "Dog", only by super type "Animal" * container.resolve!Dog; // Error: No type is registered by concrete type "Dog", only by super type "Animal"
* --- * ---
* You need to use the resolve method which allows you to specify a qualifier. * You need to use the resolve method which allows you to specify a qualifier.
*/ */
public RegistrationType resolve(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) { public RegistrationType resolve(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) {
return resolve!(RegistrationType, RegistrationType)(resolveOptions); return resolve!(RegistrationType, RegistrationType)(resolveOptions);
} }
/** /**
* Resolve dependencies using a qualifier. * Resolve dependencies using a qualifier.
* *
* Dependencies can only resolved using this method if they are registered by super type. * Dependencies can only resolved using this method if they are registered by super type.
* *
* Resolved dependencies are automatically autowired before being returned. * Resolved dependencies are automatically autowired before being returned.
* *
* Returns: * Returns:
* An instance is returned which is created according to the registration scope with which they are registered. * An instance is returned which is created according to the registration scope with which they are registered.
* *
* Throws: * Throws:
* ResolveException when type is not registered or there are multiple candidates available for type. * ResolveException when type is not registered or there are multiple candidates available for type.
* *
* Examples: * Examples:
* Resolve dependencies registered by super type: * Resolve dependencies registered by super type:
* --- * ---
* class Cat : Animal { ... } * class Cat : Animal { ... }
* class Dog : Animal { ... } * class Dog : Animal { ... }
* *
* container.register!(Animal, Cat); * container.register!(Animal, Cat);
* container.register!(Animal, Dog); * container.register!(Animal, Dog);
* *
* container.resolve!(Animal, Cat); * container.resolve!(Animal, Cat);
* container.resolve!(Animal, Dog); * container.resolve!(Animal, Dog);
* --- * ---
*/ */
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) { public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) {
TypeInfo resolveType = typeid(RegistrationType); TypeInfo resolveType = typeid(RegistrationType);
TypeInfo qualifierType = typeid(QualifierType); TypeInfo qualifierType = typeid(QualifierType);
debug(poodinisVerbose) { debug(poodinisVerbose) {
writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString()); writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
} }
static if (__traits(compiles, new QualifierType())) { static if (__traits(compiles, new QualifierType())) {
if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.registerBeforeResolving)) { if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.registerBeforeResolving)) {
register!(RegistrationType, QualifierType)(); register!(RegistrationType, QualifierType)();
} }
} }
auto candidates = resolveType in registrations; auto candidates = resolveType in registrations;
if (!candidates) { if (!candidates) {
if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.noResolveException)) { if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.noResolveException)) {
return null; return null;
} }
throw new ResolveException("Type not registered.", resolveType); throw new ResolveException("Type not registered.", resolveType);
} }
Registration registration = getQualifiedRegistration(resolveType, qualifierType, cast(Registration[]) *candidates); Registration registration = getQualifiedRegistration(resolveType, qualifierType, cast(Registration[]) *candidates);
try { try {
QualifierType newInstance = resolveAutowiredInstance!QualifierType(registration); QualifierType newInstance = resolveAutowiredInstance!QualifierType(registration);
callPostConstructors(newInstance); callPostConstructors(newInstance);
return newInstance; return newInstance;
} catch (ValueInjectionException e) { } catch (ValueInjectionException e) {
throw new ResolveException(e, resolveType); throw new ResolveException(e, resolveType);
} }
} }
private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) { private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) {
QualifierType instance; QualifierType instance;
if (!(cast(Registration[]) autowireStack).canFind(registration)) { if (!(cast(Registration[]) autowireStack).canFind(registration)) {
autowireStack ~= cast(shared(Registration)) registration; autowireStack ~= cast(shared(Registration)) registration;
instance = cast(QualifierType) registration.getInstance(new AutowireInstantiationContext()); instance = cast(QualifierType) registration.getInstance(new AutowireInstantiationContext());
autowireStack = autowireStack[0 .. $-1]; autowireStack = autowireStack[0 .. $-1];
} else { } else {
auto autowireContext = new AutowireInstantiationContext(); auto autowireContext = new AutowireInstantiationContext();
autowireContext.autowireInstance = false; autowireContext.autowireInstance = false;
instance = cast(QualifierType) registration.getInstance(autowireContext); instance = cast(QualifierType) registration.getInstance(autowireContext);
} }
return instance; return instance;
} }
/** /**
* Resolve all dependencies registered to a super type. * Resolve all dependencies registered to a super type.
* *
* Returns: * Returns:
* An array of autowired instances is returned. The order is undetermined. * An array of autowired instances is returned. The order is undetermined.
* *
* Examples: * Examples:
* --- * ---
* class Cat : Animal { ... } * class Cat : Animal { ... }
* class Dog : Animal { ... } * class Dog : Animal { ... }
* *
* container.register!(Animal, Cat); * container.register!(Animal, Cat);
* container.register!(Animal, Dog); * container.register!(Animal, Dog);
* *
* Animal[] animals = container.resolveAll!Animal; * Animal[] animals = container.resolveAll!Animal;
* --- * ---
*/ */
public RegistrationType[] resolveAll(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) { public RegistrationType[] resolveAll(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) {
RegistrationType[] instances; RegistrationType[] instances;
TypeInfo resolveType = typeid(RegistrationType); TypeInfo resolveType = typeid(RegistrationType);
auto qualifiedRegistrations = resolveType in registrations; auto qualifiedRegistrations = resolveType in registrations;
if (!qualifiedRegistrations) { if (!qualifiedRegistrations) {
if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.noResolveException)) { if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.noResolveException)) {
return []; return [];
} }
throw new ResolveException("Type not registered.", resolveType); throw new ResolveException("Type not registered.", resolveType);
} }
foreach(registration ; cast(Registration[]) *qualifiedRegistrations) { foreach(registration ; cast(Registration[]) *qualifiedRegistrations) {
instances ~= resolveAutowiredInstance!RegistrationType(registration); instances ~= resolveAutowiredInstance!RegistrationType(registration);
} }
return instances; return instances;
} }
private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) { private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) {
if (resolveType == qualifierType) { if (resolveType == qualifierType) {
if (candidates.length > 1) { if (candidates.length > 1) {
string candidateList = candidates.toConcreteTypeListString(); string candidateList = candidates.toConcreteTypeListString();
throw new ResolveException("Multiple qualified candidates available: " ~ candidateList ~ ". Please use a qualifier.", resolveType); throw new ResolveException("Multiple qualified candidates available: " ~ candidateList ~ ". Please use a qualifier.", resolveType);
} }
return candidates[0]; return candidates[0];
} }
return getRegistration(candidates, qualifierType); return getRegistration(candidates, qualifierType);
} }
private void callPostConstructors(Type)(Type instance) { private void callPostConstructors(Type)(Type instance) {
foreach (memberName; __traits(allMembers, Type)) { foreach (memberName; __traits(allMembers, Type)) {
mixin(createImportsString!Type); mixin(createImportsString!Type);
static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName)))
&& __traits(getProtection, __traits(getMember, instance, memberName)) == "public" && __traits(getProtection, __traits(getMember, instance, memberName)) == "public"
&& isFunction!(mixin(fullyQualifiedName!Type ~ `.` ~ memberName)) && isFunction!(mixin(fullyQualifiedName!Type ~ `.` ~ memberName))
&& hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) { && hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) {
__traits(getMember, instance, memberName)(); __traits(getMember, instance, memberName)();
} }
} }
} }
/** /**
* Clears all dependency registrations managed by this container. * Clears all dependency registrations managed by this container.
*/ */
public void clearAllRegistrations() { public void clearAllRegistrations() {
foreach(registrationsOfType; registrations) { foreach(registrationsOfType; registrations) {
callPreDestructorsOfRegistrations(registrationsOfType); callPreDestructorsOfRegistrations(registrationsOfType);
} }
registrations.destroy(); registrations.destroy();
} }
/** /**
* Removes a registered dependency by type. * Removes a registered dependency by type.
* *
* A dependency can be removed either by super type or concrete type, depending on how they are registered. * A dependency can be removed either by super type or concrete type, depending on how they are registered.
* *
* Examples: * Examples:
* --- * ---
* container.removeRegistration!Animal; * container.removeRegistration!Animal;
* --- * ---
*/ */
public void removeRegistration(RegistrationType)() { public void removeRegistration(RegistrationType)() {
auto registrationsOfType = *(typeid(RegistrationType) in registrations); auto registrationsOfType = *(typeid(RegistrationType) in registrations);
callPreDestructorsOfRegistrations(registrationsOfType); callPreDestructorsOfRegistrations(registrationsOfType);
registrations.remove(typeid(RegistrationType)); registrations.remove(typeid(RegistrationType));
} }
private void callPreDestructorsOfRegistrations(shared(Registration[]) registrations) { private void callPreDestructorsOfRegistrations(shared(Registration[]) registrations) {
foreach(registration; registrations) { foreach(registration; registrations) {
Registration unsharedRegistration = cast(Registration) registration; Registration unsharedRegistration = cast(Registration) registration;
if (unsharedRegistration.preDestructor !is null) { if (unsharedRegistration.preDestructor !is null) {
unsharedRegistration.preDestructor()(); unsharedRegistration.preDestructor()();
} }
} }
} }
/** /**
* Apply persistent registration options which will be used everytime register() is called. * Apply persistent registration options which will be used everytime register() is called.
*/ */
public void setPersistentRegistrationOptions(RegistrationOption options) { public void setPersistentRegistrationOptions(RegistrationOption options) {
persistentRegistrationOptions = options; persistentRegistrationOptions = options;
} }
/** /**
* Unsets all applied persistent registration options * Unsets all applied persistent registration options
*/ */
public void unsetPersistentRegistrationOptions() { public void unsetPersistentRegistrationOptions() {
persistentRegistrationOptions = RegistrationOption.none; persistentRegistrationOptions = RegistrationOption.none;
} }
/** /**
* Apply persistent resolve options which will be used everytime resolve() is called. * Apply persistent resolve options which will be used everytime resolve() is called.
*/ */
public void setPersistentResolveOptions(ResolveOption options) { public void setPersistentResolveOptions(ResolveOption options) {
persistentResolveOptions = options; persistentResolveOptions = options;
} }
/** /**
* Unsets all applied persistent resolve options * Unsets all applied persistent resolve options
*/ */
public void unsetPersistentResolveOptions() { public void unsetPersistentResolveOptions() {
persistentResolveOptions = ResolveOption.none; persistentResolveOptions = ResolveOption.none;
} }
} }

View file

@ -5,7 +5,7 @@
* *
* Authors: * Authors:
* Mike Bierlee, m.bierlee@lostmoment.com * Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2017 Mike Bierlee * Copyright: 2014-2018 Mike Bierlee
* License: * License:
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
@ -21,7 +21,7 @@ import poodinis.autowire;
import std.traits; import std.traits;
class ApplicationContext { class ApplicationContext {
public void registerDependencies(shared(DependencyContainer) container) {} public void registerDependencies(shared(DependencyContainer) container) {}
} }
/** /**
@ -35,7 +35,7 @@ struct Component {}
* enables you to use type-qualified alternatives for dependencies. * enables you to use type-qualified alternatives for dependencies.
*/ */
struct RegisterByType(Type) { struct RegisterByType(Type) {
Type type; Type type;
} }
/** /**
@ -52,33 +52,33 @@ struct Prototype {}
* want to use annotations to set-up dependencies in your classes. * want to use annotations to set-up dependencies in your classes.
*/ */
public void registerContext(Context : ApplicationContext)(shared(DependencyContainer) container) { public void registerContext(Context : ApplicationContext)(shared(DependencyContainer) container) {
auto context = new Context(); auto context = new Context();
context.registerDependencies(container); context.registerDependencies(container);
context.registerContextComponents(container); context.registerContextComponents(container);
container.register!(ApplicationContext, Context)().existingInstance(context); container.register!(ApplicationContext, Context)().existingInstance(context);
autowire(container, context); autowire(container, context);
} }
public void registerContextComponents(ApplicationContextType : ApplicationContext)(ApplicationContextType context, shared(DependencyContainer) container) { public void registerContextComponents(ApplicationContextType : ApplicationContext)(ApplicationContextType context, shared(DependencyContainer) container) {
foreach (member ; __traits(allMembers, ApplicationContextType)) { foreach (member ; __traits(allMembers, ApplicationContextType)) {
static if (__traits(getProtection, __traits(getMember, context, member)) == "public" && hasUDA!(__traits(getMember, context, member), Component)) { static if (__traits(getProtection, __traits(getMember, context, member)) == "public" && hasUDA!(__traits(getMember, context, member), Component)) {
auto factoryMethod = &__traits(getMember, context, member); auto factoryMethod = &__traits(getMember, context, member);
Registration registration = null; Registration registration = null;
auto createsSingleton = CreatesSingleton.yes; auto createsSingleton = CreatesSingleton.yes;
foreach(attribute; __traits(getAttributes, __traits(getMember, context, member))) { foreach(attribute; __traits(getAttributes, __traits(getMember, context, member))) {
static if (is(attribute == RegisterByType!T, T)) { static if (is(attribute == RegisterByType!T, T)) {
registration = container.register!(typeof(attribute.type), ReturnType!factoryMethod); registration = container.register!(typeof(attribute.type), ReturnType!factoryMethod);
} else static if (__traits(isSame, attribute, Prototype)) { } else static if (__traits(isSame, attribute, Prototype)) {
createsSingleton = CreatesSingleton.no; createsSingleton = CreatesSingleton.no;
} }
} }
if (registration is null) { if (registration is null) {
registration = container.register!(ReturnType!factoryMethod); registration = container.register!(ReturnType!factoryMethod);
} }
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, createsSingleton, null, factoryMethod); registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, createsSingleton, null, factoryMethod);
} }
} }
} }

View file

@ -3,7 +3,7 @@
* *
* Authors: * Authors:
* Mike Bierlee, m.bierlee@lostmoment.com * Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2017 Mike Bierlee * Copyright: 2014-2018 Mike Bierlee
* License: * License:
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
@ -24,147 +24,147 @@ alias CreatesSingleton = Flag!"CreatesSingleton";
alias InstanceFactoryMethod = Object delegate(); alias InstanceFactoryMethod = Object delegate();
class InstanceCreationException : Exception { class InstanceCreationException : Exception {
this(string message, string file = __FILE__, size_t line = __LINE__) { this(string message, string file = __FILE__, size_t line = __LINE__) {
super(message, file, line); super(message, file, line);
} }
} }
struct InstanceFactoryParameters { struct InstanceFactoryParameters {
TypeInfo_Class instanceType; TypeInfo_Class instanceType;
CreatesSingleton createsSingleton = CreatesSingleton.yes; CreatesSingleton createsSingleton = CreatesSingleton.yes;
Object existingInstance; Object existingInstance;
InstanceFactoryMethod factoryMethod; InstanceFactoryMethod factoryMethod;
} }
class InstanceFactory { class InstanceFactory {
private Object instance = null; private Object instance = null;
private InstanceFactoryParameters _factoryParameters; private InstanceFactoryParameters _factoryParameters;
this() { this() {
factoryParameters = InstanceFactoryParameters(); factoryParameters = InstanceFactoryParameters();
} }
public @property void factoryParameters(InstanceFactoryParameters factoryParameters) { public @property void factoryParameters(InstanceFactoryParameters factoryParameters) {
if (factoryParameters.factoryMethod is null) { if (factoryParameters.factoryMethod is null) {
factoryParameters.factoryMethod = &this.createInstance; factoryParameters.factoryMethod = &this.createInstance;
} }
if (factoryParameters.existingInstance !is null) { if (factoryParameters.existingInstance !is null) {
factoryParameters.createsSingleton = CreatesSingleton.yes; factoryParameters.createsSingleton = CreatesSingleton.yes;
this.instance = factoryParameters.existingInstance; this.instance = factoryParameters.existingInstance;
} }
_factoryParameters = factoryParameters; _factoryParameters = factoryParameters;
} }
public @property InstanceFactoryParameters factoryParameters() { public @property InstanceFactoryParameters factoryParameters() {
return _factoryParameters; return _factoryParameters;
} }
public Object getInstance() { public Object getInstance() {
if (_factoryParameters.createsSingleton && instance !is null) { if (_factoryParameters.createsSingleton && instance !is null) {
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugUseExistingInstance(); printDebugUseExistingInstance();
} }
return instance; return instance;
} }
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugCreateNewInstance(); printDebugCreateNewInstance();
} }
instance = _factoryParameters.factoryMethod(); instance = _factoryParameters.factoryMethod();
return instance; return instance;
} }
private void printDebugUseExistingInstance() { private void printDebugUseExistingInstance() {
if (_factoryParameters.instanceType !is null) { if (_factoryParameters.instanceType !is null) {
writeln(format("DEBUG: Existing instance returned of type %s", _factoryParameters.instanceType.toString())); writeln(format("DEBUG: Existing instance returned of type %s", _factoryParameters.instanceType.toString()));
} else { } else {
writeln("DEBUG: Existing instance returned from custom factory method"); writeln("DEBUG: Existing instance returned from custom factory method");
} }
} }
private void printDebugCreateNewInstance() { private void printDebugCreateNewInstance() {
if (_factoryParameters.instanceType !is null) { if (_factoryParameters.instanceType !is null) {
writeln(format("DEBUG: Creating new instance of type %s", _factoryParameters.instanceType.toString())); writeln(format("DEBUG: Creating new instance of type %s", _factoryParameters.instanceType.toString()));
} else { } else {
writeln("DEBUG: Creating new instance from custom factory method"); writeln("DEBUG: Creating new instance from custom factory method");
} }
} }
protected Object createInstance() { protected Object createInstance() {
enforce!InstanceCreationException(_factoryParameters.instanceType, "Instance type is not defined, cannot create instance without knowing its type."); enforce!InstanceCreationException(_factoryParameters.instanceType, "Instance type is not defined, cannot create instance without knowing its type.");
return _factoryParameters.instanceType.create(); return _factoryParameters.instanceType.create();
} }
} }
class ConstructorInjectingInstanceFactory(InstanceType) : InstanceFactory { class ConstructorInjectingInstanceFactory(InstanceType) : InstanceFactory {
private shared DependencyContainer container; private shared DependencyContainer container;
private bool isBeingInjected = false; private bool isBeingInjected = false;
this(shared DependencyContainer container) { this(shared DependencyContainer container) {
this.container = container; this.container = container;
} }
private static string createArgumentList(Params...)() { private static string createArgumentList(Params...)() {
string argumentList = ""; string argumentList = "";
foreach(param; Params) { foreach(param; Params) {
if (argumentList.length > 0) { if (argumentList.length > 0) {
argumentList ~= ","; argumentList ~= ",";
} }
argumentList ~= "container.resolve!" ~ param.stringof; argumentList ~= "container.resolve!" ~ param.stringof;
} }
return argumentList; return argumentList;
} }
private static string createImportList(Params...)() { private static string createImportList(Params...)() {
string importList = ""; string importList = "";
foreach(param; Params) { foreach(param; Params) {
importList ~= createImportsString!param; importList ~= createImportsString!param;
} }
return importList; return importList;
} }
private static bool parametersAreValid(Params...)() { private static bool parametersAreValid(Params...)() {
bool isValid = true; bool isValid = true;
foreach(param; Params) { foreach(param; Params) {
if (isBuiltinType!param) { if (isBuiltinType!param) {
isValid = false; isValid = false;
break; break;
} }
} }
return isValid; return isValid;
} }
protected override Object createInstance() { protected override Object createInstance() {
enforce!InstanceCreationException(container, "A dependency container is not defined. Cannot perform constructor injection without one."); enforce!InstanceCreationException(container, "A dependency container is not defined. Cannot perform constructor injection without one.");
enforce!InstanceCreationException(!isBeingInjected, format("%s is already being created and injected; possible circular dependencies in constructors?", InstanceType.stringof)); enforce!InstanceCreationException(!isBeingInjected, format("%s is already being created and injected; possible circular dependencies in constructors?", InstanceType.stringof));
Object instance = null; Object instance = null;
static if (__traits(compiles, __traits(getOverloads, InstanceType, `__ctor`))) { static if (__traits(compiles, __traits(getOverloads, InstanceType, `__ctor`))) {
foreach(ctor ; __traits(getOverloads, InstanceType, `__ctor`)) { foreach(ctor ; __traits(getOverloads, InstanceType, `__ctor`)) {
static if (parametersAreValid!(Parameters!ctor)) { static if (parametersAreValid!(Parameters!ctor)) {
isBeingInjected = true; isBeingInjected = true;
mixin(createImportsString!InstanceType mixin(createImportsString!InstanceType
~ createImportList!(Parameters!ctor) ~ ` ~ createImportList!(Parameters!ctor) ~ `
instance = new ` ~ fullyQualifiedName!InstanceType ~ `(` ~ createArgumentList!(Parameters!ctor) ~ `); instance = new ` ~ fullyQualifiedName!InstanceType ~ `(` ~ createArgumentList!(Parameters!ctor) ~ `);
`); `);
isBeingInjected = false; isBeingInjected = false;
break; break;
} }
} }
} }
if (instance is null) { if (instance is null) {
instance = typeid(InstanceType).create(); instance = typeid(InstanceType).create();
} }
enforce!InstanceCreationException(instance !is null, "Unable to create instance of type" ~ InstanceType.stringof ~ ", does it have injectable constructors?"); enforce!InstanceCreationException(instance !is null, "Unable to create instance of type" ~ InstanceType.stringof ~ ", does it have injectable constructors?");
return instance; return instance;
} }
} }

View file

@ -1,16 +1,27 @@
/**
* This module contains instance factory facilities
*
* Authors:
* Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2018 Mike Bierlee
* License:
* This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file.
*/
module poodinis.imports; module poodinis.imports;
import std.traits; import std.traits;
public static string createImportsString(Type)() { public static string createImportsString(Type)() {
string imports = `import ` ~ moduleName!Type ~ `;`; string imports = `import ` ~ moduleName!Type ~ `;`;
static if (__traits(compiles, TemplateArgsOf!Type)) { static if (__traits(compiles, TemplateArgsOf!Type)) {
foreach(TemplateArgType; TemplateArgsOf!Type) { foreach(TemplateArgType; TemplateArgsOf!Type) {
static if (!isBuiltinType!TemplateArgType) { static if (!isBuiltinType!TemplateArgType) {
imports ~= createImportsString!TemplateArgType; imports ~= createImportsString!TemplateArgType;
} }
} }
} }
return imports; return imports;
} }

View file

@ -3,7 +3,7 @@
* *
* Authors: * Authors:
* Mike Bierlee, m.bierlee@lostmoment.com * Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2017 Mike Bierlee * Copyright: 2014-2018 Mike Bierlee
* License: * License:
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.

View file

@ -19,7 +19,7 @@
* Kenji Hara, * Kenji Hara,
* Shoichi Kato, * Shoichi Kato,
* Mike Bierlee (m.bierlee@lostmoment.com) * Mike Bierlee (m.bierlee@lostmoment.com)
* Copyright: Copyright Digital Mars 2005 - 2009., Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-., 2014-2017 Mike Bierlee * Copyright: Copyright Digital Mars 2005 - 2009., Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-., 2014-2018 Mike Bierlee
* License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) * License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
*/ */
@ -29,35 +29,35 @@ import std.exception;
import std.traits; import std.traits;
static if (!__traits(compiles, basicExceptionCtors)) { static if (!__traits(compiles, basicExceptionCtors)) {
mixin template basicExceptionCtors() mixin template basicExceptionCtors()
{ {
this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow
{ {
super(msg, file, line, next); super(msg, file, line, next);
} }
this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @safe pure nothrow
{ {
super(msg, file, line, next); super(msg, file, line, next);
} }
} }
} }
static if (!__traits(compiles, isFunction)) { static if (!__traits(compiles, isFunction)) {
template isFunction(X...) if (X.length == 1) template isFunction(X...) if (X.length == 1)
{ {
static if (is(typeof(&X[0]) U : U*) && is(U == function) || static if (is(typeof(&X[0]) U : U*) && is(U == function) ||
is(typeof(&X[0]) U == delegate)) is(typeof(&X[0]) U == delegate))
{ {
// x is a (nested) function symbol. // x is a (nested) function symbol.
enum isFunction = true; enum isFunction = true;
} }
else static if (is(X[0] T)) else static if (is(X[0] T))
{ {
// x is a type. Take the type of it and examine. // x is a type. Take the type of it and examine.
enum isFunction = is(T == function); enum isFunction = is(T == function);
} }
else else
enum isFunction = false; enum isFunction = false;
} }
} }

View file

@ -5,7 +5,7 @@
* *
* Authors: * Authors:
* Mike Bierlee, m.bierlee@lostmoment.com * Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2017 Mike Bierlee * Copyright: 2014-2018 Mike Bierlee
* License: * License:
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
@ -17,61 +17,61 @@ import poodinis.container;
import poodinis.factory; import poodinis.factory;
class Registration { class Registration {
private TypeInfo _registeredType = null; private TypeInfo _registeredType = null;
private TypeInfo_Class _instanceType = null; private TypeInfo_Class _instanceType = null;
private Registration linkedRegistration; private Registration linkedRegistration;
private shared(DependencyContainer) _originatingContainer; private shared(DependencyContainer) _originatingContainer;
private InstanceFactory _instanceFactory; private InstanceFactory _instanceFactory;
private void delegate() _preDestructor; private void delegate() _preDestructor;
public @property registeredType() { public @property registeredType() {
return _registeredType; return _registeredType;
} }
public @property instanceType() { public @property instanceType() {
return _instanceType; return _instanceType;
} }
public @property originatingContainer() { public @property originatingContainer() {
return _originatingContainer; return _originatingContainer;
} }
public @property instanceFactory() { public @property instanceFactory() {
return _instanceFactory; return _instanceFactory;
} }
public @property preDestructor() { public @property preDestructor() {
return _preDestructor; return _preDestructor;
} }
protected @property preDestructor(void delegate() preDestructor) { protected @property preDestructor(void delegate() preDestructor) {
_preDestructor = preDestructor; _preDestructor = preDestructor;
} }
this(TypeInfo registeredType, TypeInfo_Class instanceType, InstanceFactory instanceFactory, shared(DependencyContainer) originatingContainer) { this(TypeInfo registeredType, TypeInfo_Class instanceType, InstanceFactory instanceFactory, shared(DependencyContainer) originatingContainer) {
this._registeredType = registeredType; this._registeredType = registeredType;
this._instanceType = instanceType; this._instanceType = instanceType;
this._originatingContainer = originatingContainer; this._originatingContainer = originatingContainer;
this._instanceFactory = instanceFactory; this._instanceFactory = instanceFactory;
} }
public Object getInstance(InstantiationContext context = new InstantiationContext()) { public Object getInstance(InstantiationContext context = new InstantiationContext()) {
if (linkedRegistration !is null) { if (linkedRegistration !is null) {
return linkedRegistration.getInstance(context); return linkedRegistration.getInstance(context);
} }
if (instanceFactory is null) { if (instanceFactory is null) {
throw new InstanceCreationException("No instance factory defined for registration of type " ~ registeredType.toString()); throw new InstanceCreationException("No instance factory defined for registration of type " ~ registeredType.toString());
} }
return instanceFactory.getInstance(); return instanceFactory.getInstance();
} }
public Registration linkTo(Registration registration) { public Registration linkTo(Registration registration) {
this.linkedRegistration = registration; this.linkedRegistration = registration;
return this; return this;
} }
} }
/** /**
@ -80,35 +80,35 @@ class Registration {
* Effectively makes the given registration a singleton. * Effectively makes the given registration a singleton.
*/ */
public Registration singleInstance(Registration registration) { public Registration singleInstance(Registration registration) {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.yes); registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.yes);
return registration; return registration;
} }
/** /**
* Scopes registrations to return a new instance every time the given registration is resolved. * Scopes registrations to return a new instance every time the given registration is resolved.
*/ */
public Registration newInstance(Registration registration) { public Registration newInstance(Registration registration) {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.no); registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.no);
return registration; return registration;
} }
/** /**
* Scopes registrations to return the given instance every time the given registration is resolved. * Scopes registrations to return the given instance every time the given registration is resolved.
*/ */
public Registration existingInstance(Registration registration, Object instance) { public Registration existingInstance(Registration registration, Object instance) {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.yes, instance); registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.yes, instance);
return registration; return registration;
} }
public string toConcreteTypeListString(Registration[] registrations) { public string toConcreteTypeListString(Registration[] registrations) {
auto concreteTypeListString = ""; auto concreteTypeListString = "";
foreach (registration ; registrations) { foreach (registration ; registrations) {
if (concreteTypeListString.length > 0) { if (concreteTypeListString.length > 0) {
concreteTypeListString ~= ", "; concreteTypeListString ~= ", ";
} }
concreteTypeListString ~= registration.instanceType.toString(); concreteTypeListString ~= registration.instanceType.toString();
} }
return concreteTypeListString; return concreteTypeListString;
} }
class InstantiationContext {} class InstantiationContext {}

View file

@ -4,7 +4,7 @@
* *
* Authors: * Authors:
* Mike Bierlee, m.bierlee@lostmoment.com * Mike Bierlee, m.bierlee@lostmoment.com
* Copyright: 2014-2017 Mike Bierlee * Copyright: 2014-2018 Mike Bierlee
* License: * License:
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
@ -19,20 +19,20 @@ import poodinis.polyfill;
* Thrown when something goes wrong during value injection. * Thrown when something goes wrong during value injection.
*/ */
class ValueInjectionException : Exception { class ValueInjectionException : Exception {
mixin basicExceptionCtors; mixin basicExceptionCtors;
} }
/** /**
* Thrown by injectors when the value with the given key cannot be found. * Thrown by injectors when the value with the given key cannot be found.
*/ */
class ValueNotAvailableException : Exception { class ValueNotAvailableException : Exception {
this(string key) { this(string key) {
super(format("Value for key %s is not available", key)); super(format("Value for key %s is not available", key));
} }
this(string key, Throwable cause) { this(string key, Throwable cause) {
super(format("Value for key %s is not available", key), cause); super(format("Value for key %s is not available", key), cause);
} }
} }
/** /**
@ -53,12 +53,12 @@ class ValueNotAvailableException : Exception {
* --- * ---
*/ */
struct Value { struct Value {
/** /**
* The textual key used to find the value by injectors. * The textual key used to find the value by injectors.
* *
* The format is injector-specific. * The format is injector-specific.
*/ */
string key; string key;
} }
/** /**
@ -79,12 +79,12 @@ struct Value {
* --- * ---
*/ */
struct MandatoryValue { struct MandatoryValue {
/** /**
* The textual key used to find the value by injectors. * The textual key used to find the value by injectors.
* *
* The format is injector-specific. * The format is injector-specific.
*/ */
string key; string key;
} }
/** /**
@ -110,14 +110,14 @@ struct MandatoryValue {
* --- * ---
*/ */
interface ValueInjector(Type) { interface ValueInjector(Type) {
/** /**
* Get a value from the injector by key. * Get a value from the injector by key.
* *
* The key can have any format. Generally you are encouraged * The key can have any format. Generally you are encouraged
* to accept a dot separated path, for example: server.http.port * to accept a dot separated path, for example: server.http.port
* *
* Throws: ValueNotAvailableException when the value for the given key is not available for any reason * Throws: ValueNotAvailableException when the value for the given key is not available for any reason
*/ */
Type get(string key); Type get(string key);
} }

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */
@ -12,171 +12,171 @@ import std.exception;
version(unittest) { version(unittest) {
// Test autowiring concrete type to existing instance // Test autowiring concrete type to existing instance
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto componentB = new ComponentB(); auto componentB = new ComponentB();
container.autowire(componentB); container.autowire(componentB);
assert(componentB !is null, "Autowirable dependency failed to autowire"); assert(componentB !is null, "Autowirable dependency failed to autowire");
} }
// Test autowiring interface type to existing instance // Test autowiring interface type to existing instance
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
auto componentD = new ComponentD(); auto componentD = new ComponentD();
container.autowire(componentD); container.autowire(componentD);
assert(componentD.componentC !is null, "Autowirable dependency failed to autowire"); assert(componentD.componentC !is null, "Autowirable dependency failed to autowire");
} }
// Test autowiring private members // Test autowiring private members
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
auto componentD = new ComponentD(); auto componentD = new ComponentD();
container.autowire(componentD); container.autowire(componentD);
assert(componentD.privateComponentC is componentD.componentC, "Autowire private dependency failed"); assert(componentD.privateComponentC is componentD.componentC, "Autowire private dependency failed");
} }
// Test autowiring will only happen once // Test autowiring will only happen once
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC).newInstance(); container.register!(InterfaceA, ComponentC).newInstance();
auto componentD = new ComponentD(); auto componentD = new ComponentD();
container.autowire(componentD); container.autowire(componentD);
auto expectedComponent = componentD.componentC; auto expectedComponent = componentD.componentC;
container.autowire(componentD); container.autowire(componentD);
auto actualComponent = componentD.componentC; auto actualComponent = componentD.componentC;
assert(expectedComponent is actualComponent, "Autowiring the second time wired a different instance"); assert(expectedComponent is actualComponent, "Autowiring the second time wired a different instance");
} }
// Test autowiring unregistered type // Test autowiring unregistered type
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto componentD = new ComponentD(); auto componentD = new ComponentD();
assertThrown!(ResolveException)(container.autowire(componentD), "Autowiring unregistered type should throw ResolveException"); assertThrown!(ResolveException)(container.autowire(componentD), "Autowiring unregistered type should throw ResolveException");
} }
// Test autowiring member with non-autowire attribute does not autowire // Test autowiring member with non-autowire attribute does not autowire
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto componentE = new ComponentE(); auto componentE = new ComponentE();
container.autowire(componentE); container.autowire(componentE);
assert(componentE.componentC is null, "Autowiring should not occur for members with attributes other than @Autowire"); assert(componentE.componentC is null, "Autowiring should not occur for members with attributes other than @Autowire");
} }
// Test autowire class with alias declaration // Test autowire class with alias declaration
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto componentDeclarationCocktail = new ComponentDeclarationCocktail(); auto componentDeclarationCocktail = new ComponentDeclarationCocktail();
container.autowire(componentDeclarationCocktail); container.autowire(componentDeclarationCocktail);
assert(componentDeclarationCocktail.componentA !is null, "Autowiring class with non-assignable declarations failed"); assert(componentDeclarationCocktail.componentA !is null, "Autowiring class with non-assignable declarations failed");
} }
// Test autowire class with qualifier // Test autowire class with qualifier
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
auto componentX = container.resolve!(InterfaceA, ComponentX); auto componentX = container.resolve!(InterfaceA, ComponentX);
auto monkeyShine = new MonkeyShine(); auto monkeyShine = new MonkeyShine();
container.autowire(monkeyShine); container.autowire(monkeyShine);
assert(monkeyShine.component is componentX, "Autowiring class with qualifier failed"); assert(monkeyShine.component is componentX, "Autowiring class with qualifier failed");
} }
// Test autowire class with multiple qualifiers // Test autowire class with multiple qualifiers
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
auto componentC = container.resolve!(InterfaceA, ComponentC); auto componentC = container.resolve!(InterfaceA, ComponentC);
auto componentX = container.resolve!(InterfaceA, ComponentX); auto componentX = container.resolve!(InterfaceA, ComponentX);
auto bootstrapBootstrap = new BootstrapBootstrap(); auto bootstrapBootstrap = new BootstrapBootstrap();
container.autowire(bootstrapBootstrap); container.autowire(bootstrapBootstrap);
assert(bootstrapBootstrap.componentX is componentX, "Autowiring class with multiple qualifiers failed"); assert(bootstrapBootstrap.componentX is componentX, "Autowiring class with multiple qualifiers failed");
assert(bootstrapBootstrap.componentC is componentC, "Autowiring class with multiple qualifiers failed"); assert(bootstrapBootstrap.componentC is componentC, "Autowiring class with multiple qualifiers failed");
} }
// Test getting instance from autowired registration will autowire instance // Test getting instance from autowired registration will autowire instance
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto registration = new AutowiredRegistration!ComponentB(typeid(ComponentB), new InstanceFactory(), container).singleInstance(); auto registration = new AutowiredRegistration!ComponentB(typeid(ComponentB), new InstanceFactory(), container).singleInstance();
auto instance = cast(ComponentB) registration.getInstance(new AutowireInstantiationContext()); auto instance = cast(ComponentB) registration.getInstance(new AutowireInstantiationContext());
assert(instance.componentA !is null); assert(instance.componentA !is null);
} }
// Test autowiring a dynamic array with all qualified types // Test autowiring a dynamic array with all qualified types
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
auto lord = new LordOfTheComponents(); auto lord = new LordOfTheComponents();
container.autowire(lord); container.autowire(lord);
assert(lord.components.length == 2, "Dynamic array was not autowired"); assert(lord.components.length == 2, "Dynamic array was not autowired");
} }
// Test autowiring new instance of singleinstance registration with newInstance UDA // Test autowiring new instance of singleinstance registration with newInstance UDA
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto regularComponentA = container.resolve!ComponentA; auto regularComponentA = container.resolve!ComponentA;
auto charlie = new ComponentCharlie(); auto charlie = new ComponentCharlie();
container.autowire(charlie); container.autowire(charlie);
assert(charlie.componentA !is regularComponentA, "Autowiring class with AssignNewInstance did not yield a different instance"); assert(charlie.componentA !is regularComponentA, "Autowiring class with AssignNewInstance did not yield a different instance");
} }
// Test autowiring members from base class // Test autowiring members from base class
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
container.register!ComponentB; container.register!ComponentB;
container.register!ComponentZ; container.register!ComponentZ;
auto instance = new ComponentZ(); auto instance = new ComponentZ();
container.autowire(instance); container.autowire(instance);
assert(instance.componentA !is null); assert(instance.componentA !is null);
} }
// Test autowiring optional dependencies // Test autowiring optional dependencies
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto instance = new OuttaTime(); auto instance = new OuttaTime();
container.autowire(instance); container.autowire(instance);
assert(instance.interfaceA is null); assert(instance.interfaceA is null);
assert(instance.componentA is null); assert(instance.componentA is null);
assert(instance.componentCs is null); assert(instance.componentCs is null);
} }
// Test autowiring class using value injection // Test autowiring class using value injection
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!int, TestInjector); container.register!(ValueInjector!int, TestInjector);
container.register!ComponentA; container.register!ComponentA;
auto instance = new ValuedClass(); auto instance = new ValuedClass();
container.autowire(instance); container.autowire(instance);
assert(instance.intValue == 8); assert(instance.intValue == 8);
assert(instance.unrelated !is null); assert(instance.unrelated !is null);
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */
@ -12,105 +12,105 @@ import std.exception;
version(unittest) { version(unittest) {
//Test register component registrations from context //Test register component registrations from context
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
auto bananaInstance = container.resolve!Banana; auto bananaInstance = container.resolve!Banana;
assert(bananaInstance.color == "Yellow"); assert(bananaInstance.color == "Yellow");
} }
//Test non-annotated methods are not registered //Test non-annotated methods are not registered
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
assertThrown!ResolveException(container.resolve!Apple); assertThrown!ResolveException(container.resolve!Apple);
} }
//Test register component by base type //Test register component by base type
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
auto instance = container.resolve!Fruit; auto instance = container.resolve!Fruit;
assert(instance.getShape() == "Pear shaped"); assert(instance.getShape() == "Pear shaped");
} }
//Test register components with multiple candidates //Test register components with multiple candidates
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
auto rabbit = container.resolve!(Animal, Rabbit); auto rabbit = container.resolve!(Animal, Rabbit);
assert(rabbit.getYell() == "Squeeeeeel"); assert(rabbit.getYell() == "Squeeeeeel");
auto wolf = container.resolve!(Animal, Wolf); auto wolf = container.resolve!(Animal, Wolf);
assert(wolf.getYell() == "Wooooooooooo"); assert(wolf.getYell() == "Wooooooooooo");
} }
//Test register component as prototype //Test register component as prototype
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
auto firstInstance = container.resolve!PieChart; auto firstInstance = container.resolve!PieChart;
auto secondInstance = container.resolve!PieChart; auto secondInstance = container.resolve!PieChart;
assert(firstInstance !is null && secondInstance !is null); assert(firstInstance !is null && secondInstance !is null);
assert(firstInstance !is secondInstance); assert(firstInstance !is secondInstance);
} }
// Test setting up simple dependencies through application context // Test setting up simple dependencies through application context
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!SimpleContext; container.registerContext!SimpleContext;
auto instance = container.resolve!CakeChart; auto instance = container.resolve!CakeChart;
assert(instance !is null); assert(instance !is null);
} }
// Test resolving dependency from registered application context // Test resolving dependency from registered application context
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!SimpleContext; container.registerContext!SimpleContext;
auto instance = container.resolve!Apple; auto instance = container.resolve!Apple;
assert(instance !is null); assert(instance !is null);
} }
// Test autowiring application context // Test autowiring application context
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Apple; container.register!Apple;
container.registerContext!AutowiredTestContext; container.registerContext!AutowiredTestContext;
auto instance = container.resolve!ClassWrapper; auto instance = container.resolve!ClassWrapper;
assert(instance !is null); assert(instance !is null);
assert(instance.someClass !is null); assert(instance.someClass !is null);
} }
// Test autowiring application context with dependencies registered in same context // Test autowiring application context with dependencies registered in same context
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!ComplexAutowiredTestContext; container.registerContext!ComplexAutowiredTestContext;
auto instance = container.resolve!ClassWrapperWrapper; auto instance = container.resolve!ClassWrapperWrapper;
auto wrapper = container.resolve!ClassWrapper; auto wrapper = container.resolve!ClassWrapper;
auto someClass = container.resolve!Apple; auto someClass = container.resolve!Apple;
assert(instance !is null); assert(instance !is null);
assert(instance.wrapper is wrapper); assert(instance.wrapper is wrapper);
assert(instance.wrapper.someClass is someClass); assert(instance.wrapper.someClass is someClass);
} }
// Test resolving registered context // Test resolving registered context
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!TestContext; container.registerContext!TestContext;
container.resolve!ApplicationContext; container.resolve!ApplicationContext;
} }
} }

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */
@ -12,137 +12,137 @@ import std.exception;
version(unittest) { version(unittest) {
// Test instance factory with singletons // Test instance factory with singletons
unittest { unittest {
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.yes); factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.yes);
auto instanceOne = factory.getInstance(); auto instanceOne = factory.getInstance();
auto instanceTwo = factory.getInstance(); auto instanceTwo = factory.getInstance();
assert(instanceOne !is null, "Created factory instance is null"); assert(instanceOne !is null, "Created factory instance is null");
assert(instanceOne is instanceTwo, "Created factory instance is not the same"); assert(instanceOne is instanceTwo, "Created factory instance is not the same");
} }
// Test instance factory with new instances // Test instance factory with new instances
unittest { unittest {
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.no); factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.no);
auto instanceOne = factory.getInstance(); auto instanceOne = factory.getInstance();
auto instanceTwo = factory.getInstance(); auto instanceTwo = factory.getInstance();
assert(instanceOne !is null, "Created factory instance is null"); assert(instanceOne !is null, "Created factory instance is null");
assert(instanceOne !is instanceTwo, "Created factory instance is the same"); assert(instanceOne !is instanceTwo, "Created factory instance is the same");
} }
// Test instance factory with existing instances // Test instance factory with existing instances
unittest { unittest {
auto existingInstance = new TestImplementation(); auto existingInstance = new TestImplementation();
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.yes, existingInstance); factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.yes, existingInstance);
auto instanceOne = factory.getInstance(); auto instanceOne = factory.getInstance();
auto instanceTwo = factory.getInstance(); auto instanceTwo = factory.getInstance();
assert(instanceOne is existingInstance, "Created factory instance is not the existing instance"); assert(instanceOne is existingInstance, "Created factory instance is not the existing instance");
assert(instanceTwo is existingInstance, "Created factory instance is not the existing instance when called again"); assert(instanceTwo is existingInstance, "Created factory instance is not the existing instance when called again");
} }
// Test instance factory with existing instances when setting singleton flag to "no" // Test instance factory with existing instances when setting singleton flag to "no"
unittest { unittest {
auto existingInstance = new TestImplementation(); auto existingInstance = new TestImplementation();
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.no, existingInstance); factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), CreatesSingleton.no, existingInstance);
auto instance = factory.getInstance(); auto instance = factory.getInstance();
assert(instance is existingInstance, "Created factory instance is not the existing instance"); assert(instance is existingInstance, "Created factory instance is not the existing instance");
} }
// Test creating instance using custom factory method // Test creating instance using custom factory method
unittest { unittest {
Object factoryMethod() { Object factoryMethod() {
auto instance = new TestImplementation(); auto instance = new TestImplementation();
instance.someContent = "Ducks!"; instance.someContent = "Ducks!";
return instance; return instance;
} }
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(null, CreatesSingleton.yes, null, &factoryMethod); factory.factoryParameters = InstanceFactoryParameters(null, CreatesSingleton.yes, null, &factoryMethod);
auto instance = cast(TestImplementation) factory.getInstance(); auto instance = cast(TestImplementation) factory.getInstance();
assert(instance !is null, "No instance was created by factory or could not be cast to expected type"); assert(instance !is null, "No instance was created by factory or could not be cast to expected type");
assert(instance.someContent == "Ducks!"); assert(instance.someContent == "Ducks!");
} }
// Test injecting constructor of class // Test injecting constructor of class
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestImplementation; container.register!TestImplementation;
auto factory = new ConstructorInjectingInstanceFactory!ClassWithConstructor(container); auto factory = new ConstructorInjectingInstanceFactory!ClassWithConstructor(container);
auto instance = cast(ClassWithConstructor) factory.getInstance(); auto instance = cast(ClassWithConstructor) factory.getInstance();
assert(instance !is null); assert(instance !is null);
assert(instance.testImplementation is container.resolve!TestImplementation); assert(instance.testImplementation is container.resolve!TestImplementation);
} }
// Test injecting constructor of class with multiple constructors injects the first candidate // Test injecting constructor of class with multiple constructors injects the first candidate
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!SomeOtherClassThen; container.register!SomeOtherClassThen;
container.register!TestImplementation; container.register!TestImplementation;
auto factory = new ConstructorInjectingInstanceFactory!ClassWithMultipleConstructors(container); auto factory = new ConstructorInjectingInstanceFactory!ClassWithMultipleConstructors(container);
auto instance = cast(ClassWithMultipleConstructors) factory.getInstance(); auto instance = cast(ClassWithMultipleConstructors) factory.getInstance();
assert(instance !is null); assert(instance !is null);
assert(instance.someOtherClassThen is container.resolve!SomeOtherClassThen); assert(instance.someOtherClassThen is container.resolve!SomeOtherClassThen);
assert(instance.testImplementation is null); assert(instance.testImplementation is null);
} }
// Test injecting constructor of class with multiple constructor parameters // Test injecting constructor of class with multiple constructor parameters
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!SomeOtherClassThen; container.register!SomeOtherClassThen;
container.register!TestImplementation; container.register!TestImplementation;
auto factory = new ConstructorInjectingInstanceFactory!ClassWithConstructorWithMultipleParameters(container); auto factory = new ConstructorInjectingInstanceFactory!ClassWithConstructorWithMultipleParameters(container);
auto instance = cast(ClassWithConstructorWithMultipleParameters) factory.getInstance(); auto instance = cast(ClassWithConstructorWithMultipleParameters) factory.getInstance();
assert(instance !is null); assert(instance !is null);
assert(instance.someOtherClassThen is container.resolve!SomeOtherClassThen); assert(instance.someOtherClassThen is container.resolve!SomeOtherClassThen);
assert(instance.testImplementation is container.resolve!TestImplementation); assert(instance.testImplementation is container.resolve!TestImplementation);
} }
// Test injecting constructor of class with primitive constructor parameters // Test injecting constructor of class with primitive constructor parameters
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!SomeOtherClassThen; container.register!SomeOtherClassThen;
auto factory = new ConstructorInjectingInstanceFactory!ClassWithPrimitiveConstructor(container); auto factory = new ConstructorInjectingInstanceFactory!ClassWithPrimitiveConstructor(container);
auto instance = cast(ClassWithPrimitiveConstructor) factory.getInstance(); auto instance = cast(ClassWithPrimitiveConstructor) factory.getInstance();
assert(instance !is null); assert(instance !is null);
assert(instance.someOtherClassThen is container.resolve!SomeOtherClassThen); assert(instance.someOtherClassThen is container.resolve!SomeOtherClassThen);
} }
// Test injecting constructor of class with empty constructor will skip injection // Test injecting constructor of class with empty constructor will skip injection
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto factory = new ConstructorInjectingInstanceFactory!ClassWithEmptyConstructor(container); auto factory = new ConstructorInjectingInstanceFactory!ClassWithEmptyConstructor(container);
auto instance = cast(ClassWithEmptyConstructor) factory.getInstance(); auto instance = cast(ClassWithEmptyConstructor) factory.getInstance();
assert(instance !is null); assert(instance !is null);
assert(instance.someOtherClassThen is null); assert(instance.someOtherClassThen is null);
} }
// Test injecting constructor of class with no candidates fails // Test injecting constructor of class with no candidates fails
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto factory = new ConstructorInjectingInstanceFactory!ClassWithNonInjectableConstructor(container); auto factory = new ConstructorInjectingInstanceFactory!ClassWithNonInjectableConstructor(container);
assertThrown!InstanceCreationException(factory.getInstance()); assertThrown!InstanceCreationException(factory.getInstance());
} }
} }

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */
@ -8,5 +8,5 @@
module poodinis.test.foreignDependencies; module poodinis.test.foreignDependencies;
version(unittest) { version(unittest) {
class Ola {} class Ola {}
} }

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */
@ -12,51 +12,51 @@ import std.exception;
version(unittest) { version(unittest) {
// Test getting instance without scope defined throws exception // Test getting instance without scope defined throws exception
unittest { unittest {
Registration registration = new Registration(typeid(TestType), null, null, null); Registration registration = new Registration(typeid(TestType), null, null, null);
assertThrown!(InstanceCreationException)(registration.getInstance(), null); assertThrown!(InstanceCreationException)(registration.getInstance(), null);
} }
// Test set single instance scope using scope setter // Test set single instance scope using scope setter
unittest { unittest {
Registration registration = new Registration(null, typeid(TestType), new InstanceFactory(), null); Registration registration = new Registration(null, typeid(TestType), new InstanceFactory(), null);
auto chainedRegistration = registration.singleInstance(); auto chainedRegistration = registration.singleInstance();
auto instance1 = registration.getInstance(); auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance(); auto instance2 = registration.getInstance();
assert(instance1 is instance2, "Registration with single instance scope did not return the same instance"); assert(instance1 is instance2, "Registration with single instance scope did not return the same instance");
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set"); assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
} }
// Test set new instance scope using scope setter // Test set new instance scope using scope setter
unittest { unittest {
Registration registration = new Registration(null, typeid(TestType), new InstanceFactory(), null); Registration registration = new Registration(null, typeid(TestType), new InstanceFactory(), null);
auto chainedRegistration = registration.newInstance(); auto chainedRegistration = registration.newInstance();
auto instance1 = registration.getInstance(); auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance(); auto instance2 = registration.getInstance();
assert(instance1 !is instance2, "Registration with new instance scope did not return a different instance"); assert(instance1 !is instance2, "Registration with new instance scope did not return a different instance");
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set"); assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
} }
// Test set existing instance scope using scope setter // Test set existing instance scope using scope setter
unittest { unittest {
Registration registration = new Registration(null, null, new InstanceFactory(), null); Registration registration = new Registration(null, null, new InstanceFactory(), null);
auto expectedInstance = new TestType(); auto expectedInstance = new TestType();
auto chainedRegistration = registration.existingInstance(expectedInstance); auto chainedRegistration = registration.existingInstance(expectedInstance);
auto actualInstance = registration.getInstance(); auto actualInstance = registration.getInstance();
assert(expectedInstance is expectedInstance, "Registration with existing instance scope did not return the same instance"); assert(expectedInstance is expectedInstance, "Registration with existing instance scope did not return the same instance");
assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set"); assert(registration is chainedRegistration, "Registration returned by scope setting is not the same as the registration being set");
} }
// Test linking registrations // Test linking registrations
unittest { unittest {
Registration firstRegistration = new Registration(typeid(TestInterface), typeid(TestImplementation), new InstanceFactory(), null).singleInstance(); Registration firstRegistration = new Registration(typeid(TestInterface), typeid(TestImplementation), new InstanceFactory(), null).singleInstance();
Registration secondRegistration = new Registration(typeid(TestImplementation), typeid(TestImplementation), new InstanceFactory(), null).singleInstance().linkTo(firstRegistration); Registration secondRegistration = new Registration(typeid(TestImplementation), typeid(TestImplementation), new InstanceFactory(), null).singleInstance().linkTo(firstRegistration);
auto firstInstance = firstRegistration.getInstance(); auto firstInstance = firstRegistration.getInstance();
auto secondInstance = secondRegistration.getInstance(); auto secondInstance = secondRegistration.getInstance();
assert(firstInstance is secondInstance); assert(firstInstance is secondInstance);
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */

View file

@ -1,6 +1,6 @@
/** /**
* Poodinis Dependency Injection Framework * Poodinis Dependency Injection Framework
* Copyright 2014-2017 Mike Bierlee * Copyright 2014-2018 Mike Bierlee
* This software is licensed under the terms of the MIT license. * This software is licensed under the terms of the MIT license.
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */
@ -12,126 +12,126 @@ import std.exception;
version(unittest) { version(unittest) {
struct LocalStruct { struct LocalStruct {
bool wasInjected = false; bool wasInjected = false;
} }
class LocalStructInjector : ValueInjector!LocalStruct { class LocalStructInjector : ValueInjector!LocalStruct {
public override LocalStruct get(string key) { public override LocalStruct get(string key) {
auto data = LocalStruct(true); auto data = LocalStruct(true);
return data; return data;
} }
} }
class LocalClassWithStruct { class LocalClassWithStruct {
@Value("") @Value("")
public LocalStruct localStruct; public LocalStruct localStruct;
} }
// Test injection of values // Test injection of values
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!MyConfig; container.register!MyConfig;
container.register!(ValueInjector!int, IntInjector); container.register!(ValueInjector!int, IntInjector);
container.register!(ValueInjector!string, StringInjector); container.register!(ValueInjector!string, StringInjector);
container.register!(ValueInjector!Thing, ThingInjector); container.register!(ValueInjector!Thing, ThingInjector);
auto instance = container.resolve!MyConfig; auto instance = container.resolve!MyConfig;
assert(instance.stuffs == 364); assert(instance.stuffs == 364);
assert(instance.name == "Le Chef"); assert(instance.name == "Le Chef");
assert(instance.thing.x == 8899); assert(instance.thing.x == 8899);
} }
// Test injection of values throws exception when injector is not there // Test injection of values throws exception when injector is not there
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!MyConfig; container.register!MyConfig;
assertThrown!ResolveException(container.resolve!MyConfig); assertThrown!ResolveException(container.resolve!MyConfig);
assertThrown!ValueInjectionException(autowire(container, new MyConfig())); assertThrown!ValueInjectionException(autowire(container, new MyConfig()));
} }
// Test injection of values with defaults // Test injection of values with defaults
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithDefaults; container.register!ConfigWithDefaults;
container.register!(ValueInjector!int, DefaultIntInjector); container.register!(ValueInjector!int, DefaultIntInjector);
auto instance = container.resolve!ConfigWithDefaults; auto instance = container.resolve!ConfigWithDefaults;
assert(instance.noms == 9); assert(instance.noms == 9);
} }
// Test mandatory injection of values which are available // Test mandatory injection of values which are available
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithMandatory; container.register!ConfigWithMandatory;
container.register!(ValueInjector!int, MandatoryAvailableIntInjector); container.register!(ValueInjector!int, MandatoryAvailableIntInjector);
auto instance = container.resolve!ConfigWithMandatory; auto instance = container.resolve!ConfigWithMandatory;
assert(instance.nums == 7466); assert(instance.nums == 7466);
} }
// Test mandatory injection of values which are not available // Test mandatory injection of values which are not available
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithMandatory; container.register!ConfigWithMandatory;
container.register!(ValueInjector!int, MandatoryUnavailableIntInjector); container.register!(ValueInjector!int, MandatoryUnavailableIntInjector);
assertThrown!ResolveException(container.resolve!ConfigWithMandatory); assertThrown!ResolveException(container.resolve!ConfigWithMandatory);
assertThrown!ValueInjectionException(autowire(container, new ConfigWithMandatory())); assertThrown!ValueInjectionException(autowire(container, new ConfigWithMandatory()));
} }
// Test injecting dependencies within value injectors // Test injecting dependencies within value injectors
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto dependency = new Dependency(); auto dependency = new Dependency();
container.register!Dependency.existingInstance(dependency); container.register!Dependency.existingInstance(dependency);
container.register!(ValueInjector!int, DependencyInjectedIntInjector); container.register!(ValueInjector!int, DependencyInjectedIntInjector);
auto injector = cast(DependencyInjectedIntInjector) container.resolve!(ValueInjector!int); auto injector = cast(DependencyInjectedIntInjector) container.resolve!(ValueInjector!int);
assert(injector.dependency is dependency); assert(injector.dependency is dependency);
} }
// Test injecting circular dependencies within value injectors // Test injecting circular dependencies within value injectors
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!int, CircularIntInjector); container.register!(ValueInjector!int, CircularIntInjector);
auto injector = cast(CircularIntInjector) container.resolve!(ValueInjector!int); auto injector = cast(CircularIntInjector) container.resolve!(ValueInjector!int);
assert(injector.dependency is injector); assert(injector.dependency is injector);
assert(injector.get("whatever") == 3); assert(injector.get("whatever") == 3);
} }
// Test value injection within value injectors // Test value injection within value injectors
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!int, ValueInjectedIntInjector); container.register!(ValueInjector!int, ValueInjectedIntInjector);
auto injector = cast(ValueInjectedIntInjector) container.resolve!(ValueInjector!int); auto injector = cast(ValueInjectedIntInjector) container.resolve!(ValueInjector!int);
assert(injector.count == 5); assert(injector.count == 5);
} }
// Test value injection within dependencies of value injectors // Test value injection within dependencies of value injectors
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithDefaults; container.register!ConfigWithDefaults;
container.register!(ValueInjector!int, DependencyValueInjectedIntInjector); container.register!(ValueInjector!int, DependencyValueInjectedIntInjector);
auto injector = cast(DependencyValueInjectedIntInjector) container.resolve!(ValueInjector!int); auto injector = cast(DependencyValueInjectedIntInjector) container.resolve!(ValueInjector!int);
assert(injector.config.noms == 8899); assert(injector.config.noms == 8899);
} }
// Test resolving locally defined struct injector (github issue #20) // Test resolving locally defined struct injector (github issue #20)
unittest { unittest {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!LocalStruct, LocalStructInjector); container.register!(ValueInjector!LocalStruct, LocalStructInjector);
container.register!LocalClassWithStruct; container.register!LocalClassWithStruct;
auto injector = container.resolve!(ValueInjector!LocalStruct); auto injector = container.resolve!(ValueInjector!LocalStruct);
assert(injector !is null); assert(injector !is null);
auto localClass = container.resolve!LocalClassWithStruct; auto localClass = container.resolve!LocalClassWithStruct;
assert(localClass.localStruct.wasInjected); assert(localClass.localStruct.wasInjected);
} }
} }