Browse files

Formalize post-require-hook and change YUI load hook to match new sig…

…nature.
  • Loading branch information...
1 parent e2b707c commit 59d07a08aea19609ad3935f3883b8d9ae865fca0 @gotwarlost committed Jan 27, 2013
View
2 index.js
@@ -105,7 +105,7 @@ module.exports = {
*/
VERSION: meta.VERSION,
//undocumented
- _yuiLoadHook: require('./lib/util/yui-load-hook').getPostLoadHook,
+ _yuiLoadHook: require('./lib/util/yui-load-hook'),
//undocumented
TreeSummarizer: require('./lib/util/tree-summarizer'),
//undocumented
View
18 lib/command/common/run-with-cover.js
@@ -25,6 +25,7 @@ function usage(arg0, command) {
formatOption('-x <exclude-pattern> [-x <exclude-pattern>]', 'one or more fileset patterns e.g. "**/vendor/**"'),
formatOption('--[no-]default-excludes', 'apply default excludes [ **/node_modules/**, **/test/**, **/tests/** ], defaults to true'),
formatOption('--hook-run-in-context', 'hook vm.runInThisContext in addition to require (supports RequireJS), defaults to false'),
+ formatOption('--post-require-hook <file>', 'JS module that exports a function for post-require processing'),
formatOption('--report <report-type>', 'report type, one of html, lcov, lcovonly, none, defaults to lcov (= lcov.info + HTML)'),
formatOption('--dir <report-dir>', 'report directory, defaults to ./coverage'),
formatOption('--print <type>', 'type of report to print to console, one of summary (default), detail, both or none'),
@@ -45,7 +46,8 @@ function run(args, commandName, enableHooks, callback) {
'default-excludes': Boolean,
print: String,
'self-test': Boolean,
- 'hook-run-in-context': Boolean
+ 'hook-run-in-context': Boolean,
+ 'post-require-hook': path
},
opts = nopt(config, { v : '--verbose' }, args, 0),
cmdAndArgs = opts.argv.remain,
@@ -118,11 +120,19 @@ function run(args, commandName, enableHooks, callback) {
var coverageVar = '$$cov_' + new Date().getTime() + '$$',
instrumenter = new Instrumenter({ coverageVariable: coverageVar }),
transformer = instrumenter.instrumentSync.bind(instrumenter),
- hookOpts = { verbose: opts.verbose };
+ hookOpts = { verbose: opts.verbose },
+ postLoadHookFile;
- if (opts.yui) { //EXPERIMENTAL code: do not rely on this in anyway until the docs say it is allowed
- hookOpts.postLoadHook = require('../../util/yui-load-hook').getPostLoadHook(matchFn, transformer, opts.verbose);
+ if (opts['post-require-hook']) {
+ postLoadHookFile = path.resolve(opts['post-require-hook']);
+ } else if (opts.yui) { //EXPERIMENTAL code: do not rely on this in anyway until the docs say it is allowed
+ postLoadHookFile = path.resolve(__dirname, '../../util/yui-load-hook');
}
+ if (postLoadHookFile) {
+ if (opts.verbose) { console.log('Use post-load-hook: ' + postLoadHookFile); }
+ hookOpts.postLoadHook = require(postLoadHookFile)(matchFn, transformer, opts.verbose);
+ }
+
if (opts['self-test']) {
hook.unloadRequireCache(matchFn);
}
View
2 lib/hook.js
@@ -83,6 +83,8 @@ function unloadRequireCache(matcher) {
* from where the code was loaded. Should return the transformed code.
* @param options {Object} options Optional.
* @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called
+ * @param {Function} [options.postLoadHook] a function that is called with the name of the file being
+ * required. This is called after the require is processed irrespective of whether it was transformed.
*/
function hookRequire(matcher, transformer, options) {
options = options || {};
View
70 lib/util/yui-load-hook.js
@@ -8,44 +8,42 @@
var path = require('path'),
yuiRegexp = /yui-nodejs\.js$/;
-module.exports = {
- getPostLoadHook: function (matchFn, transformFn, verbose) {
- return function (file) {
- if (!file.match(yuiRegexp)) {
- return;
- }
- var YMain = require(file),
- YUI,
- loaderFn,
- origGet;
+module.exports = function (matchFn, transformFn, verbose) {
+ return function (file) {
+ if (!file.match(yuiRegexp)) {
+ return;
+ }
+ var YMain = require(file),
+ YUI,
+ loaderFn,
+ origGet;
- if (YMain.YUI) {
- YUI = YMain.YUI;
- loaderFn = YUI.Env && YUI.Env.mods && YUI.Env.mods['loader-base'] ? YUI.Env.mods['loader-base'].fn : null;
- if (!loaderFn) { return; }
- if (verbose) { console.log('Applying YUI load post-hook'); }
- YUI.Env.mods['loader-base'].fn = function (Y) {
- loaderFn.call(null, Y);
- origGet = Y.Get._exec;
- Y.Get._exec = function (data, url, cb) {
- if (matchFn(url) || matchFn(path.resolve(url))) { //allow for relative paths as well
- if (verbose) {
- console.log('Transforming [' + url + ']');
- }
- try {
- data = transformFn(data, url);
- } catch (ex) {
- console.error('Error transforming: ' + url + ' return original code');
- console.error(ex.message || ex);
- if (ex.stack) { console.error(ex.stack); }
- }
+ if (YMain.YUI) {
+ YUI = YMain.YUI;
+ loaderFn = YUI.Env && YUI.Env.mods && YUI.Env.mods['loader-base'] ? YUI.Env.mods['loader-base'].fn : null;
+ if (!loaderFn) { return; }
+ if (verbose) { console.log('Applying YUI load post-hook'); }
+ YUI.Env.mods['loader-base'].fn = function (Y) {
+ loaderFn.call(null, Y);
+ origGet = Y.Get._exec;
+ Y.Get._exec = function (data, url, cb) {
+ if (matchFn(url) || matchFn(path.resolve(url))) { //allow for relative paths as well
+ if (verbose) {
+ console.log('Transforming [' + url + ']');
}
- return origGet.call(Y, data, url, cb);
- };
- return Y;
+ try {
+ data = transformFn(data, url);
+ } catch (ex) {
+ console.error('Error transforming: ' + url + ' return original code');
+ console.error(ex.message || ex);
+ if (ex.stack) { console.error(ex.stack); }
+ }
+ }
+ return origGet.call(Y, data, url, cb);
};
- }
- };
- }
+ return Y;
+ };
+ }
+ };
};
View
11 test/cli/sample-project/node_modules/post-require/hook.js
@@ -0,0 +1,11 @@
+var path = require('path');
+module.exports = function (matchFn, transformFn, verbose) {
+ console.error('PRH: MatchFn was a ' + typeof matchFn);
+ console.error('PRH: TransformFn was a ' + typeof transformFn);
+ console.error('PRH: Verbose was ' + verbose);
+ return function (file) {
+ var base = path.basename(file);
+ console.error('PRH: Saw ' + base);
+ };
+};
+
View
14 test/cli/test-cover-command.js
@@ -125,5 +125,19 @@ module.exports = {
test.ok(filtered.length === Object.keys(coverage).length);
test.done();
});
+ },
+ "should apply post-require-hook correctly": function (test) {
+ helper.setOpts({ lazyHook : true });
+ run([ 'test/run.js', '-v', '-x', '**/foo.js', '--post-require-hook', 'node_modules/post-require/hook.js' ], function (results) {
+ test.ok(results.succeeded());
+ test.ok(results.grepError(/PRH: MatchFn was a function/));
+ test.ok(results.grepError(/PRH: TransformFn was a function/));
+ test.ok(results.grepError(/PRH: Verbose was true/));
+ //yes, post require hook must be called always even when a file is not covered
+ test.ok(results.grepError(/PRH: Saw foo\.js/));
+ //and, of course, for covered files as well
+ test.ok(results.grepError(/PRH: Saw bar\.js/));
+ test.done();
+ });
}
};

0 comments on commit 59d07a0

Please sign in to comment.