Skip to content

Commit

Permalink
Load scripts or modules.
Browse files Browse the repository at this point in the history
Load many scripts or modules, not just one.
  • Loading branch information
unscriptable committed Jul 9, 2013
1 parent d781d11 commit 1be8b64
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 59 deletions.
117 changes: 74 additions & 43 deletions init/LoaderImpl.js
Expand Up @@ -35,6 +35,7 @@

evalAsync: function (source, callback, errback) {
if (!callback) callback = noop;
if (!errback) errback = fail;
try {
callback(this.eval(source));
}
Expand All @@ -43,22 +44,74 @@
}
},

load: function (idOrArray, callback, errback) {
var pipeline, options, dfd, loader, withOptions, promisify;
load: function (ids, callback, errback) {
if (!errback) errback = fail; // propagate by default
return this.fulfillAsType(ids, 'script')
.then(spread(callback), errback);
},

"import": function (ids, callback, errback) {
if (!errback) errback = fail; // propagate by default
return this.fulfillAsType(ids, 'module')
.then(spread(callback), errback);
},

get: function (name) {
var module;
module = this.cache[String(name)];
// note: when all things in the cache are instanceof Module,
// this sniff will be safer
if (module && typeof module.execute == 'function') {
// run factory
var deps = [];
for (var i = 0; i < module.imports.length; i++) {
deps[i] = this.get(module.imports[i]);
}
this.cache[String(name)] = module
= module.execute.apply(null, deps);
}
return module;
},

has: function (name) {
return String(name) in this.cache;
},

set: function (name, thing) {
this.cache[String(name)] = ToModule(thing);
},

"delete": function (name) {
delete this.cache[String(name)];
},

fulfillAsType: function (ids, type) {
var promises = [], i;

if (Object.prototype.toString.call(ids) != '[object Array]') {
ids = [ids];
}

for (i = 0; i < ids.length; i++) {
promises.push(this.runPipeline(ids[i], { type: type }));
}
return all(promises);
},

runPipeline: function (id, options) {
var pipeline, loader, withOptions, promisify;

// ignoring arrays for now.... TODO: implement for array, too.
// TODO: pre-prepare pipeline instead of building it from scratch each time
// withOptions
// promisify

pipeline = this.pipeline;
options = {};
loader = this;
withOptions = this.withOptions;
promisify = this.promisify;

// start pipeline with id as input
return when(idOrArray)
return when(id)

// normalize name
.then(pipeline.normalize)
Expand Down Expand Up @@ -91,50 +144,19 @@
.then(withOptions(bind(this, 'processModule'), options))

// callback or handle errors and early aborts
.then(callback, function (reason) {
.then(null, function (reason) {
if (reason instanceof Module) {
callback(loader.get(options.normalized));
return loader.get(options.normalized);
}
else if (reason instanceof defer) {
reason.promise.then(callback, errback);
else if (promise.isDeferred(reason)) {
return reason;
}
else {
errback(reason);
throw reason;
}
});
},

"import": function () {},

get: function (name) {
var module;
module = this.cache[String(name)];
// note: when all things in the cache are instanceof Module,
// this sniff will be safer
if (module && typeof module.execute == 'function') {
// run factory
var deps = [];
for (var i = 0; i < module.imports.length; i++) {
deps[i] = this.get(module.imports[i]);
}
this.cache[String(name)] = module
= module.execute.apply(null, deps);
}
return module;
},

has: function (name) {
return String(name) in this.cache;
},

set: function (name, thing) {
this.cache[String(name)] = ToModule(thing);
},

"delete": function (name) {
delete this.cache[String(name)];
},

processNormalized: function (result, options) {
if (typeof result == 'object') {
options.normalized = result.normalized;
Expand All @@ -160,7 +182,8 @@

processImports: function (result, options) {
var imports, count, promises;
imports = result.imports;
// scripts don't return a result
imports = result ? result.imports : [];
count = 0;
promises = [];
while (count < imports.length) {
Expand All @@ -177,7 +200,7 @@
this.set(options.normalized, module);
// hackish way to ensure factory has run
module = this.get(options.normalized);
if (dfd instanceof defer) dfd.fulfill(module);
if (promise.isDeferred(dfd)) dfd.fulfill(module);
return module;
},

Expand Down Expand Up @@ -252,8 +275,16 @@
}
}

function spread (func) {
return function (params) {
return func.apply(null, params);
};
}

function noop () {}

function fail (ex) { throw ex; }

}(
typeof global == 'object' ? global : this.window || this.global || {},
function () { return (1, eval).call(arguments[1], arguments[0]); }
Expand Down
17 changes: 14 additions & 3 deletions init/Pipeline.js
@@ -1,4 +1,4 @@
(function (global, cjsmEval) {
(function (global, cjsmEval, globalEval) {


/***** imports *****/
Expand Down Expand Up @@ -66,7 +66,12 @@
}

function link (source, options) {
return parseCjsm(source, options);
if (options.type == 'script') {
return parseScript(source, options);
}
else {
return parseCjsm(source, options);
}
}

function isAbsUrl (url) {
Expand All @@ -80,6 +85,10 @@
+ '\n*/\n';
}

function parseScript (source, options) {
return void globalEval(source);
}

function parseCjsm (source, options) {
var mctx, currQuote, clean;

Expand Down Expand Up @@ -167,5 +176,7 @@

}(
typeof global != 'undefined' ? global : this.global || this.window,
function (require, exports, module, global) { eval(arguments[4]); }
// TODO: how do we inject these params and run in the context of `global`?
function (require, exports, module, global) { eval(arguments[4]); },
function () { (1, eval)(arguments[0]); }
));
4 changes: 2 additions & 2 deletions init/fetchText.js
Expand Up @@ -41,7 +41,7 @@
xhr.send(null);
}

function nodeFetch (url, callback, errback) {console.log('here', url);
function nodeFetch (url, callback, errback) {
fs.readFile(url, function (err) {
if (err) {
errback(err);
Expand All @@ -52,7 +52,7 @@
});
}

function cjsFetch (url, callback, errback) {console.log('here', url);
function cjsFetch (url, callback, errback) {
try {
callback(fs.read(url));
}
Expand Down
8 changes: 4 additions & 4 deletions load.js
Expand Up @@ -86,17 +86,17 @@
}

Loader.prototype = {
// TODO: use Object.defineProperties or a shim for it
// TODO: use Object.defineProperties or a sham for it
global: global,
strict: true,
evalAsync: function (src, callback, errback) {
return getImpl(this).evalAsync(src, callback, errback);
getImpl(this).evalAsync(src, callback, errback);
},
"import": function (idOrArray, callback, errback) {
return getImpl(this)['import'](idOrArray, callback, errback);
getImpl(this)['import'](idOrArray, callback, errback);
},
load: function (idOrArray, callback, errback) {
return getImpl(this).load(idOrArray, callback, errback);
getImpl(this).load(idOrArray, callback, errback);
},
eval: function (src) { return getImpl(this).eval(src); },
get: function (name) { return getImpl(this).get(name); },
Expand Down
4 changes: 2 additions & 2 deletions test/app/main.js
Expand Up @@ -5,9 +5,9 @@ var doc = global.document;
exports.init = doc ? insert : log;

function insert () {
doc.body.appendChild(doc.createElement('div')).innerHTML = 'it works!';
doc.body.appendChild(doc.createElement('div')).innerHTML = 'it works in a browser!';
}

function log () {
console.log('it works!');
console.log('it works in node/ringo!');
}
10 changes: 5 additions & 5 deletions test/run.js
@@ -1,7 +1,7 @@
// this is just a simple cjsm file
// this is just a global script file

module.exports = {};
console.log('running inside run.js');

console.log('running inside main.js');

require('app/main').init();
System.import('app/main', function (main) {
main.init();
});

0 comments on commit 1be8b64

Please sign in to comment.