├── .gitignore
├── .travis.yml
├── README.md
├── example.html
├── example.js
├── kebab-min.js
├── kebab.js
├── package.json
└── test
└── kebab.js
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | node_modules
15 | npm-debug.log
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.6
4 | - 0.8
5 | - 0.9
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kebab [](http://travis-ci.org/thlorenz/kebab)
2 |
3 | Half queue half pubsub. Super small (< 30 loc) and simple queue that supports subscribers.
4 |
5 | ```javascript
6 | var kebab = require('kebab')
7 | , kb = kebab()
8 | , items = 10
9 | , consumers = 4;
10 |
11 | function produce () {
12 | var id = --items;
13 |
14 | if (id) {
15 | setTimeout(function () {
16 | console.log('Producer enqueueing item %d', id);
17 | kb.enqueue({ now: new Date() }, id);
18 | produce();
19 | }, 50);
20 | }
21 | }
22 |
23 | function consume (num) {
24 | kb.once(function (info, id) {
25 | console.log( 'Consumer %s handling item %d produced at (%ds:%dms).'
26 | , num, id, info.now.getSeconds(), info.now.getMilliseconds());
27 |
28 | // younger consumers are lazy and therefore only consume once
29 | if (num > 1) setTimeout(function () { consume(num); }, 180);
30 | });
31 | }
32 |
33 | for (var i = 0; i < consumers; i++) consume(i);
34 |
35 | produce();
36 | ```
37 |
38 | Outputs:
39 |
40 | Producer enqueueing item 9
41 | Consumer 0 handling item 9 at (3s:879ms).
42 | Producer enqueueing item 8
43 | Consumer 1 handling item 8 at (3s:942ms).
44 | Producer enqueueing item 7
45 | Consumer 2 handling item 7 at (3s:995ms).
46 | Producer enqueueing item 6
47 | Consumer 3 handling item 6 at (4s:48ms).
48 | Producer enqueueing item 5
49 | Producer enqueueing item 4
50 | Consumer 2 handling item 5 at (4s:99ms).
51 | Producer enqueueing item 3
52 | Consumer 3 handling item 4 at (4s:150ms).
53 | Producer enqueueing item 2
54 | Producer enqueueing item 1
55 | Consumer 2 handling item 3 at (4s:202ms).
56 | Consumer 3 handling item 2 at (4s:252ms).
57 | Consumer 2 handling item 1 at (4s:303ms).
58 |
59 | ## Install
60 |
61 | `npm install kebab`
62 |
63 | ## Run Tests
64 |
65 | `npm test`
66 |
67 | ## Run example
68 |
69 | ### With nodejs
70 |
71 | `npm run-script example`
72 |
73 | ### In the Browser
74 |
75 | `open example.html`
76 |
77 | ## Features
78 |
79 | - works server side
80 | - works in the browser
81 | - supports async module loaders like requirejs
82 |
83 | ## API
84 |
85 | ### create a kebab
86 |
87 | ```javascript
88 | var kebab = require('kebab')
89 | , kb = kebab();
90 | ```
91 |
92 | ### enqueue
93 |
94 | ***kebab.enqueue(arg1 [, arg2, .., argn])***
95 |
96 | arg1 .. argn are the arguments you want to pass when a subscriber callback is called.
97 |
98 | **Example:**
99 |
100 | ```javascript
101 | kb.enqueue(1, 'hello world');
102 | ```
103 |
104 | ### once
105 |
106 | ***kebab.once(callback)***
107 |
108 | Subscribe to be called back with queued arguments.
109 |
110 | If queue is currently holding arguments, callback will be invoked with them immediately.
111 |
112 | Otherwise the callback will be invoked one time when arguments are enqueued in the future.
113 |
114 | **Example:**
115 |
116 | ```javascript
117 | kb.once(function (num, s) { console.log('working on num: %s - %s', num, s); });
118 | ```
119 |
--------------------------------------------------------------------------------
/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Kebab Producer/Consumer Example
6 |
7 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
1 | var kebab = require('./')
2 | , kb = kebab()
3 | , items = 10
4 | , consumers = 4
5 | ;
6 |
7 | function produce () {
8 | var id = --items;
9 |
10 | if (id) {
11 | setTimeout(function () {
12 | console.log('Producer enqueueing item %d', id);
13 | kb.enqueue({ now: new Date() }, id);
14 | produce();
15 | }, 50);
16 | }
17 |
18 | }
19 |
20 | function consume (num) {
21 | kb.once(function (info, id) {
22 | console.log(
23 | 'Consumer %s handling item %d produced at (%ds:%dms).'
24 | , num, id, info.now.getSeconds(), info.now.getMilliseconds()
25 | );
26 |
27 | // younger consumers are lazy and therefore only consume once
28 | if (num > 1) {
29 | // heavy work going on
30 | setTimeout(function () { consume(num); }, 180);
31 | }
32 | });
33 | }
34 |
35 | for (var i = 0; i < consumers; i++)
36 | consume(i);
37 |
38 | produce();
39 |
--------------------------------------------------------------------------------
/kebab-min.js:
--------------------------------------------------------------------------------
1 | (function(){function t(){var t=[],n=[];return{enqueue:function(){t.push(e.call(arguments));var r=n.shift();r&&r.apply(this,t.shift())},once:function(e){var r=t.shift();return r?e.apply(this,r):n.push(e)}}}var e=Array.prototype.slice;typeof define=="function"&&define.amd?define(function(){return t}):typeof window=="object"?window.kebab=t:typeof module=="object"&&typeof module.exports=="object"&&(module.exports=t)})();
--------------------------------------------------------------------------------
/kebab.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var slice = Array.prototype.slice;
3 |
4 | function kebab() {
5 | var queue = []
6 | , subscriptions = [];
7 |
8 | return {
9 | enqueue : function () {
10 | queue.push(slice.call(arguments));
11 | var sub = subscriptions.shift();
12 | if (sub) sub.apply(this, queue.shift());
13 | }
14 | , once : function (cb) {
15 | var args = queue.shift();
16 | return args ? cb.apply(this, args) : subscriptions.push(cb);
17 | }
18 | };
19 | }
20 |
21 | if (typeof define === 'function' && define.amd) {
22 | define(function () { return kebab; });
23 | } else if (typeof window === 'object') {
24 | window.kebab = kebab;
25 | } else if (typeof module === 'object' && typeof module.exports === 'object') {
26 | module.exports = kebab;
27 | }
28 | })();
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kebab",
3 | "version": "0.0.3",
4 | "description": "Half queue half pubsub. Super small (< 30 loc) and simple queue that supports subscribers.",
5 | "main": "kebab.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "scripts": {
10 | "test": "tap ./test/*.js",
11 | "example": "node example"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git://github.com/thlorenz/kebab.git"
16 | },
17 | "keywords": [
18 | "pubsub",
19 | "queue",
20 | "micro",
21 | "small",
22 | "simple"
23 | ],
24 | "author": "Thorsten Lorenz",
25 | "license": "BSD",
26 | "devDependencies": {
27 | "tap": "~0.3.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/kebab.js:
--------------------------------------------------------------------------------
1 | /*jshint asi:true*/
2 |
3 | var kebab = require('..')
4 | , test = require('tap').test;
5 |
6 | function setup () {
7 | kb = kebab();
8 | }
9 |
10 | test('when an item is in the queue', function (t) {
11 | setup();
12 | t.plan(1);
13 |
14 | kb.enqueue('uno');
15 |
16 | t.test('# once calls back immediately with that item', function (t) {
17 | t.plan(1);
18 | kb.once(function (item) {
19 | t.equal('uno', item);
20 | t.end();
21 | })
22 | })
23 | })
24 |
25 | test('when no item is in the queue', function (t) {
26 | setup();
27 | t.plan(1);
28 |
29 | t.test('# and I listen once', function (t) {
30 | var calledBack = false;
31 |
32 | t.plan(1);
33 |
34 | kb.once(function (item) {
35 | calledBack = true;
36 | })
37 |
38 | setTimeout(function () {
39 | t.equal(false, calledBack, 'does not immediately call back');
40 | t.end();
41 | }, 10);
42 | })
43 | })
44 |
45 | test('when no item is in the queue', function (t) {
46 | setup();
47 | t.plan(1);
48 |
49 | t.test('# and I listen once', function (t) {
50 | var calledBack = false
51 | , calledWith;
52 |
53 | t.plan(1);
54 |
55 | kb.once(function (item) {
56 | calledBack = true;
57 | calledWith = item;
58 | })
59 |
60 | t.test('# # and enqueue an item after', function (t) {
61 | t.plan(3);
62 |
63 | kb.enqueue('uno');
64 |
65 | t.equal(calledBack, true, 'calls back');
66 | t.equal('uno', calledWith, 'with queued item');
67 |
68 | t.test('# # # and enqueue another item after', function (t) {
69 | t.plan(2);
70 |
71 | calledBack = false;
72 | kb.enqueue('dos');
73 |
74 | t.equal(calledBack, false, 'does not call back again');
75 |
76 | t.test('# # # # and I listen once again', function (t) {
77 | t.plan(1);
78 |
79 | kb.once(function (item) {
80 | t.equal('dos', item, 'calls back with the other item');
81 | t.end();
82 | })
83 | })
84 | })
85 | })
86 | })
87 | })
88 |
89 | test('when I queue multiple arguments', function (t) {
90 | setup();
91 | kb.enqueue(1, 2, 'foo', { uno: 'eins' });
92 |
93 | t.test('and I listen once', function (t) {
94 | t.plan(4);
95 |
96 | kb.once(function ($1, $2, foo, unoeins) {
97 | t.equal($1, 1, 'passes first number');
98 | t.equal($2, 2, 'passes second number');
99 | t.equal(foo, 'foo', 'passes string');
100 | t.deepEqual(unoeins, { uno: 'eins' }, 'passes object');
101 | t.end();
102 | })
103 | })
104 | })
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------