Skip to content

Commit

Permalink
Merge a01eae9 into 16e4de7
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima committed Feb 21, 2020
2 parents 16e4de7 + a01eae9 commit ccd4612
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 6 deletions.
87 changes: 81 additions & 6 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -600,12 +600,26 @@ class Generator extends EventEmitter {
queueTaskGroup(taskGroup, taskOptions) {
const self = this;
// Run each queue items
_.each(taskGroup, (newMethod, newMethodName) => {
if (!_.isFunction(newMethod) || !methodIsValid(newMethodName)) return;
_.each(taskGroup, (groupMember, newMethodName) => {
if (typeof groupMember !== 'function') {
if (typeof groupMember === 'object') {
self.queueTask({
taskName: newMethodName,
...groupMember,
...taskOptions
});
}

return;
}

if (!methodIsValid(newMethodName)) {
return;
}

self.queueTask({
...taskOptions,
method: newMethod,
method: groupMember,
taskName: newMethodName
});
});
Expand All @@ -617,6 +631,8 @@ class Generator extends EventEmitter {
* @param {Task} task: Task to be queued.
*/
queueTask(task) {
assert(task.taskName);
assert(task.method);
const reject = task.reject || (() => {});
const queueName = task.queueName || 'default';
const methodName = task.taskName;
Expand Down Expand Up @@ -674,6 +690,63 @@ class Generator extends EventEmitter {
);
}

runComposedMethod(name, ...parameters) {
const property = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), name);
if (!property) {
throw new Error(`Property ${name} not found at ${this.options.namespace}`);
}

if (property.get) {
this.queueGroupTask(property.get.call(self));
return;
}

const method = property.value;
if (typeof method !== 'function') {
throw new Error(
`Property ${name} is not a composed method at ${this.options.namespace}`
);
}

const tasks = method.call(this, ...parameters);
if (typeof tasks !== 'object') {
throw new Error(
`Function ${name} is not a composed method at ${this.options.namespace}`
);
}

const self = this;
const queueTask = function(task) {
if (!task.method) {
throw new Error(
`Invalid task at composed method ${name} at ${self.options.namespace}`
);
}

if (task.priorityName) {
const priority = self._queues[task.priorityName];
if (!priority) {
throw new Error(`Priority ${task.priorityName} is not defined`);
}

// If priority is defined, use it configs as defaults;
task = { ...priority, ...task };
}

// If run in not defined, set to false to don't start the loop if not running yet
task.run = task.run === undefined ? false : task.run;
self.queueTask(task);
};

if (Array.isArray(tasks)) {
tasks.filter(task => task.method && task.taskName).forEach(queueTask);
return;
}

tasks.taskName = tasks.taskName || name;
queueTask(tasks);
}

/**
* Runs the generator, scheduling prototype methods on a run queue. Method names
* will determine the order each method is run. Methods without special names
Expand Down Expand Up @@ -790,11 +863,13 @@ class Generator extends EventEmitter {
options = {};
}

const returnCompose = ret => (returnNewGenerator ? ret : this);

let instantiatedGenerator;

if (Array.isArray(generator)) {
const generators = generator.map(gen => this.composeWith(gen, options));
return returnNewGenerator ? generators : this;
return returnCompose(generators);
}

const instantiate = (Generator, path) => {
Expand Down Expand Up @@ -877,7 +952,7 @@ class Generator extends EventEmitter {
}

if (!instantiatedGenerator) {
return returnNewGenerator ? instantiatedGenerator : this;
return returnCompose(instantiatedGenerator);
}

if (this._running) {
Expand All @@ -886,7 +961,7 @@ class Generator extends EventEmitter {
this._composedWith.push(instantiatedGenerator);
}

return returnNewGenerator ? instantiatedGenerator : this;
return returnCompose(instantiatedGenerator);
}

/**
Expand Down
121 changes: 121 additions & 0 deletions test/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,127 @@ describe('Base', () => {
});
});

describe('#runComposedMethod', () => {
it('correctly run runComposedMethod', function() {
const commonConfiguring = sinon.spy();
const configuring = sinon.spy();

const TestGenerator = class extends Base {
constructor(args, opts) {
super(args, {
...opts,
customPriorities: [{ name: 'commonConfiguring', once: true }]
});
}
};
_.extend(TestGenerator.prototype, {
commonConfiguring: commonConfiguring,

get composed() {
return {
commonConfiguring: {
method: this.commonConfiguring,
priorityName: 'commonConfiguring'
}
};
},

_composed(options) {
return [
{
method: this.commonConfiguring,
taskName: 'commonConfiguring',
priorityName: 'commonConfiguring'
},
{
method: this.commonConfiguring,
taskName: 'commonConfiguring',
priorityName: 'commonConfiguring'
},
{
method: function() {
configuring(options.callNumber);
},
taskName: 'configuring'
}
];
}
});

const testGen = new TestGenerator([], {
resolved: 'unknown',
namespace: 'dummy',
env: this.env,
'skip-install': true
});

testGen.runComposedMethod('_composed', { callNumber: 1 });
testGen.runComposedMethod('_composed', { callNumber: 2 });

return testGen.run().then(() => {
sinon.assert.calledOnce(commonConfiguring);
sinon.assert.calledTwice(configuring);
assert.equal(1, configuring.getCall(0).args[0]);
assert.equal(2, configuring.getCall(1).args[0]);
});
});

it("throws if the method doesn't exists", function() {
assert.throws(() => this.dummy.runComposedMethod('dontExists'), /not found/);
});

describe('throws on errors', function() {
before(function() {
const TestGenerator = class extends Base {};
TestGenerator.prototype.notAFunction = {};
TestGenerator.prototype.returnUndefined = () => {};
TestGenerator.prototype.invalidComposedMethod = () => {
return {};
};

TestGenerator.prototype.invalidPriority = () => {
return { method: () => {}, priorityName: 'dontExists' };
};

this.gen = new TestGenerator([], {
resolved: 'unknown',
namespace: 'dummy',
env: this.env,
'skip-install': true
});
});

it('throws if not a function', function() {
assert.throws(
() => this.gen.runComposedMethod('notAFunction'),
/not a composed method/
);
});

it('throws if passed an invalid priority', function() {
assert.throws(
() => this.gen.runComposedMethod('invalidPriority'),
/Priority (.*) is not defined/
);
});

/* Ait('throws if the function returns not an object', function() {
* assert.throws(
* () => this.gen.runComposedMethod('returnUndefined'),
* /not a composed method/
* );
* });
*/

it('throws if the function returns a invalid task', function() {
assert.throws(
() => this.gen.runComposedMethod('invalidComposedMethod'),
/Invalid task at composed method/
);
});
});
});

describe('Custom priorities errors', () => {
it('error is thrown with duplicate custom queue', function() {
const TestGenerator = class extends Base {
Expand Down

0 comments on commit ccd4612

Please sign in to comment.