78 lines
2.7 KiB
CoffeeScript
78 lines
2.7 KiB
CoffeeScript
_ = require("lodash")
|
|
|
|
EventEmitter = require('events').EventEmitter
|
|
|
|
# Helper class to register and store modules.
|
|
# It stores a list of objects in an object literal indexed by the name of the module.
|
|
# Includes methods for a class to ask for a module and wait until it is ready.
|
|
#
|
|
# This class is used to prevent errors when modules are required in an order that
|
|
# would generate a circular dependency. In these cases, the objects might not be loaded
|
|
# entirely.
|
|
# @see http://nodejs.org/api/modules.html#modules_cycles
|
|
#
|
|
# With this class, the class requiring a module can wait until the module is properly
|
|
# loaded. More than that, it will return an instanced object, not only a reference to
|
|
# a class (as usually done when using `require`).
|
|
#
|
|
# @example How to use it
|
|
# modules = new Modules()
|
|
# modules.wait ["db"], ->
|
|
# # this callback will only be called when the module "db" is registered
|
|
# db = config.modules.get("db")
|
|
# ...
|
|
# # calls to register a module can be made anywhere in the application
|
|
# modules.register "db", new Database()
|
|
#
|
|
module.exports = class Modules extends EventEmitter
|
|
|
|
constructor: ->
|
|
# the list of modules registered:
|
|
@modules = {}
|
|
# list of callbacks waiting for a module to be registered:
|
|
@callbacks = []
|
|
|
|
# Registers a new module with the name in `name` and the content in `object`.
|
|
# @param name [string] the name of the module
|
|
# @param object [string] the instance of the module
|
|
# @return [object] the same object in the parameter `object`
|
|
register: (name, object) ->
|
|
@modules[name] = object
|
|
@_checkCallbacks()
|
|
object
|
|
|
|
# Blocks until a list of modules is registered.
|
|
# @param names [Array] an array of strings with the names of all modules that should be waited for
|
|
# @param callback [Function] will be called when *all* modules in `names` are registered
|
|
wait: (names, callback) ->
|
|
names = [names] unless _.isArray(names)
|
|
@callbacks.push {modules: names, fn: callback}
|
|
@_checkCallbacks()
|
|
|
|
# Returns the module with the name in `name`.
|
|
# @param name [string] the name of the module to be returned
|
|
# @return [object] the module asked for
|
|
get: (name) ->
|
|
@modules[name]
|
|
|
|
# Returns the list of all modules registered.
|
|
# @return [Array] all modules registered
|
|
all: ->
|
|
@modules
|
|
|
|
# Run through the list of registered callbacks in `@callbacks` to see if any of
|
|
# them are ready to be called (if all modules waited for are available).
|
|
# @private
|
|
_checkCallbacks: () ->
|
|
toRemove = []
|
|
for cb in @callbacks
|
|
done = true
|
|
for name in cb.modules
|
|
unless @modules[name]?
|
|
done = false
|
|
break
|
|
if done
|
|
cb.fn()
|
|
toRemove.push cb
|
|
@callbacks = _.filter(@callbacks, (i) -> i not in toRemove)
|