| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- var util = require('util')
- module.exports = ifAsync
- var OK = 0
- var EXPECT_THEN = 1
- function ifAsync() {
- var clauses = toArray(arguments)
- var elseClause = elseNoop
- var fluentState = OK
- if (clauses.length === 0) {
- throw new Error('at least one predicate and one consequent are required')
- }
- // using fluent interface, we expect the user will call then() before invoking the functor
- if (clauses.length === 1) {
- fluentState = EXPECT_THEN
- } else if (clauses.length % 2 === 1) {
- elseClause = clauses.pop()
- }
- var functor = function() {
- if (fluentState !== OK) {
- throw new Error('missing at least one consequent, you forgot to call then() ?')
- }
- var args = arguments
- var callback = args[args.length - 1]
- if (typeof callback !== 'function') {
- throw new Error('missing callback argument')
- }
- var predicate = clauses.shift()
-
- if (!predicate) {
- return elseClause.apply(null, args)
- }
- var consequent = clauses.shift()
-
- var replacedCallbackArgs = toArray(args)
- replacedCallbackArgs.pop()
- replacedCallbackArgs.push(predicateCallback)
- predicate.apply(null, replacedCallbackArgs)
- function predicateCallback(err, result) {
- if (err) return callback(err)
- if (result) {
- return consequent.apply(null, args)
- } else {
- functor.apply(null, args)
- }
- }
- }
- functor.then = function(fn) {
- if (fluentState !== EXPECT_THEN) {
- throw new Error('not expecting a then() call now')
- }
- fluentState = OK
- clauses.push(fn)
- return functor
- }
- functor.and = function(fn) {
- var predicate = clauses.pop()
- // logical AND using ifAsync
- clauses.push(
- ifAsync(predicate)
- .then(fn)
- .else(callbackFalse)
- )
- return functor
- }
- functor.and.not = function(predicate) {
- return functor.and(not(predicate))
- }
- functor.or = function(fn) {
- var predicate = clauses.pop()
- // logical OR
- clauses.push(
- ifAsync(predicate)
- .then(callbackTrue)
- .elseIf(fn)
- .then(callbackTrue)
- .else(callbackFalse)
- )
- return functor
- }
- functor.or.not = function(predicate) {
- return functor.or(not(predicate))
- }
- functor.else = function(predicate) {
- if (fluentState === EXPECT_THEN) {
- throw new Error('only then() may be called after elseIf()')
- }
- elseClause = predicate
- return functor
- }
- functor.elseif = functor.elseIf = function(predicate) {
- if (fluentState === EXPECT_THEN) {
- throw new Error('only then() may be called after elseIf()')
- }
- clauses.push(predicate)
- // allow only then after a call to elseif
- fluentState = EXPECT_THEN
- return functor
- }
- functor.elseif.not = function(predicate) {
- return functor.elseIf(not(predicate))
- }
- return functor
- }
- ifAsync.not = function(predicate) {
- if (typeof predicate !== 'function') {
- throw new Error('argument must be a predicate function')
- }
- return ifAsync(not(predicate))
- }
- function not(predicate) {
- return function () {
- var args = toArray(arguments)
- var callback = args.pop()
- if (typeof callback !== 'function') {
- throw new Error('expected a callback but instead got ' + typeof callback)
- }
- args.push(function(err, result) {
- callback(err, !result)
- })
- predicate.apply(null, args)
- }
- }
- function elseNoop() {
- var args = toArray(arguments)
- var callback = args.pop()
- args.unshift(null)
- if (typeof callback !== 'function') {
- throw new Error('expected a callback function')
- }
- setImmediate(function () {
- callback.apply(null, args)
- })
- }
- function callbackTrue() {
- var callback = arguments[arguments.length - 1]
- if (typeof callback !== 'function') {
- throw new Error('expected a callback function')
- }
-
- callback(null, true)
- }
- function callbackFalse() {
- var callback = arguments[arguments.length - 1]
- if (typeof callback !== 'function') {
- throw new Error('expected a callback function')
- }
-
- callback(null, false)
- }
- function toArray(args) {
- return Array.prototype.slice.call(args, 0)
- }
|