From ded480c660da3a288f3a7e9e4e7773bd2a7cb2c7 Mon Sep 17 00:00:00 2001 From: Ben Alman Date: Fri, 6 Apr 2012 10:11:51 -0400 Subject: [PATCH] Adding the ability for the task queue to be cleared more programmatically via marker. --- lib/util/task.js | 52 ++++++++++++++++++++++++++++----------- test/util/task_test.js | 56 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 16 deletions(-) diff --git a/lib/util/task.js b/lib/util/task.js index 923e736a7..c3af2589e 100644 --- a/lib/util/task.js +++ b/lib/util/task.js @@ -20,7 +20,9 @@ // Task queue. this._queue = []; // Queue placeholder (for dealing with nested tasks). - this._placeholder = {}; + this._placeholder = {placeholder: true}; + // Queue marker (for clearing the queue programatically). + this._marker = {marker: true}; // Options. this._options = {}; // Is the queue running? @@ -240,6 +242,19 @@ return {task: task, nameArgs: name, args: args, flags: flags}; }; + // Append things to queue in the correct spot. + Task.prototype._push = function(things) { + // Get current placeholder index. + var index = this._queue.indexOf(this._placeholder); + if (index === -1) { + // No placeholder, add task+args objects to end of queue. + this._queue = this._queue.concat(things); + } else { + // Placeholder exists, add task+args objects just before placeholder. + [].splice.apply(this._queue, [index, 0].concat(things)); + } + }; + // Enqueue a task. Task.prototype.run = function() { // Parse arguments into an array, returning an array of task+args objects. @@ -250,15 +265,15 @@ this._throwIfRunning(new TaskError('Task "' + fails[0].nameArgs + '" not found.')); return this; } - // Get current placeholder index. - var index = this._queue.indexOf(this._placeholder); - if (index === -1) { - // No placeholder, add task+args objects to end of queue. - this._queue = this._queue.concat(things); - } else { - // Placeholder exists, add task+args objects just before placeholder. - [].splice.apply(this._queue, [index, 0].concat(things)); - } + // Append things to queue in the correct spot. + this._push(things); + // Make chainable! + return this; + }; + + // Add a marker to the queue to facilitate clearing it programatically. + Task.prototype.mark = function() { + this._push(this._marker); // Make chainable! return this; }; @@ -273,8 +288,10 @@ var async = false; // Get next task+args object from queue. var thing; - // Skip any placeholders. - do { thing = this._queue.shift(); } while (thing === this._placeholder); + // Skip any placeholders or markers. + do { + thing = this._queue.shift(); + } while (thing === this._placeholder || thing === this._marker); // If queue was empty, we're all done. if (!thing) { this._running = false; @@ -340,9 +357,14 @@ nextTask(); }; - // Clear all remaining tasks from the queue, or a subset. - Task.prototype.clearQueue = function() { - this._queue = []; + // Clear remaining tasks from the queue. + Task.prototype.clearQueue = function(options) { + if (!options) { options = {}; } + if (options.untilMarker) { + this._queue.splice(0, this._queue.indexOf(this._marker) + 1); + } else { + this._queue = []; + } // Make chainable! return this; }; diff --git a/test/util/task_test.js b/test/util/task_test.js index a90356b59..afe9e16c7 100644 --- a/test/util/task_test.js +++ b/test/util/task_test.js @@ -285,7 +285,8 @@ exports['Tasks'] = { } }); task.run('a:b:c').start(); - }, 'Task#clearQueue': function(test) { + }, + 'Task#clearQueue': function(test) { test.expect(1); var task = this.task; task.registerTask('a', 'Push task name onto result.', result.pushTaskname); @@ -305,6 +306,59 @@ exports['Tasks'] = { }); task.run('a b c d e').start(); }, + 'Task#mark': function(test) { + // test.expect(1); + var task = this.task; + task.registerTask('a', 'Explode.', function() { + throw task.taskError('whoops.'); + }); + task.registerTask('b', 'This task should never run.', result.pushTaskname); + task.registerTask('c', 'This task should never run.', result.pushTaskname); + + task.registerTask('d', 'Push task name onto result.', result.pushTaskname); + task.registerTask('e', 'Explode.', function() { + throw task.taskError('whoops.'); + }); + task.registerTask('f', 'This task should never run.', result.pushTaskname); + + task.registerTask('g', 'Push task name onto result.', result.pushTaskname); + task.registerTask('h', 'Push task name onto result.', result.pushTaskname); + task.registerTask('i', 'Explode.', function() { + throw task.taskError('whoops.'); + }); + + task.registerTask('j', 'Run a task and push task name onto result.', function() { + task.run('k'); + result.push(this.name); + }); + task.registerTask('k', 'Explode.', function() { + throw task.taskError('whoops.'); + }); + task.registerTask('l', 'This task should never run.', result.pushTaskname); + + task.registerTask('m', 'Push task name onto result.', result.pushTaskname); + task.registerTask('n', 'Run a task and push task name onto result.', function() { + task.run('o'); + result.push(this.name); + }); + task.registerTask('o', 'Explode.', function() { + throw task.taskError('whoops.'); + }); + + task.registerTask('p', 'Push task name onto result.', result.pushTaskname); + + task.options({ + error: function(e) { + result.push('!' + this.name); + task.clearQueue({untilMarker: true}); + }, + done: function() { + test.strictEqual(result.getJoined(), '!ad!egh!ij!kmn!op', 'The specified tasks should have run, in-order.'); + test.done(); + } + }); + task.run('a b c').mark().run('d e f').mark().run('g h i').mark().run('j l').mark().run('m n').mark().run('p').mark().start(); + }, 'Task#requires': function(test) { test.expect(1); var task = this.task;