Created
July 12, 2015 18:08
-
-
Save marbemac/27ee149aa5a50ce82823 to your computer and use it in GitHub Desktop.
Signals implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const runAction = (name, action, commonArgs, args) => { | |
console.log(`signals:${name}:${action.name}`, {action: action, commonArgs: commonArgs, args: args}) | |
try { | |
return action(commonArgs, args) | |
} catch(e) { | |
console.error(`Error running ${action.name} action for the ${name} signal.`, | |
{action: action, err: e, commonArgs: commonArgs, args: args}) | |
return Promise.reject(e) | |
} | |
} | |
const handleAction = (name, actions, counter, path, commonArgs, args, rejectTriggered) => { | |
let actionChain = actions.slice(counter) | |
if (typeof actionChain[0] === 'object') { | |
console.log(`signals:${name}:${path.toUpperCase()}`, rejectTriggered) | |
if (!actionChain[0][path]) { | |
console.error(`You have a branching action chain for signal ${name}, but have not defined a ${path} branch!'`, { | |
actions: actions, counter: counter, chain: actionChain[0]}) | |
} | |
const afterActions = actionChain[0].after | |
return runActions(name, actionChain[0][path], commonArgs, args, rejectTriggered).then(() => { | |
if (afterActions && afterActions.length > 0) { | |
return runActions(name, afterActions, commonArgs, args, rejectTriggered) | |
} | |
}, () => { | |
if (afterActions && afterActions.length > 0) { | |
return runActions(name, afterActions, commonArgs, args, rejectTriggered) | |
} | |
}) | |
} else { | |
return runActions(name, actionChain, commonArgs, args, rejectTriggered) | |
} | |
} | |
const runActions = (name, actions, commonArgs, args, rejectTriggered) => { | |
rejectTriggered = rejectTriggered || false | |
let counter = 0 | |
for (let i in actions) { | |
counter += 1 | |
if (actions[i] === undefined) { | |
let extra = '' | |
if (counter === 1 && actions.length > 1) { | |
extra = `, right before the ${actions[counter].name} action` | |
} else if (counter > 1) { | |
extra = `, right after the ${actions[counter - 1].name} action` | |
} | |
console.error(`You have an undefined action in your ${name} signal${extra}.'`, {actions: actions, counter: counter}) | |
continue | |
} | |
let run = runAction(name, actions[i], commonArgs, args) | |
if (run instanceof Promise) { | |
return run.then((e) => { | |
return handleAction(name, actions, counter, 'resolve', commonArgs, args, rejectTriggered) | |
}).catch((e) => { | |
rejectTriggered = e | |
return handleAction(name, actions, counter, 'reject', commonArgs, args, rejectTriggered) | |
}) | |
} | |
} | |
if (rejectTriggered) { | |
return Promise.reject() | |
} else { | |
return Promise.resolve() | |
} | |
} | |
const signalFactory = (obj = {}) => { | |
obj.signals = {} | |
// The new function requires at least two arguments. | |
// The first argument is the name of the action. | |
// Subsequent arguments are action functions, or chain objects. | |
// | |
// An action function has the signature action(commonArgs, args), | |
// and may return a promise. | |
// | |
// A chain object can follow an asyncronous action, and comes in the form | |
// { | |
// resolve: [action1, action2], | |
// reject: [action3], | |
// after: [action4, action5] | |
// } | |
// | |
// So a full call to .new would look like: | |
// | |
// signal.new('myCoolSignal', | |
// action1, | |
// ayncAction2, | |
// { | |
// resolve: [ | |
// action3, | |
// asyncAction4, | |
// { | |
// resolve: [action6], | |
// reject: [action5] | |
// } | |
// ], | |
// reject: [action5], | |
// after: [finishAction] | |
// } | |
// ) | |
// | |
// One can then invoke this signal via signals.myCoolSignal({passed: 'args'}) | |
obj.new = function() { | |
const args = [].slice.call(arguments) | |
const name = args[0] | |
const actions = args.slice(1) | |
const commonArgs = obj.commonArgs | |
commonArgs.signals = obj.signals | |
obj.signals[name] = function() { | |
console.log('signals', `Running signals ${name}`) | |
let passedArgs = [].slice.call(arguments)[0] || {} | |
return runActions(name, actions, commonArgs, passedArgs).then(() => { | |
// successful signal loop | |
}, () => { | |
// unsuccessful signal loop | |
}) | |
} | |
} | |
return obj | |
} | |
export default signalFactory |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment