summaryrefslogtreecommitdiff
path: root/node_modules/hooks/hooks.alt.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/hooks/hooks.alt.js')
-rw-r--r--node_modules/hooks/hooks.alt.js134
1 files changed, 134 insertions, 0 deletions
diff --git a/node_modules/hooks/hooks.alt.js b/node_modules/hooks/hooks.alt.js
new file mode 100644
index 0000000..6ced357
--- /dev/null
+++ b/node_modules/hooks/hooks.alt.js
@@ -0,0 +1,134 @@
+/**
+ * Hooks are useful if we want to add a method that automatically has `pre` and `post` hooks.
+ * For example, it would be convenient to have `pre` and `post` hooks for `save`.
+ * _.extend(Model, mixins.hooks);
+ * Model.hook('save', function () {
+ * console.log('saving');
+ * });
+ * Model.pre('save', function (next, done) {
+ * console.log('about to save');
+ * next();
+ * });
+ * Model.post('save', function (next, done) {
+ * console.log('saved');
+ * next();
+ * });
+ *
+ * var m = new Model();
+ * m.save();
+ * // about to save
+ * // saving
+ * // saved
+ */
+
+// TODO Add in pre and post skipping options
+module.exports = {
+ /**
+ * Declares a new hook to which you can add pres and posts
+ * @param {String} name of the function
+ * @param {Function} the method
+ * @param {Function} the error handler callback
+ */
+ hook: function (name, fn, err) {
+ if (arguments.length === 1 && typeof name === 'object') {
+ for (var k in name) { // `name` is a hash of hookName->hookFn
+ this.hook(k, name[k]);
+ }
+ return;
+ }
+
+ if (!err) err = fn;
+
+ var proto = this.prototype || this
+ , pres = proto._pres = proto._pres || {}
+ , posts = proto._posts = proto._posts || {};
+ pres[name] = pres[name] || [];
+ posts[name] = posts[name] || [];
+
+ function noop () {}
+
+ proto[name] = function () {
+ var self = this
+ , pres = this._pres[name]
+ , posts = this._posts[name]
+ , numAsyncPres = 0
+ , hookArgs = [].slice.call(arguments)
+ , preChain = pres.map( function (pre, i) {
+ var wrapper = function () {
+ if (arguments[0] instanceof Error)
+ return err(arguments[0]);
+ if (numAsyncPres) {
+ // arguments[1] === asyncComplete
+ if (arguments.length)
+ hookArgs = [].slice.call(arguments, 2);
+ pre.apply(self,
+ [ preChain[i+1] || allPresInvoked,
+ asyncComplete
+ ].concat(hookArgs)
+ );
+ } else {
+ if (arguments.length)
+ hookArgs = [].slice.call(arguments);
+ pre.apply(self,
+ [ preChain[i+1] || allPresDone ].concat(hookArgs));
+ }
+ }; // end wrapper = function () {...
+ if (wrapper.isAsync = pre.isAsync)
+ numAsyncPres++;
+ return wrapper;
+ }); // end posts.map(...)
+ function allPresInvoked () {
+ if (arguments[0] instanceof Error)
+ err(arguments[0]);
+ }
+
+ function allPresDone () {
+ if (arguments[0] instanceof Error)
+ return err(arguments[0]);
+ if (arguments.length)
+ hookArgs = [].slice.call(arguments);
+ fn.apply(self, hookArgs);
+ var postChain = posts.map( function (post, i) {
+ var wrapper = function () {
+ if (arguments[0] instanceof Error)
+ return err(arguments[0]);
+ if (arguments.length)
+ hookArgs = [].slice.call(arguments);
+ post.apply(self,
+ [ postChain[i+1] || noop].concat(hookArgs));
+ }; // end wrapper = function () {...
+ return wrapper;
+ }); // end posts.map(...)
+ if (postChain.length) postChain[0]();
+ }
+
+ if (numAsyncPres) {
+ complete = numAsyncPres;
+ function asyncComplete () {
+ if (arguments[0] instanceof Error)
+ return err(arguments[0]);
+ --complete || allPresDone.call(this);
+ }
+ }
+ (preChain[0] || allPresDone)();
+ };
+
+ return this;
+ },
+
+ pre: function (name, fn, isAsync) {
+ var proto = this.prototype
+ , pres = proto._pres = proto._pres || {};
+ if (fn.isAsync = isAsync) {
+ this.prototype[name].numAsyncPres++;
+ }
+ (pres[name] = pres[name] || []).push(fn);
+ return this;
+ },
+ post: function (name, fn, isAsync) {
+ var proto = this.prototype
+ , posts = proto._posts = proto._posts || {};
+ (posts[name] = posts[name] || []).push(fn);
+ return this;
+ }
+};