Browse files

added crude implementations of various meta-haxx for require

  • Loading branch information...
1 parent 76129f1 commit 55e3c094daed36a4d39c7c9e13bf5f9800b2d4c2 @dominictarr committed Nov 5, 2010
Showing with 697 additions and 246 deletions.
  1. +10 −0 common.js
  2. +61 −212 modules.js
  3. +196 −0 resolve.js
  4. +10 −0 test/.examples/one_random.js
  5. +97 −31 test/modules.asynct.js
  6. +265 −0 test/modules.wrapRequire.asynct.js
  7. +13 −3 test/remap.asynct.js
  8. +45 −0 test/resolve.asynct.js
View
10 common.js
@@ -0,0 +1,10 @@
+//common
+
+ var debugLevel = parseInt(process.env["NODE_DEBUG"], 16);
+ exports.debug = debug
+ function debug (x) {
+ if (debugLevel & 1) {
+ process.binding('stdio').writeError(x + "\n");
+ }
+ }
+
View
273 modules.js
@@ -1,7 +1,17 @@
+
+ var path = require('path')
+ , resolve = require('./resolve')
+
+ exports.resolveModuleFilename = resolve.resolveModuleFilename
+
var internalModuleCache = {};
function useCache(moduleCache){
+// var extensions = {};
+ var extensions = require.extensions
+
+
// Set the environ variable NODE_MODULE_CONTEXTS=1 to make node load all
// modules in thier own context.
var contextLoad = false;
@@ -11,7 +21,6 @@ function useCache(moduleCache){
var registerExtension = function(){console.log('require.registerExtension() removed. Use require.extensions instead');}
-
// *** module prototype ***
//the test of this is at the bottom...
exports.Module = Module
@@ -35,7 +44,8 @@ function useCache(moduleCache){
*/
- var natives = process.binding('natives');
+ var natives = process.binding('natives'); //refactor this out to call require
+ // remove this...>>>
function loadNative (id) {
var m = new Module(id);
@@ -53,30 +63,11 @@ function useCache(moduleCache){
return loadNative(id).exports;
}
+ // <<< remote this...
// Modules
- var debugLevel = parseInt(process.env["NODE_DEBUG"], 16);
- function debug (x) {
- if (debugLevel & 1) {
- process.binding('stdio').writeError(x + "\n");
- }
- }
-
- var pathFn = process.compile("(function (exports) {" + natives.path + "\n})",
- "path");
- // this is the path module,
- //since require isn't setup yet you have to load this funny way.
- var pathModule = createInternalModule('path', pathFn);
- var path = pathModule.exports;
-
- function createInternalModule (id, constructor) {//only for internal node stuff... fs, http, etc.
- var m = new Module(id);
- constructor(m.exports);
- m.loaded = true;
- internalModuleCache[id] = m;
- return m;
- };
+ var debug = require('./common').debug
// The paths that the user has specifically asked for. Highest priority.
@@ -86,156 +77,19 @@ function useCache(moduleCache){
resolving modules... START
*/
- var modulePaths = [];
- if (process.env.NODE_PATH) {
- modulePaths = process.env.NODE_PATH.split(":");
- }
- // The default global paths that are always checked.
- // Lowest priority.
- var defaultPaths = [];
- if (process.env.HOME) {
- defaultPaths.push(path.join(process.env.HOME, ".node_modules"));
- defaultPaths.push(path.join(process.env.HOME, ".node_libraries"));
- }
- defaultPaths.push(path.join(process.execPath, "..", "..", "lib", "node"));
-
- var extensions = {};
-
- // Which files to traverse while finding id? Returns generator function.
- function traverser (id, dirs) {
- var head = [], inDir = [], dirs = dirs.slice(),
- exts = Object.keys(extensions);
- return function next () {
- var result = head.shift();
- if (result) { return result; }//on first call result will be undefined
-
- var gen = inDir.shift();
- if (gen) { head = gen(); return next(); }//also null first time
-
- var dir = dirs.shift();//not necessarily null.
- if (dir !== undefined) {
- function direct (ext) { return path.join(dir, id + ext); }
- function index (ext) { return path.join(dir, id, 'index' + ext); }
- inDir = [
- function () { return exts.map(direct); },
- function () { return exts.map(index); }
- ];
- /*
- head will be assigned here,
- so on second call head will be ok,
- and inDir will be ok, so after that call,
- head will have ext.length values,
- if you get through all of those,
- gen will be called again, and you'll have ext values.
-
- so it only actually builds the list of possible paths as it goes
- doing a minimal amount of string and array manip, unless it's necessary
-
- the same could be done with two nested for in loops.
- */
- head = [path.join(dir, id)];
- return next();
- }
- };
- }
- // traverser is only called from findModulePath
- function findModulePath (request, paths) {
- var nextLoc = traverser(request, paths);
-
- var fs = requireNative('fs');
-
- var location, stats;
- while (location = nextLoc()) {
- try { stats = fs.statSync(location); } catch(e) { continue; }
- if (stats && !stats.isDirectory()) return location;
- }
- return false;
- }
- //who calls findModulePath? only resolveModuleFilename
-
-
-/*
- modulePathWalk is a little strange... i havn't seen anyone using node_modules directories.
- it has the effect of adding ./node_modules to the path, ahead of the default paths.
-
-*/
- function modulePathWalk (parent) {
- if (parent._modulePaths) return parent._modulePaths;
- var p = parent.filename.split("/");
- var mp = [];
- while (undefined !== p.pop()) {
- mp.push(p.join("/")+"/node_modules");
- }
- return parent._modulePaths = mp;
- }
-
- // sync - no i/o performed
- function resolveModuleLookupPaths (request, parent) {
-
- if (natives[request]) return [request, []];
-
- if (request.charAt(0) === '/') {
- return [request, ['']];
- }
-
- var start = request.substring(0, 2);
- if (start !== "./" && start !== "..") {
- var paths = modulePaths.concat(modulePathWalk(parent)).concat(defaultPaths);
- return [request, paths];//the more interesting case... search through the path.
- }
-
- // Is the parent an index module?
- // We can assume the parent has a valid extension,
- // as it already has been accepted as a module.
- var isIndex = /^index\.\w+?$/.test(path.basename(parent.filename)),//check whether parent.filename is index.[EXTENSION]
- parentIdPath = isIndex ? parent.id : path.dirname(parent.id),//the name that was require(name) to get parent module.
- id = path.join(parentIdPath, request);//absolute path from the relative one.
- //if parent is an index, then it's id will be the name of the directory it is in.
- //and since it is relative, there is only be extentions.length places to look for the new file.
-
- // make sure require('./path') and require('path') get distinct ids, even
- // when called from the toplevel js file
- if (parentIdPath === '.' && id.indexOf('/') === -1) {
- id = './' + id;
- }
- debug("RELATIVE: requested:" + request + " set ID to: "+id+" from "+parent.id);
- return [id, [path.dirname(parent.filename)]];
- }
- exports.resolveModuleFilename = resolveModuleFilename
- function resolveModuleFilename (request, parent) {
- if (natives[request]) return [request, request];//fs http net, etc.
- var resolvedModule = resolveModuleLookupPaths(request, parent),
- id = resolvedModule[0],
- paths = resolvedModule[1];
-
- // look up the filename first, since that's the cache key.
- debug("looking for " + JSON.stringify(id) + " in " + JSON.stringify(paths));
- var filename = findModulePath(request, paths);
- if (!filename) {
- throw new Error("Cannot find module '" + request + "'");
- }
- return [id, filename];
- }
/*
resolve modules ends...
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
*/
- exports.loadModule = loadModule
+ exports.loadResolvedModule = loadResolvedModule
- function loadModule (request, parent, wrapper) {
- debug("loadModule REQUEST " + (request) + " parent: " + parent.id + " wrapper: " + wrapper);
-
- var resolved = resolveModuleFilename(request, parent);
- var id = resolved[0];
- var filename = resolved[1];
-
- // With natives id === request
- // We deal with these first
+ function loadResolvedModule (id,filename,parent,wrapper){
+ // remote this...>>>
var cachedNative = internalModuleCache[id];
if (cachedNative) {
return cachedNative;
@@ -247,24 +101,42 @@ function useCache(moduleCache){
var cachedModule = moduleCache[filename];
if (cachedModule) return cachedModule;
+ // <<< remote this...
- /*
- possibly, the way to do reloading is to use a special cache.
- rather than delete the reloaded module from the cache.
-
- */
-
var module = new Module(id, parent);
+
moduleCache[filename] = module;
module.requireWrapper = wrapper;//intercepts creation of require so it can me remapped.
module.load(filename);
+
return module;
+ }
+
+ exports.loadModule = loadModule
+
+ function loadModule (request, parent, wrapper) {
+ // console.log("loadModule REQUEST " + (request) + " parent: " + parent.id + " wrapper: " + wrapper);
+
+ var resolved = resolve.resolveModuleFilename(request, parent);
+ var id = resolved[0];
+ var filename = resolved[1];
+ //console.log(" RESOLVED " + (id) + " filename: " + filename );
+
+ // With natives id === request
+ // We deal with these first
+
+ return loadResolvedModule (id,filename,parent,wrapper)
};
-/* function loadModule (request, parent, wrapper) {
- return loadModule2(request, parent, wrapper).exports;
+ function loadModuleExports (request, parent, wrapper) {
+
+ if (natives[request]) {//usually, we want to load these from the main cache.
+ return require(request)
+ }
+
+ return loadModule(request, parent, wrapper).exports;
};
-*/
+
//resolveModuleFilename was here. moved into resolvein module section
@@ -278,7 +150,6 @@ function useCache(moduleCache){
/*
finish loading the module with the function for loading that extension type
.. if .js it will call _compile()
-
*/
var extension = path.extname(filename) || '.js';
@@ -295,47 +166,25 @@ function useCache(moduleCache){
}
exports.makeRequire = makeRequire
+ //modify loadModuleExports() to call require.resolve so that you can just modify that to get a change.
- function makeRequire(self){//also pass in mapping? or a function which may modify require...
+ function makeRequire(self){
function require (path) {
- return loadModule(path, self,self.wrapRequire).exports;
+ /*
+ i'm compromising the design to keep the old interface.
+ better to add a function that returns [id,filename]
+ */
+
+ var id = resolve.resolveModuleId(path,self)
+ , filename = require.resolve(path)
+
+ return loadResolvedModule (id,filename,self,self.requireWrapper).exports
+// return loadModuleExports(path, self,self.wrapRequire);//wrapRequire is the makeRequire which will be assigned to sub modules.
}
- /*
- which would need to be passed loadModule,
- and assigned to the new Module so that _compile
- can see it, after the extension method is called...
-
- hang on, if it is a property of a Module then loadModule can already see it
- since self is a Module.
-
- you could just create a new module, and then assign it a requireWrapper.
-
-// loadModule will copy self.requireWrapper to the new module
- the Module constructor will copy requireWrapper from it's parent.
-
- or rather, will it need a copy method? (so it can decend the hierachy?)
- NO. in moduleWrapper this will -> the module, and so will know the parent,
- so it will be able to make a decision about what to copy.
-
- so to get started,
- you create a module2 = new Module, assign it's wrapper,
- //loadModule(path,module2)
-
- hmm, maybe should pass requireWrapper into load module.
-
- then it is just
- modules = require('modules')
- modules.loadModule('id',module,wrapper).exports
- that assigns the wrapper to the module,
- then _compile calls it. which also gets to (re)define what it assigns to
- the next require in submodules...
-
- yes that will work.
- */
- require.resolve = function (request) {
- return resolveModuleFilename(request, self)[1];
+ require.resolve = function newResolve (request) {
+ return resolve.resolveModuleFilename(request, self)[1];
}
- require.paths = modulePaths;
+ require.paths = resolve.modulePaths;
require.main = process.mainModule;
// Enable support to add extra extension types
require.extensions = extensions;
@@ -352,7 +201,7 @@ function useCache(moduleCache){
content = content.replace(/^\#\!.*/, '');
- var require = self.requireWrapper ? self.requireWrapper(makeRequire(self)) : makeRequire(self);
+ var require = self.requireWrapper ? self.requireWrapper(makeRequire(self),self) : makeRequire(self);
var dirname = path.dirname(filename);
@@ -416,7 +265,7 @@ function useCache(moduleCache){
// Native extension for .js
extensions['.js'] = function (module, filename) {
- var content = requireNative('fs').readFileSync(filename, 'utf8');
+ var content = require('fs').readFileSync(filename, 'utf8');
module._compile(content, filename);
};
View
196 resolve.js
@@ -0,0 +1,196 @@
+
+// var modules
+ var natives = process.binding('natives');
+ var debug = require('./common').debug
+ var path = require('path')
+
+// var pathFn = process.compile("(function (exports) {" + natives.path + "\n})",
+ // "path");
+ // this is the path module,
+ //since require isn't setup yet you have to load this funny way.
+// var pathModule = createInternalModule('path', pathFn);
+// var path = pathModule.exports;
+
+/* function createInternalModule (id, constructor) {//only for internal node stuff... fs, http, etc.
+ var m = new Module(id);
+ constructor(m.exports);
+ m.loaded = true;
+ internalModuleCache[id] = m;
+ return m;
+ };*/
+
+
+ var modulePaths = [];
+ exports.modulePaths = modulePaths
+ if (process.env.NODE_PATH) {
+ modulePaths = process.env.NODE_PATH.split(":");
+ }
+
+ // The default global paths that are always checked.
+ // Lowest priority.
+ var defaultPaths = [];
+ if (process.env.HOME) {
+ defaultPaths.push(path.join(process.env.HOME, ".node_modules"));
+ defaultPaths.push(path.join(process.env.HOME, ".node_libraries"));
+ }
+ defaultPaths.push(path.join(process.execPath, "..", "..", "lib", "node"));
+
+ var extensions = require.extensions
+ // exports.extensions = extensions
+
+ // Which files to traverse while finding id? Returns generator function.
+ function traverser (id, dirs) {
+ var head = [], inDir = [], dirs = dirs.slice(),
+ exts = Object.keys(extensions);
+ return function next () {
+ var result = head.shift();
+ if (result) { return result; }//on first call result will be undefined
+
+ var gen = inDir.shift();
+ if (gen) { head = gen(); return next(); }//also null first time
+
+ var dir = dirs.shift();//not necessarily null.
+ if (dir !== undefined) {
+ function direct (ext) { return path.join(dir, id + ext); }
+ function index (ext) { return path.join(dir, id, 'index' + ext); }
+ inDir = [
+ function () { return exts.map(direct); },
+ function () { return exts.map(index); }
+ ];
+ /*
+ head will be assigned here,
+ so on second call head will be ok,
+ and inDir will be ok, so after that call,
+ head will have ext.length values,
+ if you get through all of those,
+ gen will be called again, and you'll have ext values.
+
+ so it only actually builds the list of possible paths as it goes
+ doing a minimal amount of string and array manip, unless it's necessary
+
+ the same could be done with two nested for in loops.
+ */
+ head = [path.join(dir, id)];
+ return next();
+ }
+ };
+ }
+
+ // traverser is only called from findModulePath
+ function findModulePath (request, paths) {
+ var nextLoc = traverser(request, paths);
+
+ var fs = require('fs');
+
+ var location, stats;
+ while (location = nextLoc()) {
+ try { stats = fs.statSync(location); } catch(e) { continue; }
+ if (stats && !stats.isDirectory()) return location;
+ }
+ return false;
+ }
+ //who calls findModulePath? only resolveModuleFilename
+
+
+/*
+ modulePathWalk is a little strange... i havn't seen anyone using node_modules directories.
+ it has the effect of adding ./node_modules to the path, ahead of the default paths.
+
+*/
+ function modulePathWalk (parent) {
+ if (parent._modulePaths) return parent._modulePaths;
+ var p = parent.filename.split("/");
+ var mp = [];
+ while (undefined !== p.pop()) {
+ mp.push(p.join("/")+"/node_modules");
+ }
+ return parent._modulePaths = mp;
+ }
+
+ exports.resolveModuleId = resolveModuleId
+
+ function resolveModuleId (request,parent){
+
+ if (natives[request]) return request;
+
+ if (request.charAt(0) === '/') {
+ return request;
+ }
+
+ var start = request.substring(0, 2);
+
+ if (start !== "./" && start !== "..") {
+ return request
+ }
+ var isIndex = /^index\.\w+?$/.test(path.basename(parent.filename)),//check whether parent.filename is index.[EXTENSION]
+ parentIdPath = isIndex ? parent.id : path.dirname(parent.id),//the name that was require(name) to get parent module.
+ id = path.join(parentIdPath, request);//absolute path from the relative one.
+ //if parent is an index, then it's id will be the name of the directory it is in.
+ //and since it is relative, there is only be extentions.length places to look for the new file.
+
+ // make sure require('./path') and require('path') get distinct ids, even
+ // when called from the toplevel js file
+ if (parentIdPath === '.' && id.indexOf('/') === -1) {
+ id = './' + id;
+ }
+ return id
+ }
+
+ exports.resolveModuleLookupPaths = resolveModuleLookupPaths
+ // sync - no i/o performed
+ function resolveModuleLookupPaths (request, parent) {
+
+ if (natives[request]) return [request, []];
+
+ if (request.charAt(0) === '/') {
+ return [request, ['']];
+ }
+
+ var start = request.substring(0, 2);
+
+ if (start !== "./" && start !== "..") {
+ var paths = modulePaths.concat(modulePathWalk(parent)).concat(defaultPaths);
+ return [request, paths];//the more interesting case... search through the path.
+ }
+
+ // Is the parent an index module?
+ // We can assume the parent has a valid extension,
+ // as it already has been accepted as a module.
+ var isIndex = /^index\.\w+?$/.test(path.basename(parent.filename)),//check whether parent.filename is index.[EXTENSION]
+ parentIdPath = isIndex ? parent.id : path.dirname(parent.id),//the name that was require(name) to get parent module.
+ id = path.join(parentIdPath, request);//absolute path from the relative one.
+ //if parent is an index, then it's id will be the name of the directory it is in.
+ //and since it is relative, there is only be extentions.length places to look for the new file.
+
+ // make sure require('./path') and require('path') get distinct ids, even
+ // when called from the toplevel js file
+
+
+
+ //here is a special case i think the main module gets the id '.'
+
+ if (parentIdPath === '.' && id.indexOf('/') === -1) {
+ id = './' + id;
+ }
+ debug("RELATIVE: requested:" + request + " set ID to: "+id+" from "+parent.id);
+ return [id, [path.dirname(parent.filename)]];
+ }
+
+ exports.resolveModuleFilename = resolveModuleFilename
+ function resolveModuleFilename (request, parent) {
+ if (natives[request]) return [request, request];//fs http net, etc.
+ var resolvedModule = resolveModuleLookupPaths(request, parent),
+ id = resolvedModule[0],
+ paths = resolvedModule[1];
+
+ // look up the filename first, since that's the cache key.
+ debug("looking for " + JSON.stringify(id) + " in " + JSON.stringify(paths));
+ var filename = findModulePath(request, paths);
+ if (!filename) {
+// console.log(extensions);
+ throw new Error("Cannot find module '" + request + "', from: " + path.dirname(parent.filename));
+ }
+ return [id, filename];
+ }
+
+
View
10 test/.examples/one_random.js
@@ -0,0 +1,10 @@
+/*
+ this file will export one random number,
+ for all the requires which load it,
+ unless it's loaded into a new cache.
+*/
+
+var oneRandom = Math.random(1000)
+exports.oneRandom = function(){
+ return oneRandom;
+}
View
128 test/modules.asynct.js
@@ -1,6 +1,8 @@
var modules = require('remap/modules')
, require2 = modules.makeRequire(module)
, inspect = require('util').inspect
+
+; // a semi-colon for Ryan Gahl
exports['Require2 can load a module'] = function (test){
@@ -14,12 +16,18 @@ exports['Require2 can load a module'] = function (test){
}
function looksLikeRequire(test,r){
- test.ok('function' === typeof r.resolve)
- test.ok('object' === typeof r.paths)
- test.ok('object' === typeof r.extensions)
- test.ok('function' === typeof r.registerExtension)
- test.ok('object' === typeof r.cache)
- test.ok('object' === typeof r.main)
+ var types =
+ { resolve: 'function'
+ , paths: 'object'
+ , extensions: 'object'
+ , registerExtension: 'function'
+ , cache: 'object'
+ , main: 'object'
+ }
+
+ for (i in types){
+ test.equal(typeof r[i], types[i], "typeof :'" + r + '.' + i + ' should be: ' + types[i] + ', but was: ' + typeof r[i])
+ }
}
exports['loads a module with different module, require'] = function (test){
@@ -35,15 +43,16 @@ exports['loads a module with different module, require'] = function (test){
looksLikeRequire(test,mirror.require)
- test.notEqual(mirror,mirror2,"require 2 can load another instance of a module")
+ test.notEqual(mirror,mirror2
+ , "require 2 can load another instance of a module")
test.strictEqual(mirror,mirror1,"require2 still use a cache")
test.equal(mirror.require.cache,mirror.require.cache)
test.equal(require.cache,require.cache)
test.notEqual(mirror.require.cache,require.cache)//loads a different cache.
- test.finish();
+ test.finish()
}
exports['modules.loadModule accepts a function which is assigned to module and called after require is made'] = function (test){
@@ -52,53 +61,77 @@ exports['modules.loadModule accepts a function which is assigned to module and c
, inside = null
, a2 = modules.loadModule('./.examples/for_modules.asynct.js',module,wrapRequire).exports
- test.strictEqual(a,a1,"modules.loadModule(X,module) will return the same as module.makeRequire(module).require(X)")
+ test.strictEqual(a,a1
+ , "modules.loadModule(X,module) will return the same as module.makeRequire(module).require(X)")
test.strictEqual(inside.exports,a2)
- test.finish();
+ test.finish()
function wrapRequire (r){
looksLikeRequire(test,r)
-
+
+ inside = this
+ return r
+ }
+
/*
here is where you'd modify the behaviour of require.
actually, you'll probably just make a whole new makeRequire
you could intercept the request and ask for something different
- also, you could just return something completely different.. mock it out...
+ also, you could just return something completely different..
+ mock it out...
+
+ *//*
+
+ hmm, maybe should pass requireWrapper into load module.
- another thing that is necessary is optionally don't cache it, so that a
- second version of a module can be loaded... say with different dependency implementations.
+ then it is just
+ modules = require('modules')
+ modules.loadModule('id',module,wrapper).exports
+ that asigns the wrapper to the module,
+ then _compile calls it. which also gets to (re)define what it asigns to
+ the next require in submodules...
+
+ yes that will work.
+
+ applications of this crazy module:
+ 1. reroute resolve, so that it loads a different module.
+ 2. return before calling loadModule, i.e. return a mock instead.
+ 3. modify module loaded.
+ i.e. wrap it and record what is called.
+ or wrap all db queries in a transaction and revert it after the test.
+ 4. change the makeRequire method for children...
*/
-
- inside = this
- return r
- }
+
}
exports['modules can uncache a loaded module'] = function (test){
var a,a2,a3, aId = './.examples/a'
a_module = modules.loadModule(aId,module)
a = a_module.exports
- test.strictEqual(a,modules.loadModule(aId,module).exports,'normally modules.loadModule will return the same modules from the cache')
+ test.strictEqual(a,modules.loadModule(aId,module).exports
+ , 'normally modules.loadModule will return the same modules from the cache')
// console.log('LOOKING FOR: ' + a.filename)
// console.log('cache: ' + inspect(modules.moduleCache))
- test.ok(modules.moduleCache[a.module.filename],'should load module into cache')
+ test.ok(modules.moduleCache[a.module.filename]
+ , 'should load module into cache')
modules.uncache(a_module)
a2 = modules.loadModule(aId,module).exports
- console.log('cache: ' + inspect(require.cache))
+// console.log('cache: ' + inspect(require.cache))
- test.notStrictEqual(a,a2,'by uncaching you can load a module twice')
+ test.notStrictEqual(a,a2
+ , 'by uncaching you can load a module twice')
test.strictEqual(a.a(),a2.a())
test.strictEqual(a.version,a2.version)
@@ -121,7 +154,7 @@ exports['modules can uncache a loaded module'] = function (test){
*/
//I don't have a test for load of children yet anyway.
- test.finish();
+ test.finish()
}
@@ -131,22 +164,29 @@ exports ['modules can be given a new cache to load into'] = function (test){
require3 = modules2.makeRequire(module)
looksLikeRequire(test,require3)
- test.notStrictEqual(require3.cache,require2.cache,"will have a different cache from another moduels.makeRequire().cache" )
+ test.notStrictEqual(require3.cache,require2.cache
+ ,"will have a different cache from another moduels.makeRequire().cache" )
- test.strictEqual(modules2.moduleCache,cache,"modules.useCache(X).moduleCache === X" )
- test.strictEqual(require3.cache,cache,"modules.useCache(X).makeRequire().cache === X" )
+ test.strictEqual(modules2.moduleCache,cache
+ ,"modules.useCache(X).moduleCache === X" )
+ test.strictEqual(require3.cache,cache
+ ,"modules.useCache(X).makeRequire().cache === X" )
//reload same twice my useing a different cache.
var cache1 = {}
, cache2 = {}
- , a1 = modules.useCache(cache1).makeRequire(module)('./.examples/a')
- , a2 = modules.useCache(cache2).makeRequire(module)('./.examples/a')
+ , a1 = modules.useCache(cache1)
+ .makeRequire(module)('./.examples/a')
+ , a2 = modules.useCache(cache2)
+ .makeRequire(module)('./.examples/a')
//modules
- test.equal(cache1[require.resolve('./.examples/a')].exports,a1,"should load module into right cache")
- test.equal(cache2[require.resolve('./.examples/a')].exports,a2,"should load module into right cache 2")
+ test.equal(cache1[require.resolve('./.examples/a')].exports,a1
+ , "should load module into right cache")
+ test.equal(cache2[require.resolve('./.examples/a')].exports,a2
+ , "should load module into right cache 2")
- test.finish();
+ test.finish()
}
exports ['modules should load children into the same cache'] = function (test){
@@ -178,3 +218,29 @@ exports ['modules should load children into the same cache'] = function (test){
test.finish()
}
+exports ['modules recreate thier "globals" for each cache'] = function (test){
+ var o = {}
+ , require2 = modules.useCache({}).makeRequire(module)
+ o.require = require('./.examples/one_random')
+ o.require2 = require2('./.examples/one_random')
+
+ test.ok(o.require.oneRandom)
+ test.ok(o.require2.oneRandom)
+ test.notEqual(o.require.oneRandom,o.require2.oneRandom)
+
+ test.finish();
+}
+exports ['modules can load native modules'] = function (test){
+ var o = {}
+ , require2 = modules.useCache({}).makeRequire(module)
+ fs = require('fs')
+ http = require2('http')
+
+/* test.ok(o.require.oneRandom)
+ test.ok(o.require2.oneRandom)
+ test.notEqual(o.require.oneRandom,o.require2.oneRandom)
+ */
+
+ test.finish()
+}
+
View
265 test/modules.wrapRequire.asynct.js
@@ -0,0 +1,265 @@
+//modules.wrapRequire.asynct
+/*
+TEST PLANS:
+
+ applications of this crazy module:
+ 1. reroute resolve, so that it loads a different module. --done at one level.
+ 2. return before calling loadModule, i.e. return a mock instead.
+ 3. modify module loaded.
+ i.e. wrap it and record what is called.
+ or wrap all db queries in a transaction and revert it after the test.
+ 4. change the makeRequire method for children...
+
+ i've got it doing the things i want now, but it's messy. next is refactor to make this easier.
+
+ 1. resolve. make resolve call a function 'resolveId' which calls resolveModule and returns [id,filename]
+ 2. be able to wrap any method is before, after and around methods.
+
+ then use syntax like
+
+ before: possibly change arguments passed to function. called with (args)
+ after: possibly change return value passed to function, called with (func, args)
+ around: all of the above, and possibly call a different function. called with return value
+
+ is before called before around? or when around calls func? probably doesn't
+ matter cos if your using both at the same time your probably trying to be too
+
+ {
+ around: function (oldFunc,path) { returns something different, or calls oldFunc}
+ resolve: {before: function (){}
+ }
+
+ maybe I'm being too clever...
+
+ prehaps important methods are just:
+ require, resolveIdFilename, and wrapRequire
+
+ instead of calling wrapRequire after it's setup require & properties it passes
+ the functions and then tidies it up.
+
+*/
+
+var modules = require('remap/modules')
+ , require2 = modules.makeRequire(module)
+ , resolve = require('remap/resolve')
+ , inspect = require('util').inspect
+
+function looksLikeRequire(test,r){
+ var types =
+ { resolve: 'function'
+ , paths: 'object'
+ , extensions: 'object'
+ , registerExtension: 'function'
+ , cache: 'object'
+ , main: 'object'
+ }
+
+ for (i in types){
+ test.equal(typeof r[i], types[i], "typeof :'" + r + '.' + i + ' should be: ' + types[i] + ', but was: ' + typeof r[i])
+ }
+}
+
+
+exports ['can change the require method for child modules'] = function (test){
+ var a = modules.loadModule('./.examples/a',module).exports
+ , a1 = require2('./.examples/a')
+ , inside = null
+ , a2 = modules.loadModule('./.examples/for_modules.asynct',module,wrapRequire).exports
+
+ test.strictEqual(a,a1
+ , "modules.loadModule(X,module) will return the same as module.makeRequire(module).require(X)")
+
+ test.strictEqual(inside.exports,a2)
+ test.finish()
+
+ function wrapRequire (r){
+ looksLikeRequire(test,r)
+
+ inside = this
+ return r
+ }
+}
+
+exports ['can change which module is loaded by redefining resolve'] = function (test){
+ var cache = {}
+ , __modules = modules.useCache(cache)
+// , a = modules.loadModule('./.examples/a',module,wrapRequire).exports
+ , a1 = require('./.examples/a')
+ , newResolveCalled = false
+ , __require = wrapRequire(__modules.makeRequire(module))
+ , a2 = __require('./.examples/a')
+ /*
+
+ the regular require load ./.examples/a which will .a() -> "A is for Apple"
+ but the new one will load a2 instead.
+
+ this doesn't say anything about what happens to require on submodules.
+ if I set module.wrapRequire = wrapRequire
+ it change, but break, because
+
+ refactor this to use a different function to resolve, which returns [id,filename]
+ and have require call it.
+ */
+ test.ok(newResolveCalled,"require.resolve should be called when require is called")
+
+ test.equal(a1.a(),"A is for Apple")
+ test.equal(a2.a(),"A is for Aardvark")
+
+ test.finish()
+
+ function wrapRequire (_require){
+
+ _require.resolve = newResolve
+
+ return _require
+
+ function newResolve (id){
+ newResolveCalled = true;
+ var remap =
+ { './.examples/a': './.examples/a2'
+ , './.examples/b': './.examples/c'
+ }
+ console.log('remap :' + id + " -> " + remap[id] || id)
+ return resolve.resolveModuleFilename(remap[id] || id, module)[1]
+ }
+ }
+}
+
+exports ['can return a mock in the place of a module'] = function (test){
+
+ var cache = {}
+ , __modules = modules.useCache(cache)
+ , newRequireCalled = false
+ , mockA =
+ { a: function (){return "A is for Airplane"}}
+ , __require = wrapRequire(__modules.makeRequire(module))
+ , a = __require('./.examples/a')
+ , a2 = __require('./.examples/a.js')
+ test.ok(newRequireCalled,"require.resolve should be called when require is called")
+
+ test.equal(a.a(),"A is for Airplane")
+ test.strictEqual(a,a2)
+ test.strictEqual(a,mockA)
+
+ test.finish();
+ /*
+ since this method still uses the old require
+ then inside the required module it will work like normal.
+ */
+ function wrapRequire(_require){
+
+ for (method in _require){
+ newRequire[method] = _require[method]
+ }
+
+ return newRequire
+
+ function newRequire(path){
+ newRequireCalled = true
+ if (/a(\.js)?$/.test(path)){
+ return mockA
+ } else {
+ return _require(path)
+ }
+ }
+ }
+}
+
+exports ['can wrap a module in something which modifies its behaviour'] = function (test){
+ var cache = {}
+ , __modules = modules.useCache(cache)
+ , wrapperListenerCalled = false
+ , __require = wrapRequire(__modules.makeRequire(module))
+ , a = __require('./.examples/a')
+// test.ok(newRequireCalled,"require.resolve should be called when require is called")
+ , expected = [['a',{},'A is for Apple']]
+
+ test.equal(a.a(),'A is for Apple')
+// test.equal(a.a(),'A is for Apple')
+
+ test.deepEqual([],expected)
+ test.finish()
+
+ function listener(method,args,returned){
+ var c = expected.shift()
+ test.equal(method,c[0])
+ //test.equal(args,c[1]) ... arguments is not an Array type unfortunately...
+ test.equal(returned,c[2])
+ wrapperListenerCalled = true
+ }
+
+ function wrapRequire(_require){
+
+ for (method in _require){
+ newRequire[method] = _require[method]
+ }
+
+ return newRequire
+
+ function newRequire (path){
+ var m = _require(path)
+ , n = {}
+ for (i in m){
+ if (typeof m[i] === 'function') {
+
+ n[i] = scope(m,i)
+ function scope (m,i) {
+ return function (){
+ var returned = m[i].apply(m,arguments)//better way to handle scope?
+// var returned = m[i]()
+ listener(i,arguments,returned)
+ return returned
+ }
+ }
+ } else {
+ n[i] = m[i]
+ }
+ }
+ return n
+ }
+ }
+}
+
+exports ['replace require for a child module'] = function (test){
+ /*
+ make a
+ a require that loads b,
+ and then triggers a callback when b requires c.
+ */
+
+ var cache = {}
+ , __modules = modules.useCache(cache)
+ , wrapperListenerCalled = false
+ , expected = ['./.examples/a','./.examples/b','./c']
+
+ var __require = wrapRequire(__modules.makeRequire(module),module)
+ , a = __require('./.examples/a')
+ , b = __require('./.examples/b')
+
+ test.ok(wrapperListenerCalled)
+ test.deepEqual(expected,[])
+ test.finish()
+
+ function listener(path){
+ wrapperListenerCalled = true
+ var exp = expected.shift()
+ test.equal(path,exp)
+ }
+
+ function wrapRequire (_require,parent){//pass the module into wrap require? then i wouldn't need to worry about this...
+ for (method in _require){
+ newRequire[method] = _require[method]
+ }
+ return newRequire
+
+ function newRequire(path){
+ //test.strictEqual(module,this)
+ var id = resolve.resolveModuleId(path,parent)
+ , filename = newRequire.resolve(path)
+ console.log("load:(" + parent.id + ").require(" + path + ")")
+ listener(path)
+ return modules.loadResolvedModule (id,filename,parent,wrapRequire).exports
+ }
+ }
+
+}
View
16 test/remap.asynct.js
@@ -5,8 +5,10 @@ exports['Change what require will resolve'] = function(test){
var remap = remapper()
test.ok(remap.resolve,'remap has resolve function')
- test.equal(require.resolve('./.examples/a'),__dirname + '/' +'.examples/a.js')
- test.equal(remap.resolve('./.examples/a'),__dirname + '/' + '.examples/a.js')
+ test.equal(require.resolve('./.examples/a')
+ , __dirname + '/' +'.examples/a.js')
+ test.equal(remap.resolve('./.examples/a')
+ , __dirname + '/' + '.examples/a.js')
remap.remap({'./.examples/a':'./.examples/a2'}) //tell remap to use a different module.
@@ -21,7 +23,8 @@ exports['load two different modules through one name by remapping'] = function (
test.equal(remap.resolve('./.examples/a'),__dirname + '/' + '.examples/a.js')
a1 = remap('./.examples/a')
test.equal(a1.a(),'A is for Apple');
- remap.remap({'./.examples/a':'./.examples/a2'}) //tell remap to use a different module.
+ remap.remap({'./.examples/a':'./.examples/a2'})
+ //tell remap to use a different module.
a2 = remap('./.examples/a')
test.equal(a2.a(),'A is for Aardvark');
@@ -45,3 +48,10 @@ specify a regular expression, or some sort of wild card to you can redirect a se
remap to git repositories.
*/
+
+exports ['provide a new require for submodules'] = function (test){
+ test.ok(false,"TEST NOT YET IMPLEMENTED")
+ test.finish();
+
+}
+
View
45 test/resolve.asynct.js
@@ -0,0 +1,45 @@
+
+var resolve = require('remap/resolve');
+
+exports ['resolve.resolveModuleFilename gets the filename and the id of a request'] = function (test){
+
+ var resolved = {}
+
+ resolved.a = resolve.resolveModuleFilename('./.examples/a', module)
+ resolved.remap_a = resolve.resolveModuleFilename('remap/test/.examples/a', module)
+ resolved.remap = resolve.resolveModuleFilename('remap', module)
+ console.log(resolved)
+
+ test.finish()
+}
+
+
+exports ['resolve.resolveModuleLookupPaths gets the id and paths of a request'] = function (test){
+
+ var resolved = {}
+
+ resolved.a = resolve.resolveModuleLookupPaths('./.examples/a', module)
+ resolved.remap_a = resolve.resolveModuleLookupPaths('remap/test/.examples/a', module)
+ resolved.remap = resolve.resolveModuleLookupPaths('remap', module)
+ console.log(resolved)
+
+ test.finish()
+}
+
+exports ['resolve.resolveModuleId gets the id of request'] = function (test){
+
+ checkResolvedId('./.examples/a')
+ checkResolvedId('remap/test/.examples/a')
+ checkResolvedId('remap')
+ checkResolvedId('fs')
+ checkResolvedId(require.resolve('./.examples/a'))//will generate a absolute filename,
+
+ function checkResolvedId(request){
+ var resolved = resolve.resolveModuleFilename(request, module)
+ , id = resolve.resolveModuleId(request,module)
+
+ test.equal(id,resolved[0])
+ }
+
+ test.finish()
+}

0 comments on commit 55e3c09

Please sign in to comment.