Skip to content

Commit 2f1d1c0

Browse files
committed
proceed with implementation of dependency resolving
1 parent a86b767 commit 2f1d1c0

3 files changed

Lines changed: 146 additions & 45 deletions

File tree

lib/macro-manager.js

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,39 @@ function State(name, value) {
1414
this.name = name;
1515
this.value = value;
1616
this.providingMacro = null;
17+
this.toBeCalledOnRisingEdge = [];
18+
1719
this.setProvidingMacro = function (macro) {
1820
this.providingMacro = macro;
1921
};
22+
23+
this.registerWaitingMacro = function (waitingDoneCallback) {
24+
this.toBeCalledOnRisingEdge.push(waitingDoneCallback);
25+
};
26+
27+
this.notifyWaitingMacros = function () {
28+
var callback;
29+
while (this.toBeCalledOnRisingEdge.length > 0) {
30+
callback = this.toBeCalledOnRisingEdge.shift();
31+
callback();
32+
}
33+
};
34+
2035
this.ensureIsSet = function (done) {
2136
if (this.value === constants.STATE_NOT_SET) {
37+
this.value = constants.STATE_PENDING_SET;
38+
this.registerWaitingMacro(done);
39+
this.providingMacro.execute(
40+
function () {
41+
stateInstance.notifyWaitingMacros();
42+
}
43+
);
44+
} else if (this.value === constants.STATE_PENDING_SET) {
2245
this.registerWaitingMacro(done);
23-
this.providingMacro(function () {this.notifyWaitingMacros();});
24-
} else if (stateInstance.value === constants.STATE_PENDING_SET) {
25-
// warten
2646
} else {
2747
done();
2848
}
2949
};
30-
31-
this.notifyWaitingMacros = function () {
32-
33-
};
3450
}
3551

3652
function StateManager() {
@@ -55,6 +71,10 @@ function StateManager() {
5571
state.value = stateValue;
5672
};
5773

74+
this.getStateByName = function (name) {
75+
return this.stateByName[name];
76+
};
77+
5878
this.getStateSummary = function () {
5979
var summary = {};
6080
var stateName;
@@ -123,6 +143,15 @@ function registerState(stateName) {
123143
virtualStates.registerState(stateName);
124144
}
125145

146+
function registerStateProvider(stateName, macro) {
147+
virtualStates.registerStateProvider(stateName, macro);
148+
}
149+
150+
function requestStateIsSet(callback, stateName) {
151+
var state = virtualStates.getStateByName(stateName);
152+
state.ensureIsSet(callback);
153+
}
154+
126155
function setStateByName(stateName, newState) {
127156
virtualStates.setStateByName(stateName, newState);
128157
}
@@ -136,7 +165,9 @@ function getDeviceByName(deviceName) {
136165
}
137166

138167
manager = {
168+
registerStateProvider: registerStateProvider,
139169
registerState: registerState,
170+
requestStateIsSet: requestStateIsSet,
140171
setStateByName: setStateByName,
141172
getCatchAllDevice: getCatchAllDevice,
142173
getDeviceByName: getDeviceByName,

lib/macro.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ function Macro(config, macroManager) {
125125

126126
this.registerStates = function () {
127127
if (this.isProvidingState()) {
128-
macroManager.registerState(config.provides);
128+
macroManager.registerStateProvider(config.provides, this);
129129
}
130130
if (this.isRequiringState()) {
131131
macroManager.registerState(config.requires);
@@ -137,7 +137,11 @@ function Macro(config, macroManager) {
137137

138138
this.execute = function (done) {
139139
this.callersCallback = done;
140-
this.macroClosureChain();
140+
if (this.isRequiringState()) {
141+
macroManager.requestStateIsSet(this.macroClosureChain, config.requires);
142+
} else {
143+
this.macroClosureChain();
144+
}
141145
};
142146

143147
this.macroClosureChain = this.createClosureChain();

test/lib/macro-manager.js

Lines changed: 102 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,6 @@ var CONFIG_DELAYED_HELLO_WORLD = [{
2121
],
2222
}];
2323

24-
var CONFIG_HELLO_STATES = [{
25-
name: 'hello!',
26-
provides: 'hello',
27-
sequence: [
28-
['say', 'hello'],
29-
],
30-
}, {
31-
name: 'world!',
32-
requires: 'hello',
33-
sequence: [
34-
['say', 'world'],
35-
],
36-
}, {
37-
name: 'goodbye!',
38-
resets: 'hello',
39-
sequence: [
40-
['say', 'goodbye'],
41-
],
42-
}, {
43-
name: 'something',
44-
resets: 'world',
45-
sequence: [
46-
['say', 'goodbye'],
47-
],
48-
}];
49-
5024
var CONFIG_HELLO = [
5125
{
5226
name: 'hello',
@@ -350,6 +324,32 @@ describe('macros', function () {
350324
});
351325

352326
describe('state', function () {
327+
var CONFIG_STATES = [{
328+
name: 'hello!',
329+
provides: 'hello',
330+
sequence: [
331+
['say', 'hello'],
332+
],
333+
}, {
334+
name: 'world!',
335+
requires: 'hello',
336+
sequence: [
337+
['say', 'world'],
338+
],
339+
}, {
340+
name: 'goodbye!',
341+
resets: 'hello',
342+
sequence: [
343+
['say', 'goodbye'],
344+
],
345+
}, {
346+
name: 'something',
347+
resets: 'world',
348+
sequence: [
349+
['say', 'goodbye'],
350+
],
351+
}];
352+
353353
describe('set, reset and query', function () {
354354
beforeEach(function () {
355355
resetMockAndFixture();
@@ -361,27 +361,27 @@ describe('macros', function () {
361361
});
362362

363363
it('should deliver current states as key value map', function () {
364-
macros.init(CONFIG_HELLO_STATES);
364+
macros.init(CONFIG_STATES);
365365
assert.deepEqual(macros.getCurrentStates(), { hello: 'clear', world: 'clear' });
366366
});
367367

368368
it('should set state after execution', function () {
369-
macros.init(CONFIG_HELLO_STATES);
369+
macros.init(CONFIG_STATES);
370370
assert.deepEqual(macros.getCurrentStates(),
371371
{ hello: 'clear', world: 'clear' }, 'not called');
372-
macros.execute(CONFIG_HELLO_STATES[0].name);
372+
macros.execute(CONFIG_STATES[0].name);
373373
clock.tick(51);
374374
assert.deepEqual(macros.getCurrentStates(),
375375
{ hello: 'set', world: 'clear' }, 'macro called');
376376
});
377377

378378
it('should reset state after execution', function () {
379-
macros.init(CONFIG_HELLO_STATES);
380-
macros.execute(CONFIG_HELLO_STATES[0].name);
379+
macros.init(CONFIG_STATES);
380+
macros.execute(CONFIG_STATES[0].name);
381381
clock.tick(51);
382382
assert.deepEqual(macros.getCurrentStates(), { hello: 'set', world: 'clear' },
383383
'state set called');
384-
macros.execute(CONFIG_HELLO_STATES[2].name);
384+
macros.execute(CONFIG_STATES[2].name);
385385
clock.tick(51);
386386
assert.deepEqual(macros.getCurrentStates(), { hello: 'clear', world: 'clear' },
387387
'state reset called');
@@ -396,7 +396,31 @@ describe('macros', function () {
396396
});
397397
});
398398

399+
// TODO validation of providers, requesters, resetters and deniers:
400+
// providers and deniers need match!
401+
399402
describe('dependency call', function () {
403+
var CONFIG_MULTI_STATES = [{
404+
name: 'Lamp',
405+
provides: 'light',
406+
sequence: [
407+
['delay', '50'],
408+
['say', 'shiny'],
409+
],
410+
}, {
411+
name: 'he',
412+
requires: 'light',
413+
sequence: [
414+
['say', 'uh'],
415+
],
416+
}, {
417+
name: 'she',
418+
requires: 'light',
419+
sequence: [
420+
['say', 'ah'],
421+
],
422+
}];
423+
400424
beforeEach(function () {
401425
resetMockAndFixture();
402426
clock = sinon.useFakeTimers();
@@ -406,15 +430,57 @@ describe('macros', function () {
406430
clock.restore();
407431
});
408432

409-
it.skip('should call macro if state is requested', function () {
410-
macros.init(CONFIG_HELLO_STATES);
411-
macros.execute(CONFIG_HELLO_STATES[1].name);
433+
it('should call macro if state is requested', function () {
434+
macros.init(CONFIG_STATES);
435+
macros.execute(CONFIG_STATES[1].name);
412436
clock.tick(51);
413437
assert.deepEqual(deviceMock.operations,
414438
[['say', 'hello'], ['say', 'world']], 'calls are not done as expected');
415-
assert.deepEqual(macros.getCurrentStates(), { hello: true, world: false },
439+
assert.deepEqual(macros.getCurrentStates(), { hello: 'set', world: 'clear' },
416440
'states are not set as required');
417441
});
442+
443+
it('should call a macro only once, if two triggered macros request it simultaneously',
444+
function () {
445+
macros.init(CONFIG_MULTI_STATES);
446+
macros.execute(CONFIG_MULTI_STATES[1].name);
447+
clock.tick(20);
448+
macros.execute(CONFIG_MULTI_STATES[2].name);
449+
assert.deepEqual(macros.getCurrentStates(), { light: 'going_to_be_set' },
450+
'states are not in progress as they should');
451+
clock.tick(131);
452+
assert.deepEqual(deviceMock.operations,
453+
[['say', 'shiny'], ['say', 'uh'], ['say', 'ah']], 'calls are not done as expected');
454+
assert.deepEqual(macros.getCurrentStates(), { light: 'set' },
455+
'states are not set as required');
456+
}
457+
);
458+
459+
it('should call a macro only if the required state is not already set.',
460+
function () {
461+
macros.init(CONFIG_MULTI_STATES);
462+
macros.execute(CONFIG_MULTI_STATES[1].name);
463+
clock.tick(101);
464+
assert.deepEqual(deviceMock.operations,
465+
[['say', 'shiny'], ['say', 'uh']], 'first calls are not done as expected');
466+
assert.deepEqual(macros.getCurrentStates(), { light: 'set' },
467+
'first states are not set as required');
468+
macros.execute(CONFIG_MULTI_STATES[2].name);
469+
clock.tick(51);
470+
assert.deepEqual(deviceMock.operations,
471+
[['say', 'shiny'], ['say', 'uh'], ['say', 'ah']],
472+
'final calls are not done as expected');
473+
assert.deepEqual(macros.getCurrentStates(), { light: 'set' },
474+
'final states are not set as required');
475+
}
476+
);
477+
478+
it.skip('should call multiple macros if multiple states are requested', function () {
479+
macros.init(CONFIG_MULTI_STATES);
480+
macros.execute(CONFIG_MULTI_STATES[1].name);
481+
clock.tick(51);
482+
// TODO
483+
});
418484
});
419485
});
420486
});

0 commit comments

Comments
 (0)