Change the module loading mechanism.
barney
allows you to hook into the module loading mechanism to
easily trigger functions or return a given value everytime a
module is required. Just make sure you know what you're doing, as this is
intended to be used mainly during testing or development.
Instalation
As usual:
npm install barney
Tests can be run with:
npm test
Usage
Once you require barney
, require()
will already be hooked. Just add
hook
s and interceptor
s.
var barney = ; // Add a hook to the `foo` modulebarney;var foo = ;assert; var count = 0; // Add an interceptorbarney; var path = ;var fs = ;assert;
See the complete API reference.
Interceptors
Interceptors are functions called whenever you require a module. Interceptors
are executed sequentially and if any of them returns a truthy value, the
chain is stopped and that value will be used as the return value for the
require()
call:
var count = 0; // Count how many times `require()` is usedbarney; var path = ;//> Logs '1 requires...' var fs = ;//> Logs '2 requires...'
You can also add an interceptor for a specific module:
var pathCount = 0; // Count how many times the `path` module has been requiredbarney; var path = ;//> Logs '`path` has been required 1 times...' var fs = ;//> Logs nothing var path = ;//> Logs '`path` has been required 2 times...'
NOTE: interceptors are run before the original loader function is executed, therefore they will be executed even if the module has already been loaded and in cache.
Interceptors receive the same arguments as the original loader function:
barney;
NOTE: at this point
request
has not yet been resolved. You probably want to resolve it usingrequire.resolve(request)
before using it.
It is also important to keep in mind that no further interceptor is called if one of them returns a truthy value:
barney; barney; ;// No log message is printed...
NOTE: generic interceptors (interceptors not attached to a specific module) are always executed before module-specific interceptors.
Hooks
Hooks are static values that should be returned for specific modules. It has almost the same effect as returning a value from an interceptor:
var assert = ; var xhrStub = sinon; // Replace the `xhr` module with a stubbarney; var xhr = ;assert;
NOTE: Hooks differ from interceptors as they are called only after all interceptors have been run:
barney.intercept('foo', function () { return 'foo'; }); barney.hook('foo', 'bar'); // Note that the interceptor has higher priority over hooks assert.equal(require('foo'), 'foo); assert.notEqual(require('foo'), 'bar');
Priorities
This is an overview of the priorities when loading a module:
- all generic interceptors are executed;
- if none returns a truthy value, all module-specific interceptors are executed;
- if no value has been returned yet, we check if a static hook is registered for the requested module;
- if no value is found, we hand the request over to the original loader function;
Restoring & cleaning up
After you are done messing with the require()
function, you can deactivate
barney
and restore the original loader using barney.restore()
. This
keeps all interceptors and hooks in place.
After restoring the original require()
function, you can hook it again
calling barney.hook()
(without params).
To clear all hooks and interceptors, you can use barney.reset()
. Or you
can specify a module to be cleared: barney.reset('foo')
.
In case you need to force the original loader to reload a module (require()
caches the loaded modules), you can do so using barney.unload('foo')
.
Reference
NOTE: all methods are chainable unless stated otherwise.
barney.hook()
Activates barney
's hooks. This is automatically called the first
time barney
is required.
barney.restore()
Or barney.unhook()
Restores the original require()
method. Hooks and interceptors are kept.
See barney.reset()
for removing hooks and interceptors.
barney.hook(module, value)
Sets the hooked value for the given module. Future calls to require(module)
will return value
(unless an interceptor returns a different value).
barney.intercept(function[, index])
Adds a generic interceptor to the stack. The interceptor will be executed
for all future calls to require()
(for all modules). If it returns a
truthy value, that will be the value returned by require()
.
If index
is defined, the interceptor will be inserted at the given index.
Interceptors cannot be added twice.
barney.intercept(module, function[, index])
Same as the previous, but adds the interceptor to a specific module
.
barney.require(module)
Or barney.skip(module)
Loads the module using the original require()
function (skips all hooks
and interceptors).
barney.reset([module])
Removes all hooks and interceptors. If a module
is defined, removes hooks
and interceptors for that module only.
barney.unload(module)
Removes the cached value for module
from the original require()
cache.
barney.isActive()
Not chainable
Returns true
if barney is hooked into require()
.
barney.notFound([module])
Not chainable if called without args
If a module
is defined, adds an interceptor that will throw a
MODULE_NOT_FOUND
error.
barney;
If called without arguments (or with more than one argument), throws a
MODULE_NOT_FOUND
error to help simulating missing modules.
barney;
Example
Hooking a module for testing
This uses sinon-chai
and mocha
:
var barney = ;var sinon = ;var chai = ; chai; var xhrStub = sinon; // During tests, if we believe a module is well tested enough, we may just// make sure that it is used as expected, avoiding actually calling them// in order to simplify our tests.//// In this example, we can avoid the actual HTTP request that the `xhr` module// would make by using a stub and could make some tests synchronous.barney; // All `require('xhr')` in `myModule` will now use the `xhrStub` instead of// the actual `xhr` module.var myModule = ; ;
License
This is an open source project released under the MIT license terms.