Last active
December 10, 2015 23:28
-
-
Save mpneuried/4509358 to your computer and use it in GitHub Desktop.
Simple namespaced Pub/Sub coffee class to use as extendable module for NodeJS and the browser.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# # PubSub | |
# | |
# Is a small helper to simply realize a pub/sub pattern to a coffee class. | |
# | |
# A namespaceing of the topics is also included. | |
# This means you can subscribe to `a` and also get the `a.b`. But if you subscribe to `a.b` you will not get a `a`. | |
# | |
# **required module**: `underscore` | |
# | |
class PubSub | |
# **_ps_handles** *Object* The handle store. It stores the handles unter each topic as array | |
_ps_handles: {} | |
# **_ps_count** *Number* Small helper to stop if no subscribers are listening | |
_ps_count: 0 | |
# **ps_delimiter** *String* Namespace delimiter String. You can change this to your prefered delimiter | |
ps_delimiter: "." | |
### | |
## subscribe | |
`pubsub.subscribe( topic, handle )` | |
subscribe to a topic | |
@param { String } topic A Topic you want to subscribe. It can be namespaced. The namesapce delimiter can be defined by the var `ps_delimiter` | |
@param { Function } handle The handle function wich will be called by a `publish` | |
@api public | |
### | |
subscribe: ( topic, handle )=> | |
# just for a fast exit if no subscribers exists | |
@_ps_count++ | |
# fire change | |
@listenerCountChanged( @_ps_count ) | |
# save the handle to the handle store | |
@_ps_handles[ topic ] or= [] | |
@_ps_handles[ topic ].push( handle ) | |
return | |
### | |
## unsubscribe | |
`pubsub.unsubscribe( handle )` | |
unsubscribe from a topic | |
@param { Function } handle The same handle used by `subscribe` | |
@api public | |
### | |
unsubscribe: ( handle )=> | |
# just for a fast exit if no subscribers exists | |
@_ps_count-- | |
# fire change | |
@listenerCountChanged( @_ps_count ) | |
# try to find the handle and remove it | |
for topic, _thandles of @_ps_handles | |
if handle in _thandles | |
@_ps_handles[ topic ] = _.without( _thandles, handle ) | |
# cleanup if topic is empty | |
if not @_ps_handles[ topic ].length | |
@_ps_handles = _.omit( @_ps_handles, topic ); | |
break | |
return | |
### | |
## publish | |
`pubsub.publish( topic, data )` | |
publish from a topic | |
@param { String } topic The topic you want to publish. | |
@param { Any } data Additional data to send the the subscriber. | |
@api public | |
### | |
publish: ( topic, data )=> | |
# find the handles and call the handles | |
for handle in @_ps_findHandles( topic ) | |
handle( topic, data ) | |
return | |
### | |
## listenerCount | |
`pubsub.listenerCount( )` | |
Get the count of listeners. Helps you the find out if anyone listens | |
@return { Number } Number of listeners | |
@api public | |
### | |
listenerCount: => | |
@_ps_count | |
### | |
## listenerCountChanged | |
`pubsub.listenerCountChanged( count )` | |
Overridable method fired if a listener subscribes or unsubscribes. Can be used the activate or deactivate something. | |
@param { Number } count New number of listener | |
@api public | |
### | |
listenerCountChanged: ( count )=> | |
return | |
### | |
## _ps_findHandles | |
`pubsub._ps_findHandles( topic )` | |
Find all matching handles of a topic. This also inculdes the use of namespacing | |
@param { String } topic The topic to find the matiching handles | |
@return { Array } An array of handles | |
@api private | |
### | |
_ps_findHandles: ( topic )=> | |
if @_ps_count | |
_keys = _.keys( @_ps_handles ) | |
_matched = [] | |
# loop through all cached topics and check if they matching the topic | |
for _kn in _keys | |
if @_ps_match( _kn.split( @ps_delimiter ), topic.split( @ps_delimiter ) ) | |
_matched = _.union( _matched, @_ps_handles[ _kn ] ) | |
_matched | |
else | |
[] | |
### | |
## _ps_match | |
`pubsub._ps_match( inp, test )` | |
Matching helper to find the handles by namespace. This will be calles recrusive through the depth of the topic namespace | |
@param { Array } inp Array of namespace cache handles to check against | |
@param { Array } test Array of topic namespace to check against `inp` | |
@return { Boolean } First `inp` level is matching first `test` level. | |
@api private | |
### | |
_ps_match: ( inp = [], test = [] )-> | |
_tk = test[ 0 ] | |
_ik = inp[ 0 ] | |
if test.length and _tk is _ik | |
# if the first level matches return true or if possible go deeper | |
if inp.length > 1 | |
@_ps_match( inp.splice( 1 ), test.splice( 1 ) ) | |
else | |
true | |
else | |
# return false on a mismatch | |
false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment