Ask/answer opcode implementation with runtime events.

This commit is contained in:
Paul Kaplan 2017-10-31 11:12:26 -04:00
parent ef961c5a4b
commit 73ffc6a797
2 changed files with 91 additions and 1 deletions

View file

@ -7,6 +7,21 @@ class Scratch3SensingBlocks {
* @type {Runtime}
*/
this.runtime = runtime;
/**
* The "answer" block value.
* @type {string}
*/
this._answer = '';
/**
* The list of queued questions and respective `resolve` callbacks.
* @type {!Array}
*/
this._questionList = [];
this.runtime.on('ANSWER', this._onAnswer.bind(this));
this.runtime.on('PROJECT_STOP_ALL', this._clearAllQuestions.bind(this));
}
/**
@ -28,10 +43,51 @@ class Scratch3SensingBlocks {
sensing_keypressed: this.getKeyPressed,
sensing_current: this.current,
sensing_dayssince2000: this.daysSince2000,
sensing_loudness: this.getLoudness
sensing_loudness: this.getLoudness,
sensing_askandwait: this.askAndWait,
sensing_answer: this.getAnswer
};
}
_onAnswer (answer) {
this._answer = answer;
const questionObj = this._questionList.shift();
if (questionObj) {
const resolve = questionObj[1];
resolve();
this._askNextQuestion();
}
}
_enqueueAsk (question, resolve) {
this._questionList.push([question, resolve]);
}
_askNextQuestion () {
if (this._questionList.length > 0) {
this.runtime.emit('QUESTION', this._questionList[0][0]);
}
}
_clearAllQuestions () {
this._questionList = [];
this.runtime.emit('QUESTION', null);
}
askAndWait (args) {
return new Promise(resolve => {
const isQuestionAsked = this._questionList.length > 0;
this._enqueueAsk(args.QUESTION, resolve);
if (!isQuestionAsked) {
this._askNextQuestion();
}
});
}
getAnswer () {
return this._answer;
}
touchingObject (args, util) {
const requestedObject = args.TOUCHINGOBJECTMENU;
if (requestedObject === '_mouse_') {

View file

@ -0,0 +1,34 @@
const test = require('tap').test;
const Sensing = require('../../src/blocks/scratch3_sensing');
const Runtime = require('../../src/engine/runtime');
test('getPrimitives', t => {
const rt = new Runtime();
const s = new Sensing(rt);
t.type(s.getPrimitives(), 'object');
t.end();
});
test('ask and answer', t => {
const rt = new Runtime();
const s = new Sensing(rt);
const expectedQuestion = 'a question';
const expectedAnswer = 'the answer';
// Test is written out of order because of promises, follow the (#) comments.
rt.addListener('QUESTION', question => {
// (2) Assert the question is correct, then emit the answer
t.strictEqual(question, expectedQuestion);
rt.emit('ANSWER', expectedAnswer);
});
// (1) Emit the question.
const promise = s.askAndWait({QUESTION: expectedQuestion});
// (3) Ask block resolves after the answer is emitted.
promise.then(() => {
t.strictEqual(s.getAnswer(), expectedAnswer);
t.end();
});
});