Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit 2131f541cf72f2b0e795df356108d1fa682389b6 @aheckmann committed Jan 8, 2013
Showing with 549 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +4 −0 .travis.yml
  3. +22 −0 LICENSE
  4. +12 −0 Makefile
  5. +18 −0 README.md
  6. +1 −0 index.js
  7. +236 −0 lib/promise.js
  8. +29 −0 package.json
  9. +190 −0 test/promise.test.js
  10. +35 −0 test/promises-A.js
@@ -0,0 +1,2 @@
+*.sw*
+node_modules/
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.6
+ - 0.8
22 LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,12 @@
+TESTS = $(shell find test/ -name '*.test.js')
+
+test:
+ @make test-unit && echo "testing promises-A+ implementation ..." && make test-promises-A
+
+test-unit:
+ @./node_modules/.bin/mocha $(T) --async-only $(TESTS)
+
+test-promises-A:
+ @node test/promises-A.js
+
+.PHONY: test test-unit test-promises-A
@@ -0,0 +1,18 @@
+#mpromise
+==========
+
+A [promises/A+](https://github.com/promises-aplus/promises-spec) conformant implementation, originally used in [mongoose](http://mongoosejs.com).
+
+## installation
+
+```
+$ npm install mpromise
+```
+
+## documentation
+
+For now read the [source](https://github.com/aheckmann/mpromise/blob/master/lib) and [tests](https://github.com/aheckmann/mpromise/blob/master/test).
+
+## license
+
+[MIT](https://github.com/aheckmann/mpromise/blob/master/LICENSE)
@@ -0,0 +1 @@
+module.exports = exports = require('./lib/promise');
@@ -0,0 +1,236 @@
+
+/*!
+ * Module dependencies.
+ */
+
+var slice = require('sliced');
+var EventEmitter = require('events').EventEmitter;
+
+/**
+ * Promise constructor.
+ *
+ * @param {Function} back a callback+errback that accepts `fn(err, ...){}` as signature
+ * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
+ * @event `err`: Emits when the promise resolves to an error.
+ * @event `complete`: Emits when the promise resolves sucessfully.
+ * @api public
+ */
+
+function Promise (back) {
+ this.emitted = {};
+ if ('function' == typeof back)
+ this.addBack(back);
+}
+
+/*!
+ * Inherits from EventEmitter.
+ */
+
+Promise.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Adds `listener` to the `event`.
+ *
+ * If `event` is either `error` or `complete` and the event has already been emitted, the`listener` is called immediately and passed the results of the original emitted event.
+ *
+ * @param {String} event
+ * @param {Function} callback
+ * @return {Promise} this
+ * @api public
+ */
+
+Promise.prototype.on = function (event, callback) {
+ if (this.emitted[event])
+ callback.apply(this, this.emitted[event]);
+ else
+ EventEmitter.prototype.on.call(this, event, callback);
+
+ return this;
+}
+
+/**
+ * Keeps track of emitted events to run them on `on`.
+ *
+ * @api private
+ */
+
+Promise.prototype.emit = function (event) {
+ // ensures a promise can't be complete() or error() twice
+ if (event == 'err' || event == 'complete') {
+ if (this.emitted.err || this.emitted.complete) {
+ return this;
+ }
+ this.emitted[event] = slice(arguments, 1);
+ }
+
+ return EventEmitter.prototype.emit.apply(this, arguments);
+}
+
+/**
+ * Shortcut for emitting the `complete` event.
+ *
+ * @api public
+ */
+
+Promise.prototype.complete = function () {
+ var args = slice(arguments);
+ return this.emit.apply(this, ['complete'].concat(args));
+}
+
+/**
+ * Shortcut for emitting the `err` event.
+ *
+ * If `err` is not instanceof Error, it is cast to Error before rejecting.
+ *
+ * @api public
+ * @return {Promise} this
+ */
+
+Promise.prototype.error = function (err) {
+ if (!(err instanceof Error)) err = new Error(err);
+ return this.reject(err);
+}
+
+/**
+ * Rejects this promise with `reason`.
+ * Differs from `promise#error` by not casting the argument to an error.
+ *
+ * @api public
+ * @param {Object|String} reason
+ * @return {Promise} this
+ */
+
+Promise.prototype.reject = function (reason) {
+ return this.emit('err', reason);
+}
+
+/**
+ * Adds a listener to the `complete` (success) event.
+ *
+ * @return {Promise} this
+ * @api public
+ */
+
+Promise.prototype.addCallback = function (fn) {
+ return this.on('complete', fn);
+}
+
+/**
+ * Adds a listener to the `err` (rejected) event.
+ *
+ * @return {Promise} this
+ * @api public
+ */
+
+Promise.prototype.addErrback = function (fn) {
+ return this.on('err', fn);
+}
+
+/**
+ * Adds a single function as both a callback and errback.
+ *
+ * It will be executed with traditional node.js argument position:
+ * function (err, args...) {}
+ *
+ * @param {Function} fn
+ * @return {Promise} this
+ */
+
+Promise.prototype.addBack = function (fn) {
+ this.on('err', function(err){
+ fn.call(this, err);
+ });
+
+ this.on('complete', function(){
+ var args = slice(arguments);
+ fn.apply(this, [null].concat(args));
+ });
+
+ return this;
+}
+
+/**
+ * Resolves this promise to an error state if `err` is passed or success
+ * state when no `err` is passed.
+ *
+ * `err` will be cast to an Error if not already instanceof Error.
+ *
+ * @param {Error} [err] error or null
+ * @param {Object} [val] value to complete the promise with
+ * @api public
+ */
+
+Promise.prototype.resolve = function (err, val) {
+ if (err) return this.error(err);
+ return this.complete(val);
+}
+
+/**
+ * Creates a new promise and returns it. If `onFulfill` or
+ * `onReject` are passed, they are added as success/error callbacks
+ * to this promise after the nextTick.
+ *
+ * Conforms to [promises/A+](https://github.com/promises-aplus/promises-spec) specification. Read for more detail how to use this method.
+ *
+ * ####Example:
+ *
+ * var p = new Promise;
+ * p.then(function (arg) {
+ * return arg + 1;
+ * }).then(function (arg) {
+ * throw new Error(arg + ' is an error!');
+ * }).then(null, function (err) {
+ * assert.ok(err instanceof Error);
+ * assert.equal('2 is an error');
+ * });
+ * p.complete(1);
+ *
+ * @see promises-A+ https://github.com/promises-aplus/promises-spec
+ * @param {Function} onFulFill
+ * @param {Function} onReject
+ * @return {Promise} newPromise
+ */
+
+Promise.prototype.then = function (onFulfill, onReject) {
+ var self = this
+ , retPromise = new Promise;
+
+ function handler (fn) {
+ return function handle (arg) {
+ try {
+ var val = fn(arg);
+ if (val && val.then) {
+ val.then(
+ retPromise.complete.bind(retPromise)
+ , retPromise.reject.bind(retPromise))
+ } else {
+ retPromise.complete(val);
+ }
+ } catch (err) {
+ retPromise.reject(err);
+ }
+ }
+ }
+
+ process.nextTick(function () {
+ if ('function' == typeof onReject) {
+ self.addErrback(handler(onReject));
+ } else {
+ self.addErrback(retPromise.reject.bind(retPromise));
+ }
+
+ if ('function' == typeof onFulfill) {
+ self.addCallback(handler(onFulfill));
+ } else {
+ self.addCallback(retPromise.complete.bind(retPromise));
+ }
+ })
+
+ return retPromise;
+}
+
+/*!
+ * Module exports.
+ */
+
+module.exports = Promise;
@@ -0,0 +1,29 @@
+{
+ "name": "mpromise",
+ "version": "0.0.0",
+ "description": "Promises A+ conformant implementation used by Mongoose",
+ "main": "index.js",
+ "scripts": {
+ "test": "make test"
+ },
+ "dependencies": {
+ "sliced": "0.0.4"
+ },
+ "devDependencies": {
+ "mocha": "1.7.4",
+ "promises-aplus-tests": ">= 1.0.2"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/aheckmann/mpromise"
+ },
+ "keywords": [
+ "promise",
+ "mongoose",
+ "aplus",
+ "a+",
+ "plus"
+ ],
+ "author": "Aaron Heckmann <aaron.heckmann+github@gmail.com>",
+ "license": "MIT"
+}
Oops, something went wrong.

0 comments on commit 2131f54

Please sign in to comment.