Permalink
Browse files

first commit.

  • Loading branch information...
0 parents commit 41c36a1cc502cf701f044f2706906063baf7b94d @jed committed Dec 6, 2010
Showing with 197 additions and 0 deletions.
  1. +110 −0 README.md
  2. +53 −0 example.js
  3. +34 −0 index.js
110 README.md
@@ -0,0 +1,110 @@
+# pbsb
+
+pbsb is a tiny javascript function that elegantly merges two common ideas in javascript: getters/setters and publish/subscribe.
+
+## overview
+
+ var endpoint = new pbsb // create
+
+ endpoint.set( value ) // set/publish
+ endpoint.get( callback ) // get/subscribe
+ endpoint( valueOrCallback ) // infer get/set by argument
+
+## description
+
+a pbsb endpoint consists of:
+
+1. a `get` function, which can be called to retrieve the endpoint's current value and optionally subscribe to subsequent updates, and
+
+2. a `set` function, which sets the endpoint's value and notifies all of the current subscribers.
+
+## features
+
+- simple: pbsb unifies the getting/setting and publish/subscribe paradigms into one asynchronous function.
+
+- tiny: currently only 210 closure'd bytes, pbsb is suitable for use as an embeddable building block in larger pub/sub implementations.
+
+- functional: `get` and `set` are functions, not methods, which means they can be passed into other callback chains without binding.
+
+- clean: pbsb's API facilitates the creation of endpoints that automatically subscribe to other endpoints, to keep logic cleanly separated.
+
+- terse: subscribers can return a function upon callback to renew their subscription, avoiding awkward `unbind`/`unsubscribe` methods.
+
+- optionally sweet: when called without an upstream setter, pbsb returns a single function that infers getting/setting by argument type.
+
+- sync-compatible: initial subscriber callbacks are async but blocking, so an endpoint's current value can be obtained without leaving the current context.
+
+## API
+
+create an endpoint:
+
+ var endpoint = new pbsb
+
+create an endpoint with an initial value:
+
+ var endpoint = pbsb( value ) // if typeof val != "function"
+
+set the endpoint's value:
+
+ endpoint.set( value )
+
+get the endpoint's current value:
+
+ endpoint.get( function( value ) {
+ // do something with value
+ })
+
+let pbsb figure out if you want to get or set:
+
+ var log = function( x ){ console.log( x ) }
+ var val = "this is not a function"
+
+ endpoint( val ) // typeof val != "function", so endpoint.set( val )
+ endpoint( log ) // typeof val == "function", so endpoint.get( val )
+
+get the endpoint's current value AND subscribe to updates:
+
+ endpoint.get( function listener( value ) {
+ // do something with value
+ return listener
+ })
+
+get the endpoint's current value AND subscribe to updates for the next hour:
+
+ var expires = +new Date + 60 * 60 * 1000
+ endpoint.get( function listener( value ) {
+ // do something with value
+ if ( expires > new Date ) return listener
+ })
+
+create an endpoint's getter and callback with its setter:
+
+ var get = pbsb( function( set ) {
+ // protip: for best results, chain endpoints by
+ // passing set as the getter for another endpoint!
+ })
+
+see the included example for ideas about how endpoints can be chained.
+
+## license
+
+copyright (c) 2010 [jed schmidt](http://jedschmidt.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,53 @@
+/*
+ this is a silly binary clock example to show how
+ pbsb endpoints can be chained.
+
+ output looks like this:
+
+ Mon, 06 Dec 2010 05:06:52 GMT
+ 1001100111111000110111101101100
+ ☃☃☃☃☃☃☃☃☃☃☃☃
+
+ Mon, 06 Dec 2010 05:06:53 GMT
+ 1001100111111000110111101101101
+ ☃☃☃☃☃☃☃☃☃☃☃
+
+ Mon, 06 Dec 2010 05:06:54 GMT
+ 1001100111111000110111101101110
+ ☃☃☃☃☃☃☃☃☃☃☃
+
+ ...
+
+*/
+
+pbsb = require( "./" ).pbsb
+
+function log( msg ){ return console.log( msg ), log }
+
+// a pbsb date endpoint
+clock = pbsb( new Date )
+
+// updated every second
+setInterval( function(){ clock.set( new Date ) }, 1000 )
+
+// a binary clock that subscribes to the date
+binaryClock = pbsb( function( cb ) {
+ clock.get( function fn( val ) {
+ return cb( ( val / 1000 | 0 ).toString( 2 ) ), fn
+ })
+})
+
+// a fancier clock that subscribes to the binary clock
+fancyBinaryClock = pbsb( function( cb ) {
+ binaryClock( function fn( val ) {
+ return cb( val.replace( /0/g, "" ).replace( /1/g, "" ) ), fn
+ })
+})
+
+// same as clock.get( log ). `clock` is a getter/setter, but
+// pbsb infers getting because typeof log == "function".
+clock( log )
+
+// `binaryClock` and `fancyBinaryClock` are getters, and can be called as is.
+binaryClock( log )
+fancyBinaryClock( log )
@@ -0,0 +1,34 @@
+this.pbsb = function( arg ) {
+ var subs = [], count = 0, value, source, getset
+
+ function get( sub ) {
+ count || source && source( set )
+ if ( sub = sub( value ) ) subs[ count++ ] = sub
+ }
+
+ function set( val ) {
+ var i = 0, l = count, sub, resubs = []
+
+ for ( count = 0; i < l; i++ ) {
+ if ( sub = subs[ i ]( val ) ) resubs[ count++ ] = sub
+ }
+
+ subs = resubs
+ value = val
+
+ return count && set
+ }
+
+ if ( arg && arg.call && arg.apply ) return source = arg, get
+
+ getset = function( arg ) {
+ ( arg && arg.call && arg.apply ? get : set ).apply( this, arguments )
+ }
+
+ getset.get = get
+ getset.set = set
+
+ value = arg
+
+ return getset
+}

0 comments on commit 41c36a1

Please sign in to comment.