Make boot() return (optional) initialGestalts instead of having a separate argument to spawn(). Fixes failing test case for initial actor route signalling.
This commit is contained in:
parent
85c6c228a3
commit
5621685052
|
@ -76,7 +76,7 @@ $(document).ready(function () {
|
|||
// Monitor connection, notifying connectivity changes
|
||||
state: "crashed", // start with this to avoid spurious initial message print
|
||||
boot: function () {
|
||||
World.updateRoutes([sub(["broker_state", __], 0, 1)]);
|
||||
return [sub(["broker_state", __], 0, 1)];
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "routes") {
|
||||
|
@ -94,7 +94,7 @@ $(document).ready(function () {
|
|||
World.spawn({
|
||||
// Actual chat functionality
|
||||
boot: function () {
|
||||
World.updateRoutes(this.subscriptions());
|
||||
return this.subscriptions();
|
||||
},
|
||||
nym: function () { return $("#nym").val(); },
|
||||
currentStatus: function () { return $("#status").val(); },
|
||||
|
|
|
@ -13,15 +13,18 @@ $(document).ready(function () {
|
|||
Minimart.RoutingTableWidget.spawnRoutingTableWidget("#spy-holder", "spy");
|
||||
|
||||
World.spawn({
|
||||
boot: function () {
|
||||
return [pub(["DOM", "#clicker-holder", "clicker",
|
||||
["button", ["span", [["style", "font-style: italic"]], "Click me!"]]]),
|
||||
pub("bump_count"),
|
||||
sub(["jQuery", "button.clicker", "click", __])];
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "message" && e.message[0] === "jQuery") {
|
||||
World.send("bump_count");
|
||||
}
|
||||
}
|
||||
}, [pub(["DOM", "#clicker-holder", "clicker",
|
||||
["button", ["span", [["style", "font-style: italic"]], "Click me!"]]]),
|
||||
pub("bump_count"),
|
||||
sub(["jQuery", "button.clicker", "click", __])]);
|
||||
});
|
||||
|
||||
World.spawn({
|
||||
counter: 0,
|
||||
|
|
|
@ -29,6 +29,13 @@ $(document).ready(function () {
|
|||
Minimart.RoutingTableWidget.spawnRoutingTableWidget("#spy-holder", "spy"); // local
|
||||
|
||||
World.spawn({
|
||||
boot: function () {
|
||||
return [pub(domWrap("#clicker-holder", localId + "-clicker",
|
||||
["button", ["span", [["style", "font-style: italic"]],
|
||||
"Click me! (" + localId + ")"]])),
|
||||
pub("bump_count"),
|
||||
sub(jQueryWrap("button."+localId+"-clicker", "click", __))];
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
console.log(JSON.stringify(e));
|
||||
if (e.type === "message"
|
||||
|
@ -40,11 +47,7 @@ $(document).ready(function () {
|
|||
World.send("bump_count");
|
||||
}
|
||||
}
|
||||
}, [pub(domWrap("#clicker-holder", localId + "-clicker",
|
||||
["button", ["span", [["style", "font-style: italic"]],
|
||||
"Click me! (" + localId + ")"]])),
|
||||
pub("bump_count"),
|
||||
sub(jQueryWrap("button."+localId+"-clicker", "click", __))]);
|
||||
});
|
||||
|
||||
World.spawn({
|
||||
counter: 0,
|
||||
|
|
|
@ -12,6 +12,9 @@ $(document).ready(function () {
|
|||
|
||||
World.spawn({
|
||||
name: 'GestaltDisplay',
|
||||
boot: function () {
|
||||
return [sub(__, 0, 10), pub(__, 0, 10)];
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "routes") {
|
||||
var gd = document.getElementById('gestalt-display');
|
||||
|
@ -21,7 +24,7 @@ $(document).ready(function () {
|
|||
gd.appendChild(t);
|
||||
}
|
||||
}
|
||||
}, [sub(__, 0, 10), pub(__, 0, 10)]);
|
||||
});
|
||||
|
||||
World.spawn(new Actor(function () {
|
||||
this.counter = 0;
|
||||
|
|
14
src/actor.js
14
src/actor.js
|
@ -13,8 +13,9 @@ function Actor(bootfn) {
|
|||
try {
|
||||
Actor._chunks = [];
|
||||
bootfn.call(this);
|
||||
finalizeActor(this, Actor._chunks);
|
||||
var initialGestalt = finalizeActor(this, Actor._chunks);
|
||||
Actor._chunks = oldChunks;
|
||||
return [initialGestalt];
|
||||
} catch (e) {
|
||||
Actor._chunks = oldChunks;
|
||||
throw e;
|
||||
|
@ -123,7 +124,7 @@ function finalizeActor(behavior, chunks) {
|
|||
var compiledProjections = {};
|
||||
var previousObjs = {};
|
||||
|
||||
behavior.updateRoutes = function () {
|
||||
behavior._computeRoutes = function () {
|
||||
var newRoutes = Route.emptyGestalt;
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
var chunk = chunks[i];
|
||||
|
@ -159,7 +160,11 @@ function finalizeActor(behavior, chunks) {
|
|||
}
|
||||
}
|
||||
}
|
||||
World.updateRoutes([newRoutes]);
|
||||
return newRoutes;
|
||||
};
|
||||
|
||||
behavior.updateRoutes = function () {
|
||||
World.updateRoutes([this._computeRoutes()]);
|
||||
};
|
||||
|
||||
behavior.handleEvent = function (e) {
|
||||
|
@ -254,7 +259,8 @@ function finalizeActor(behavior, chunks) {
|
|||
if (chunk.options.removed) { behavior[chunk.options.removed] = []; }
|
||||
}
|
||||
}
|
||||
behavior.updateRoutes();
|
||||
|
||||
return behavior._computeRoutes();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -17,9 +17,7 @@ function spawnDOMDriver(domWrapFunction, jQueryWrapFunction) {
|
|||
fragmentClass,
|
||||
fragmentSpec,
|
||||
domWrapFunction,
|
||||
jQueryWrapFunction),
|
||||
[sub(domWrapFunction(selector, fragmentClass, fragmentSpec)),
|
||||
sub(domWrapFunction(selector, fragmentClass, fragmentSpec), 0, 1)]);
|
||||
jQueryWrapFunction));
|
||||
};
|
||||
World.spawn(d);
|
||||
}
|
||||
|
@ -40,12 +38,14 @@ function DOMFragment(selector, fragmentClass, fragmentSpec, domWrapFunction, jQu
|
|||
DOMFragment.prototype.boot = function () {
|
||||
var self = this;
|
||||
var monitoring =
|
||||
sub(this.domWrapFunction(self.selector, self.fragmentClass, self.fragmentSpec), 1, 2);
|
||||
sub(self.domWrapFunction(self.selector, self.fragmentClass, self.fragmentSpec), 1, 2);
|
||||
|
||||
World.spawn(new World(function () {
|
||||
Minimart.JQuery.spawnJQueryDriver(self.selector+" > ."+self.fragmentClass,
|
||||
1,
|
||||
self.jQueryWrapFunction);
|
||||
World.spawn({
|
||||
boot: function () { return [monitoring] },
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "routes") {
|
||||
var level = e.gestalt.getLevel(1, 0); // find participant peers
|
||||
|
@ -54,8 +54,11 @@ DOMFragment.prototype.boot = function () {
|
|||
}
|
||||
}
|
||||
}
|
||||
}, [monitoring]);
|
||||
});
|
||||
}));
|
||||
|
||||
return [sub(self.domWrapFunction(self.selector, self.fragmentClass, self.fragmentSpec)),
|
||||
sub(self.domWrapFunction(self.selector, self.fragmentClass, self.fragmentSpec), 0, 1)]
|
||||
};
|
||||
|
||||
DOMFragment.prototype.handleEvent = function (e) {
|
||||
|
|
|
@ -18,9 +18,7 @@ function spawnJQueryDriver(baseSelector, metaLevel, wrapFunction) {
|
|||
selector,
|
||||
eventName,
|
||||
metaLevel,
|
||||
wrapFunction),
|
||||
[pub(wrapFunction(selector, eventName, __), metaLevel),
|
||||
pub(wrapFunction(selector, eventName, __), metaLevel, 1)]);
|
||||
wrapFunction));
|
||||
};
|
||||
World.spawn(d);
|
||||
}
|
||||
|
@ -47,6 +45,11 @@ function JQueryEventRouter(baseSelector, selector, eventName, metaLevel, wrapFun
|
|||
this.handler);
|
||||
}
|
||||
|
||||
JQueryEventRouter.prototype.boot = function () {
|
||||
return [pub(this.wrapFunction(this.selector, this.eventName, __), this.metaLevel),
|
||||
pub(this.wrapFunction(this.selector, this.eventName, __), this.metaLevel, 1)];
|
||||
};
|
||||
|
||||
JQueryEventRouter.prototype.handleEvent = function (e) {
|
||||
if (e.type === "routes" && e.gestalt.isEmpty()) {
|
||||
this.computeNodes().off(this.eventName, this.handler);
|
||||
|
|
|
@ -19,10 +19,8 @@ function pub(pattern, metaLevel, level) {
|
|||
return Route.simpleGestalt(true, pattern, metaLevel, level);
|
||||
}
|
||||
|
||||
function spawn(behavior, initialGestalts) {
|
||||
return { type: "spawn",
|
||||
behavior: behavior,
|
||||
initialGestalt: Route.gestaltUnion(initialGestalts || []) };
|
||||
function spawn(behavior) {
|
||||
return { type: "spawn", behavior: behavior };
|
||||
}
|
||||
|
||||
function updateRoutes(gestalts) {
|
||||
|
@ -85,8 +83,8 @@ World.updateRoutes = function (gestalts) {
|
|||
World.current().enqueueAction(World.activePid(), updateRoutes(gestalts));
|
||||
};
|
||||
|
||||
World.spawn = function (behavior, initialGestalts) {
|
||||
World.current().enqueueAction(World.activePid(), spawn(behavior, initialGestalts));
|
||||
World.spawn = function (behavior) {
|
||||
World.current().enqueueAction(World.activePid(), spawn(behavior));
|
||||
};
|
||||
|
||||
World.exit = function (exn) {
|
||||
|
@ -226,13 +224,18 @@ World.prototype.performAction = function (pid, action) {
|
|||
switch (action.type) {
|
||||
case "spawn":
|
||||
var pid = World.nextPid++;
|
||||
var newGestalt = action.initialGestalt.label(pid);
|
||||
this.processTable[pid] = { gestalt: newGestalt, behavior: action.behavior };
|
||||
if (action.behavior.boot) {
|
||||
this.asChild(pid, function () { action.behavior.boot() });
|
||||
var entry = { gestalt: Route.emptyGestalt, behavior: action.behavior };
|
||||
this.processTable[pid] = entry;
|
||||
if (entry.behavior.boot) {
|
||||
var initialGestalts = this.asChild(pid, function () { return entry.behavior.boot() });
|
||||
if (initialGestalts) {
|
||||
entry.gestalt = Route.gestaltUnion(initialGestalts).label(pid);
|
||||
}
|
||||
this.markPidRunnable(pid);
|
||||
}
|
||||
this.applyAndIssueRoutingUpdate(Route.emptyGestalt, newGestalt, pid);
|
||||
if (!Route.emptyGestalt.equals(entry.gestalt)) {
|
||||
this.applyAndIssueRoutingUpdate(Route.emptyGestalt, entry.gestalt, pid);
|
||||
}
|
||||
break;
|
||||
case "routes":
|
||||
if (pid in this.processTable) {
|
||||
|
@ -315,6 +318,11 @@ World.prototype.dispatchEvent = function (e) {
|
|||
}
|
||||
};
|
||||
|
||||
World.prototype.boot = function () {
|
||||
// Needed in order for the new World to be marked as "runnable", so
|
||||
// its initial actions get performed.
|
||||
};
|
||||
|
||||
World.prototype.handleEvent = function (e) {
|
||||
switch (e.type) {
|
||||
case "routes":
|
||||
|
@ -436,8 +444,8 @@ DemandMatcher.prototype.debugState = function () {
|
|||
|
||||
DemandMatcher.prototype.boot = function () {
|
||||
var observerLevel = 1 + Math.max(this.demandLevel, this.supplyLevel);
|
||||
World.updateRoutes([sub(this.demandPattern, this.metaLevel, observerLevel),
|
||||
pub(this.supplyPattern, this.metaLevel, observerLevel)]);
|
||||
return [sub(this.demandPattern, this.metaLevel, observerLevel),
|
||||
pub(this.supplyPattern, this.metaLevel, observerLevel)];
|
||||
};
|
||||
|
||||
DemandMatcher.prototype.handleEvent = function (e) {
|
||||
|
|
|
@ -12,7 +12,7 @@ function Spy(label, useJson, observationLevel) {
|
|||
}
|
||||
|
||||
Spy.prototype.boot = function () {
|
||||
World.updateRoutes([sub(__, 0, this.observationLevel), pub(__, 0, this.observationLevel)]);
|
||||
return [sub(__, 0, this.observationLevel), pub(__, 0, this.observationLevel)];
|
||||
};
|
||||
|
||||
Spy.prototype.handleEvent = function (e) {
|
||||
|
|
|
@ -17,8 +17,8 @@ function WakeDetector(period) {
|
|||
|
||||
WakeDetector.prototype.boot = function () {
|
||||
var self = this;
|
||||
World.updateRoutes([pub(this.message)]);
|
||||
this.timerId = setInterval(World.wrap(function () { self.trigger(); }), this.period);
|
||||
return [pub(this.message)];
|
||||
};
|
||||
|
||||
WakeDetector.prototype.handleEvent = function (e) {};
|
||||
|
|
|
@ -47,10 +47,11 @@ describe("configurationTrace", function() {
|
|||
it("should yield an appropriate trace", function () {
|
||||
checkTrace(function (trace) {
|
||||
World.spawn({
|
||||
boot: function () { return [sub(__)] },
|
||||
handleEvent: function (e) {
|
||||
trace(e);
|
||||
}
|
||||
}, [sub(__)]);
|
||||
});
|
||||
World.send(123);
|
||||
World.send(234);
|
||||
}, [Minimart.updateRoutes([]),
|
||||
|
@ -64,9 +65,15 @@ describe("nonempty initial routes", function () {
|
|||
it("should be immediately signalled to the process", function () {
|
||||
// Specifically, no Minimart.updateRoutes([]) first.
|
||||
checkTrace(function (trace) {
|
||||
World.spawn({ handleEvent: function (e) {
|
||||
World.spawn({ handleEvent: trace }, [sub(["A", __], 0, 1)])
|
||||
}}, [pub(["A", __])]);
|
||||
World.spawn({
|
||||
boot: function () { return [pub(["A", __])] },
|
||||
handleEvent: function (e) {
|
||||
World.spawn({
|
||||
boot: function () { return [sub(["A", __], 0, 1)] },
|
||||
handleEvent: trace
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [Minimart.updateRoutes([pub(["A", __]).label(1)])]);
|
||||
});
|
||||
});
|
||||
|
@ -74,16 +81,19 @@ describe("nonempty initial routes", function () {
|
|||
describe("actor with nonempty initial routes", function () {
|
||||
it("shouldn't see initial empty conversational context", function () {
|
||||
checkTrace(function (trace) {
|
||||
World.spawn({ handleEvent: function (e) {
|
||||
World.spawn(new Actor(function () {
|
||||
Actor.observeAdvertisers(
|
||||
function () { return ["A", __] },
|
||||
{ presence: "isPresent" },
|
||||
function () {
|
||||
trace(["isPresent", this.isPresent]);
|
||||
});
|
||||
}));
|
||||
}}, [pub(["A", __])]);
|
||||
World.spawn({
|
||||
boot: function () { return [pub(["A", __])] },
|
||||
handleEvent: function (e) {
|
||||
World.spawn(new Actor(function () {
|
||||
Actor.observeAdvertisers(
|
||||
function () { return ["A", __] },
|
||||
{ presence: "isPresent" },
|
||||
function () {
|
||||
trace(["isPresent", this.isPresent]);
|
||||
});
|
||||
}));
|
||||
}
|
||||
});
|
||||
}, [["isPresent", true]]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -297,6 +297,13 @@ describe("matcher equality", function () {
|
|||
});
|
||||
|
||||
describe("gestalt equality", function () {
|
||||
it("should distinguish emptyGestalt reliably", function () {
|
||||
expect(r.simpleGestalt(false, r.__, 0, 10)
|
||||
.union(r.simpleGestalt(true, r.__, 0, 10))
|
||||
.equals(r.emptyGestalt))
|
||||
.to.be(false);
|
||||
});
|
||||
|
||||
it("should not rely on object identity", function () {
|
||||
expect(r.simpleGestalt(false, "A", 0, 0).union(r.simpleGestalt(true, "B", 0, 0))
|
||||
.equals(r.simpleGestalt(false, "A", 0, 0).union(r.simpleGestalt(true, "B", 0, 0))))
|
||||
|
|
Loading…
Reference in New Issue