A very simple straightforward IOC/DI container
Summer is a very simple straightforward IOC/DI container. It was developed with the goal in mind to define application contexts and resolve multiple asynchronous resources with their dependencies with ease.
- Basic usage
- Scoped locals
- Scoped objects
- Included hooks
The root context, as its name implies, is a basic context without parent context.
Initialize a root context:
Summer = require "summer"rootContext =
A scoped context is an optionally named context with a parent context.
Initialize a scoped context:
requestContext = rootContext"request"
Get root context and scoped contexts:
childContextparent #=> returns the parent contextchildContextroot #=> returns the root contextchildContextcontext"request" #=> returns the context with name `request`
There are two ways to register an initializer, either by register a class or an initializer function.
Summer::register can be called as follow:
Possible options are:
- initializer: The initializer function (can be supplied as second or third argument)
- class: Class to initialize (only when no initializer is supplied)
- args: Array of arguments for initializer/constructor
- properties: Object with properties to set on initialized object
- init: Function or name of an instance method to call after properties are set.
- dispose: Function or name of an instance method to call after deleting the resolved object from scope (only useful for scoped objects).
The "init" and "dispose" callbacks will be called with a callback function if the arguments length is greater than 0.
Register a class:
cregister "fooService"class: FooSevice
Register a class with constructor arguments:
cregister "fooService"class: FooSeviceargs: cref"db"5
Summer::ref returns a reference to a registered service ("db" in this example). This reference will be resolved and supplied as first constructor argument, the second constructor argument will be 5.
Register a class with properties:
cregister "fooService"class: FooSeviceproperties:db: cref"db"maxConnections: 5
This properties will be applied after constructing the class. For an explanation of "c.ref" see the example above.
Register an initializer:
cregister "db"db = ...dbopencallbackerrdb
cregister "db": ...
Register an initializer with arguments:
cregister "usersCollection"cref"db"dbcollection "userCollection"callbackerrcollection
cregister "usersCollection" args: cref"db" ...
fs = require "fs"cregister "configFile" args: __dirname + "/../config.json" fsreadFile
Register an initializer with multiple arguments:
Register an initializer with a dispose method:
cregister "db":db = ...dbopencallbackerrdbdispose: "close" # same as (db)-> db.close()
Summer can resolve one or more objects at once.
Resolve one object:
cresolve "serviceId" ...
Resolve multiple objects:
cresolve "serviceOne""serviceTwo"doSomething servicesserviceOnedoSomething servicesserviceTwo
Resolve multiple objects with an alias to id map:
cresolve foo: "serviceOne"bar: "serviceTwo"servicesfoo #=> serviceOneservicesbar #=> serviceTwo
If you like to resolve an object manually from inside your initializer function, it is important to do this with the method "resolve" on the current binding (this or @) and not with "resolve" on your context object, otherwise the cyclical dependency detection won't work.
The context/scope acts like an "inheritable" map where "get" and "has" goes backwards up the ancestor chain of the scope to find a value. The methods "set" and "delete" will operate on the current scope and shadow values from ancestor scopes.
contextset "foo""bar"childContexthas "foo" #=> truechildContextget "foo" #=> "bar"childContextset "foo""baz"childContextget "foo" #=> "baz"contextget "foo" #=> "bar"childContextdelete "foo"childContextget "foo" #=> "bar"
Scoped objects are objects which are singletons in their scope. The scope option can be any name of an existing named scope. Special scopes are "prototype", which is not registered on any scope and "singleton", which is registered on the root context. If no scope option is given "singleton" is assumed.
Prototype scope example:
cregister "fooService"class: FooSevicescope: "prototype"
Request scope example:
cregister "fooService"class: FooSevicescope: "request"
The Summer::middleware method returns a Connect middleware which wraps the context in a request scope on every request. It calls shutdown on the request scope after calling "res.end". It sets the newly created context on "req.context".
appuse applicationContextmiddlewarename="request"appusedoSometing reqcontextresend"ok" #=> will shutdown the previously created request context (req.context)
The Summer container extends Nodes events.EventEmitter. Three events are emitted by Summer:
- initialized: After resolving the object. The listener signature is (container, factory, object).
- dispose: During disposing the object, triggered by Summer::dispose. The listener signature is (container, factory, object).
- shutdown: During shutting down the container, triggered by Summer::shutdown. The listener signature is (container).
The hooks are interceptor callbacks, allowing the application to inspect and/or manipulate resolved objects during their life cycle.
Registration of a hook
SummeraddHook "afterPropertiesSet"if typeof instanceafterPropertiesSet is "function"instanceafterPropertiesSetcallback
Summer has three life cycle phases:
- afterInitialize: Is called after resolving the object and before setting its properties.
- afterPropertiesSet: Is called after resolving and setting properties on the resolved object, this is called independently of defining properties for a registry entry (provided by the "resolveAndSetProperties" hook).
- dispose: Is called after removing the resolved object from scope.
Summer comes with predefined and pre-registered hooks to extend its basic functionality:
- Summer.Hooks.autowired: Checks the class/initializer for "autowire" annotations and process them.
- Summer.Hooks.disposableEntity: Handles the factories "dispose" option.
- Summer.Hooks.initializingEntity: Handles the factories "init" option.
- Summer.Hooks.applicationContextAware: If implemented on the resolved object, this will call "setApplicationContext" with the context. This hook is registered on the "afterInitialize" phase.
- Summer.Hooks.contextIdAware: If implement on the resolved object, this will call "setContextId" with the context id. This hook is registered on the "afterInitialize" phase. If implemented with more than one argument, a callback will be supplied as second argument.
Autowiring allows a class or initializer to declare its dependencies by id or type.
Summerautowire @collection: 'postCollection'
This will set the property "collection" with the resolved "postCollection" on an instance of "PostService" resolved by Summer.
Another way to declare dependencies is by supplying a type.
Summerautowire @persistenceManager: PersistenceManager
This will look for a factory with a class or subclass of "PersistenceManager". The type must not be ambiguous in the registry, that means there should be only one factory with class/subclass of "PersistenceManager" registered.
If you find what looks like a bug:
Check the GitHub issue tracker to see if anyone else has reported an issue.
If you don’t see anything, create an issue with information about how to reproduce it.
If you want to contribute an enhancement or a fix:
Fork the project on github.
Make your changes with tests.
Commit the changes without making changes to any files that aren’t related to your enhancement or fix.
Send a pull request.
Created by Alexander Jentz, Germany.
MIT License. See the included MIT-LICENSE file.