/inject

Dependency injection for C++ - no macros, no code generation, no common base class

Primary LanguageC++MIT LicenseMIT

INJECT
======

Inject is intended to be a C++ dependency injection library which:
 * is header-only
    Library does not require anything but including its header files
 * is non-intrusive
    Any class can be a component. No need to inherit library interfaces, declare
    mandatory members or include a macro in the class declaration. For a class
    to be a component all it needs is to have its default-constructor public and
    functioning.
 * is macro-less
    The library does not rely on pre-processing magic for code-generation. No
    need to declare constructors in a special way or include black-magic macros
    in your class' body.
 * is declarative
    This is similar to the non-intrusive bullet. Using a class as a component
    is a matter of declaration, which is done separately from the class'
    declaration, see below for examples
 * doesn't require code-generation
    The library relies only on the standard code generation facilities offered
    by C++98 through the template mechanism. No additional scripts/executables
    need to be run to get injections functionality to the application.
 * is very simple to use
 * fully supports allocation and instantiation through std::allocator
 * supports up to 10 constructor arguments
 * can inject to setter methods (two types, see examples)
 * does not use RTTI
 * is fully C++98 complaint

USAGE & DOCUMENTATION
=====================
- start with the quick reference below
- see: examples/README for code examples
- doxygen: http://www.duvdevani.com/itay/projects/inject/doxygen/

QUICK REFERENCE
===============

[All procedural snippets assume ctx is a context instance]

Register a new component (mandatory for everything else)
--------------------------------------------------------
  Declarative:
    context<>::component<T> comp_decl;
    or:
    context<>::component<T> comp_decl("component_name");

  Procedural:
    TBD
    
  Where:
    T - typename of component

Register a component as implementing another component
------------------------------------------------------

  Declarative:
    context<>::component<T>::provides<S> impls_decl;
  
  Procedural:
    TBD

  Where:
    T - typename of implementing component
    S - typename of component implemented

Select implementing component to use when component is requested
----------------------------------------------------------------
  
  [implementing component must be declared as such (see above)]

  Declarative:
    context<>::component<T>::implemented_by<S[, Scope]> impl_decl;
  
  Procedural:
    /* bind T as S implementation */
    ctx.bind<T, S[, Scope]>();
    or
    /* bind T as its own implementation */
    ctx.bind<T[, Scope]>(); 

  Where:
    T     - typename of component implemented
    S     - typename of implementation component
    Scope - (optional) implementation scope, one of: scope_none (new instance
            every time - default) and scope_singleton (same instance every time)

Request an instance of a component
----------------------------------

  Declarative:
    context<>::injected<T> p;

  Procedural:
    context<>::ptr<T>::type p = ctx.instance<T>();
  
  Where:
    T - typename of component to get instance of

Allocate (and deallocate) a component using a custom allocator
--------------------------------------------------------------

  Declarative:
    context<>::component<T>::allocator< MyAllocator<T> > alloc_decl;

  Procedural:
    TBD
  
  Where:
    T - typename of component to set allocator for

Instantiate a component with a specific constructor
---------------------------------------------------

  Declarative:
    context<>::component<T>::constructor<A1[, A2 ... A10]> ctor_decl;

  Procedural:
    TBD
  
  Where:
    T       - typename of component
    A1..A10 - typename of components in constructor declaration

Inject a component to a C++-style setter during component initialization
------------------------------------------------------------------------

  Declarative:
    context<>::component<T>::assign_setter<S, &T::setter> setter_decl;

  Procedural:
    TBD
  
  Where:
    T      - typename of component with setter
    S      - typename of component to inject
    setter - public, non-static method in T with the non-const signature:
             context<>::ptr<S>::type& setter();

Inject a component to a Java-style setter during component initialization
-------------------------------------------------------------------------

  Declarative:
    context<>::component<T>::arg_setter<S, &T::setter> setter_decl;

  Procedural:
    TBD
  
  Where:
    T      - typename of component with setter
    S      - typename of component to inject
    setter - public, non-static method in T with the non-const signature:
             void setter(const context<>::ptr<S>::type& s);

BUILDING
========
Inject is a header-only library, which means it does not require building. Just
include "inject/inject.h" and compile.

To build the unit-tests and example code:
- install cmake >= 2.6
- install boost >= 1.47
- in the top-level directory, run: 'cmake -DCMAKE_BUILD_TYPE=Debug .' or
  '-DCMAKE_BUILD_TYPE=Release .'
- make clean && make

Unit-tests executable is under: src/tests/inject/unit_tests
Example executable is under each example directory.

If you have Doxygen installed, you can run 'make doc' at the root folder to
generate the API documentation. it should generate to the doxygen/
subfolder.

COMPATIBILITY
=============

Inject was tested with:
- g++ 4.7.1
- clang++ 3.0-6
- MSVC 9 and 10

TODO
====
 * Use std::shared_ptr<> when C++11 is available
 * Use vardiac templates for constructor handling if C++11 is available
 * Implicit component registration if possible (infer from functional
   declarations)
 * thread-safe singletons (with boost or C++11 STL if available)
 * Implicit cast from ptr<S>::type so it could be assigned to straight setter
   (i.e. S& setter() and void setter(const S& s), without ptr<S>::type wrapper)
 * Test with XCode

OTHER C++ INJECTION LIBRARIES
=============================
 * dicpp (https://bitbucket.org/cheez/dicpp/)
 * cpp-resolver (http://sourceforge.net/projects/cpp-resolver/)
 * Torgny (http://programmaticallyspeaking.blogspot.com/2010/04/beautiful-dependency-injection-in-c.html)
 * QtIocContainer (http://sourceforge.net/projects/qtioccontainer/)
 * hypodermic (http://code.google.com/p/hypodermic/)
 * sauce (https://github.com/phs/sauce)
 * wallaroo (https://code.google.com/p/wallaroo/)

LICENSE
=======
Copyright (c) 2012-2013 Itay Duvdevani
All rights reserved.

Inject is distributed under the MIT OSI license. For additional info, please
refer to: LICENSE or contact itay@duvdevani.com