actor.js (WIP)

This commit is contained in:
Tony Garnock-Jones 2014-07-24 21:08:57 -07:00
parent 0b361137a2
commit fba2ee91a8
2 changed files with 117 additions and 0 deletions

116
src/actor.js Normal file
View File

@ -0,0 +1,116 @@
var Reflect = require("./reflect.js");
Actor._chunks = null;
function Actor(ctor) {
var oldChunks = Actor._chunks;
try {
Actor._chunks = [];
var behavior = new ctor();
return finalizeActor(behavior, Actor._chunks);
} catch (e) {
Actor._chunks = oldChunks;
throw e;
}
}
function checkChunks(type) {
if (!Actor._chunks) {
throw new Error("Call to Actor."+type+" outside of Actor constructor");
}
}
function extractChunk(type, defaultOptions, args) {
var options = null;
var handler = null;
for (var i = 1; i < args.length; i++) { // NB: skip the first arg - it's rawProjection
if (typeof args[i] === 'function') {
if (handler !== null) { throw new Error("Too many handler functions in Actor."+type); }
handler = args[i];
} else if (typeof args[i] === 'object') {
if (options !== null) { throw new Error("Too many options arguments in Actor."+type); }
options = args[i];
} else {
throw new Error("Unrecognised argument in Actor."+type);
}
}
options = options || {};
for (var k in options) {
if (!(k in defaultOptions)) {
throw new Error("Unrecognised option '"+k+"' in Actor."+type);
}
}
for (var k in defaultOptions) {
if (!(k in options)) {
options[k] = defaultOptions[k];
}
}
return {
type: type,
rawProjection: args[0],
options: options,
handler: handler
};
}
function chunkExtractor(type, defaultOptions) {
return function (/* ... */) {
checkChunks(type);
Actor._chunks.push(extractChunk(type,
defaultOptions,
Array.prototype.slice.call(arguments)));
};
}
var participatorDefaults = {
metaLevel: 0,
when: function () { return true; }
};
var observerDefaults = {
metaLevel: 0,
level: 0,
when: function () { return true; },
presence: null,
name: null,
set: null,
added: null,
removed: null
};
Actor.advertise = chunkExtractor('advertise', participatorDefaults);
Actor.subscribe = chunkExtractor('subscribe', participatorDefaults);
Actor.observeAdvertisers = chunkExtractor('observeAdvertisers', observerDefaults);
Actor.observeSubscribers = chunkExtractor('observeSubscribers', observerDefaults);
Actor.observeGestalt = function (gestaltFn, eventHandlerFn) {
checkChunks('observeGestalt');
Actor._chunks.push({
type: 'observeGestalt',
gestaltFn: gestaltFn,
eventHandlerFn: eventHandlerFn
});
};
function finalizeActor(behavior, chunks) {
throw new Error("notYetImplemented"); // HERE
}
function kwApply(f, thisArg, args) {
var formals = Reflect.formalParameters(f);
var actuals = []
for (var i = 0; i < formals.length; i++) {
var formal = formals[i];
if (!(formal in args)) {
throw new Error("Function parameter "+formal+" not present in args");
}
actuals.push(args[formal]);
}
return f.apply(thisArg, actuals);
}
///////////////////////////////////////////////////////////////////////////
module.exports.Actor = Actor;
module.exports.kwApply = kwApply;

View File

@ -8,3 +8,4 @@ module.exports.Reflect = require("./reflect.js");
module.exports.Spy = require("./spy.js").Spy;
module.exports.WakeDetector = require("./wake-detector.js").WakeDetector;
module.exports.Actor = require("./actor.js").Actor;