Skip to content

Instantly share code, notes, and snippets.

@dsc
Created September 17, 2012 19:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsc/3739267 to your computer and use it in GitHub Desktop.
Save dsc/3739267 to your computer and use it in GitHub Desktop.
events.co
# Technically, this is Coco, not CoffeeScript, but close enough.
{ toString:objToString } = Object::
isArray = Array.isArray or (o) -> objToString.call(o) is '[object Array]'
slice = [].slice
class exports.EventEmitter
emit: (type) ->
arg = arguments[1]
if type is 'error' and
not @_events?.error or
( isArray(@_events.error) and not @_events.error.length )
if arg instanceof Error
throw arg # Unhandled 'error' event
else
throw new Error("Uncaught, unspecified 'error' event.")
return false
queue = @_events?[type]
if typeof queue is 'function'
listener = queue
switch arguments.length
# fast cases
case 1 then listener.call this
case 2 then listener.call this, arg
case 3 then listener.call this, arg, arguments[2]
# slower
default then listener.apply this, slice.call(arguments, 1)
else if isArray queue
args = slice.call(arguments, 1)
listener.apply(this, args) for listener of queue
else
return false
return true
trigger: ->
@emit ...
on: (type, listener) ->
if typeof listener is not 'function'
throw new TypeError "addListener only takes instances of Function"
@emit 'newListener', type, listener
events = @_events or= {}
if not events[type]
events[type] = listener
else if not isArray events[type]
# Upgrade single listener to Array
events[type] = [ events[type], listener ]
else
# Copy now to avoid copying on emit (which is way more common)
( events[type] = events[type].slice() ).push(listener)
return this
addListener: ->
@on ...
off: (type, listener) ->
if typeof listener is not 'function'
throw new TypeError "addListener only takes instances of Function"
queue = @_events?[type]
return this unless queue
if typeof queue is 'function'
if queue is listener or queue.listener is listener
delete @_events[type]
return this
idx = -1
for fn, i of queue
if fn is listener or (fn.listener is listener)
idx = i
break
return this if idx < 0
if queue.length is 1
delete @_events[type]
else
queue = @_events[type] = queue.slice()
queue.splice idx, 1
return this
removeListener: ->
@off ...
removeAllListeners: (type) ->
if arguments.length is 0
@_events = {}
return this
delete @_events[type] if @_events?[type]
return this
once: (type, listener) ->
if typeof listener is not 'function'
throw new TypeError "once only takes instances of Function"
self = this
_once = ->
self.removeListener type, _once
listener ...
void
_once.listener = listener
return @on type, _once
listeners: (type) ->
events = @_events or= {}
queue = events[type] or= []
queue = events[type] = [events[type]] unless isArray queue
return queue
setMaxListeners: (n) ->
console.debug 'setMaxListeners is unsupported'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment