Skip to content

Commit

Permalink
Merge pull request #18 from rraval/master
Browse files Browse the repository at this point in the history
Implement jQuery compatible `.pipe()`
  • Loading branch information
sudhirj committed Oct 13, 2013
2 parents b6523cc + b19540a commit a5a7213
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 36 deletions.
36 changes: 22 additions & 14 deletions deferred.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,24 @@ Deferred = ->
# It also makes sense to set up a piper to which can filter the success or failure arguments through the given filter methods.
# Quite useful if you want to transform the results of a promise or log them in some way.
pipe = (doneFilter, failFilter) ->
deferred = new Deferred()
filter = (source, destination, filter) ->
if filter then candidate[source] (args...) ->
filteredArgs = filter args...
# Some pipes might want to return another promise, though, so let's check if the object is a promise and resolve it correctly if it is.
if isPromise filteredArgs
filteredArgs[source] (args...) -> destination args...
# Otherwise we can just send the filtered values onward.
else destination(filteredArgs)
# If no filters have been passed, this degenerates into a shortcut method for adding both `done` and `fail` callbacks.
else candidate[source] (args...) -> destination args...
filter 'done', deferred.resolve, doneFilter
filter 'fail', deferred.reject, failFilter
deferred
master = new Deferred()

filter = (source, funnel, callback) ->
if callback?
candidate[source]((args...) ->
value = callback(args...)
if isPromise(value)
value.done(master.resolve).fail(master.reject)
else
master[funnel](value)
)
else
candidate[source](master[funnel])

filter('done', 'resolve', doneFilter)
filter('fail', 'reject', failFilter)

return master

# Expose the `.pipe(doneFilter, failFilter)` method and alias it to `.then()`.
candidate.pipe = pipe
Expand Down Expand Up @@ -133,6 +137,10 @@ Deferred = ->
# Let's set up a `.when([deferreds])` method to do that. It should be able to take any number or deferreds as arguments (or an array of them).
_when = ->
defs = flatten arguments
if defs.length == 1
# small optimization: pass a single deferred object along
return if isPromise defs[0] then defs[0] else (new Deferred()).resolve(defs[0]).promise()

trigger = new Deferred()
return trigger.resolve().promise() if not defs.length

Expand Down
41 changes: 20 additions & 21 deletions deferred.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions deferred_test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@ describe 'deferred', ->

def.resolve('r1')

it 'should allow changing the state', (done) ->
def = deferred.Deferred()

def.pipe((result) ->
return deferred.Deferred().reject('failure').promise()
).fail((msg) ->
assert.equal msg, 'failure'
done() if msg is 'failure'
)

def.resolve('r1')

describe 'then', ->
it 'should alias pipe', ->
def = new deferred.Deferred()
Expand Down Expand Up @@ -247,6 +259,7 @@ describe 'deferred', ->
it 'should pass on resolve arguments as is when used with a single deferred', (done) ->
d1 = new deferred.Deferred()
after_all = deferred.when(d1)
assert.equal d1, after_all
after_all.done (arg1) -> done() if arg1 is 42
d1.resolve(42)

Expand Down
16 changes: 15 additions & 1 deletion deferred_test.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a5a7213

Please sign in to comment.