jam 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Makefile DELETED
@@ -1,67 +0,0 @@
1
-
2
- BIN := $(shell pwd)/node_modules/.bin
3
-
4
- GLOBALS := __coverage__,buffertools,SlowBuffer,events,util,task
5
- TEST_ENV := test
6
-
7
- # Project files definition
8
- TEST_FILES := $(wildcard test/**/*.js) $(wildcard test/*.js)
9
- LIB_FILES := $(wildcard lib/**/*.js) $(wildcard lib/*.js)
10
- COV_FILES := $(LIB_FILES:lib/%.js=lib-cov/%.js)
11
-
12
- INDEX_FILE = index.js
13
- MAIN_FILE = lib/jam.js
14
-
15
- # Test parameters so we can configure these via make
16
- TEST_TIMEOUT = 100
17
- TEST_REPORTER = list
18
- TDD_REPORTER = min
19
- COVER_REPORTER = mocha-istanbul
20
-
21
- # Command-line tools options
22
- MOCHA_OPTS = --bail --timeout $(TEST_TIMEOUT) --reporter $(TEST_REPORTER) --globals $(GLOBALS)
23
- MOCHA_TDD_OPTS = $(MOCHA_OPTS) --watch --reporter $(TDD_REPORTER)
24
- MOCHA_COVER_OPTS = $(MOCHA_OPTS) --reporter $(COVER_REPORTER)
25
- ISTANBUL_OPTS = instrument --variable global.__coverage__ --no-compact
26
- PLATO_OPTS = -d html-report/
27
- GROC_OPTS = -t lib/ -o doc/ --no-whitespace-after-token false --index $(MAIN_FILE)
28
-
29
-
30
- default: node_modules
31
-
32
- node_modules:
33
- npm install
34
-
35
- # File transformations
36
- lib-cov/%.js: lib/%.js
37
- @mkdir -p $(@D)
38
- $(BIN)/istanbul $(ISTANBUL_OPTS) --output $@ $<
39
-
40
-
41
- # Testing
42
- test: node_modules
43
- NODE_ENV=$(TEST_ENV) $(BIN)/mocha $(MOCHA_OPTS) $(TEST_FILES)
44
- tdd: node_modules
45
- NODE_ENV=$(TEST_ENV) $(BIN)/mocha $(MOCHA_TDD_OPTS) $(TEST_FILES)
46
-
47
-
48
- # Code instrumentation
49
- instrument: node_modules $(COV_FILES)
50
- cover: instrument
51
- NODE_ENV=$(TEST_ENV) JAM_COVER=1 $(BIN)/mocha $(MOCHA_COVER_OPTS) $(TEST_FILES)
52
- complex:
53
- $(BIN)/plato $(PLATO_OPTS) $(LIB_FILES)
54
-
55
- doc:
56
- $(BIN)/groc $(GROC_OPTS) $(LIB_FILES)
57
-
58
-
59
- # Cleans
60
- clean:
61
- -rm -Rf lib-cov/
62
- -rm -Rf html-report/
63
- -rm -Rf doc/
64
-
65
-
66
- .PHONY: debug default test tdd clean doc doc-gh instrument cover complex
67
-
package/example/file1.txt DELETED
@@ -1 +0,0 @@
1
- a - First! I am the very very first file.
package/example/file2.txt DELETED
@@ -1 +0,0 @@
1
- b - I am the second file, residing in B. 2nd's not a bad place, ain't it?
package/example/file3.txt DELETED
@@ -1 +0,0 @@
1
- c - I'm the last one. I get to write the ending!
package/example/map.js DELETED
@@ -1,29 +0,0 @@
1
-
2
- var FILES = 'file1.txt,file2.txt,file3.txt'.split(',')
3
- , jam = require('../lib/jam')
4
- , fs = require('fs');
5
-
6
- // normal form
7
- var readFile = function(next, filename) { fs.readFile(filename, next); }
8
- , catResult = function(next, result) {
9
- process.stdout.write(result.join(''));
10
- next();
11
- };
12
-
13
- function normal(next) {
14
- console.log("NORMAL FORM ::");
15
- jam(jam.map(FILES, readFile))
16
- (catResult)
17
- (next);
18
- }
19
-
20
- function monad(next) {
21
- console.log("MONAD FORM ::");
22
- jam(jam.return(FILES))
23
- (jam.map(readFile))
24
- (catResult)
25
- (next);
26
- }
27
-
28
- jam(normal)(monad)(function(e) { if (e) console.error(e); });
29
-
@@ -1,21 +0,0 @@
1
-
2
- var FILES = 'file1.txt,file2.txt,file3.txt'.split(',')
3
- , jam = require('../lib/jam')
4
- , fs = require('fs');
5
-
6
- var chain = jam(jam.identity);
7
-
8
- FILES.forEach(function(filename) {
9
- fs.readFile(filename, chain.promise());
10
-
11
- chain(function(next, result) {
12
- console.log("FILE: " + filename);
13
- console.log(result.toString());
14
- next();
15
- });
16
- });
17
-
18
- chain(function(e) {
19
- console.log("DONE.");
20
- });
21
-
package/index.js DELETED
@@ -1,6 +0,0 @@
1
-
2
- // index.js - Main application entrypoint
3
- module.exports = process.env.JAM_COVER ?
4
- require('./lib-cov/jam') :
5
- require('./lib/jam');
6
-
package/lib/jam.js DELETED
@@ -1,333 +0,0 @@
1
-
2
- // lib/jam.js - Main JAM entrypoint
3
- module.exports = (function() {
4
-
5
- var assert = require('assert'), tick = null;
6
-
7
- // Find out if we have setImmediate and fallback to setTimeout if necessary.
8
- tick = typeof setImmediate === 'function' ?
9
- setImmediate :
10
- function(func) { setTimeout(func, 0); };
11
-
12
- // # INTERNAL HELPERS
13
-
14
- // Function and arguments helpers.
15
- var toArgs = function(args) { return Array.prototype.slice.call(args); };
16
-
17
- function replaceHead(args, newHead) {
18
- args = toArgs(args);
19
- if (!args.length) return [newHead];
20
-
21
- args[0] = newHead;
22
- return args;
23
- }
24
-
25
- function bind(func, context) {
26
- return function() { return func.apply(context, arguments); };
27
- }
28
-
29
- // Common assertions
30
- function ensureFunc(func, argName) {
31
- assert(typeof func === 'function', argName + ' argument missing or not a function');
32
- };
33
-
34
- function ensureNum(num, argName) {
35
- assert(typeof num === 'number', argName + ' argument missing or not a number');
36
- };
37
-
38
- function ensureArray(arr, argName) {
39
- assert(arr && typeof arr === 'object' && typeof arr.length === 'number',
40
- argName + ' argument missing or does not looks like an array');
41
- };
42
-
43
- // ---
44
-
45
- // # HELPERS
46
-
47
- // Additional functions that adds to the original jam function.
48
- function includeHelpers(func) {
49
-
50
- // ## jam.identity()
51
-
52
- // Simple function that passes the values it receives to the next function.
53
- // Useful if you need a `process.nextTick` inserted in-between your call chain.
54
- func.identity = function(next) {
55
- function _identity(next) {
56
- var args = arguments;
57
- tick(function() {
58
- next.apply(this, replaceHead(args, null));
59
- });
60
- }
61
-
62
- // This function can also be passed to jam verbatim.
63
- return (typeof next === 'function') ?
64
- _identity.apply(this, arguments) :
65
- _identity;
66
- };
67
-
68
- // ## jam.nextTick()
69
-
70
- // Alias for `.identity`. Use when you need a `process.nextTick` inserted in-between
71
- // your call chain.
72
- func.nextTick = func.identity
73
-
74
- // ## jam.return( [args...] )
75
-
76
- // Returns a set of values to the next function in the chain. Useful when you want to
77
- // pass in the next function verbatim without wrapping it in a `function() { }` just
78
- // to pass values into it.
79
- func.return = function() {
80
- var args = toArgs(arguments);
81
- return function(next) {
82
- args.unshift(null);
83
- next.apply(this, args);
84
- };
85
- };
86
-
87
- // ## jam.null()
88
-
89
- // Similar to `.identity` but absorbs all arguments that has been passed to it and
90
- // forward nothing to the next function. Effectively nullifying any arguments passed
91
- // from previous jam call.
92
- //
93
- // Like `jam.identity`, this function can be passed to the jam chain verbatim.
94
- func.null = function(next) {
95
- function _null(next) { next(); }
96
-
97
- return (typeof next === 'function') ? _null.call(this, next) : _null;
98
- };
99
-
100
- // ## jam.call( function, [args...] )
101
-
102
- // Convenience for calling functions that accepts arguments in standard node.js
103
- // convention. Since jam insert `next` as first argument, most functions cannot be
104
- // passed directly into the jam chain, thus this helper function.
105
- //
106
- // If no `args` is given, this function passes arguments given to `next()` call from
107
- // previous function directly to the function (with proper callback) placement).
108
- //
109
- // Use this in combination with `jam.return` or `jam.null` if you want to control the
110
- // arguments that are passed to the function.
111
- func.call = function(func) {
112
- ensureFunc(func, 'function');
113
-
114
- var args = toArgs(arguments);
115
- args.shift(); // func
116
-
117
- if (args.length) { // use provided arguments
118
- return function(next) {
119
- args.push(next);
120
- func.apply(this, args);
121
- };
122
-
123
- } else { // use passed-in arguments during chain resolution
124
- return function(next) {
125
- args = toArgs(arguments);
126
- args.shift(); // move next to last position
127
- args.push(next);
128
-
129
- func.apply(this, args);
130
- };
131
- }
132
- };
133
-
134
- // ## jam.each( array, iterator( next, element, index ) )
135
-
136
- // Execute the given `iterator` function for each element given in the `array`. The
137
- // iterator is given a `next` function and the element to act on. The next step in the
138
- // chain will receive the original array passed verbatim so you can chain multiple
139
- // `.each` calls to act on the same array.
140
- //
141
- // You can also pass `arguments` and `"strings"` as an array or you can omit the array
142
- // entirely, in which case this method will assume that the previous chain step
143
- // returns something that looks like an array as its first result.
144
- //
145
- // Under the hood, a JAM step is added for each element. So the iterator will be
146
- // called serially, one after another finish. A parallel version maybe added in the
147
- // future.
148
- func.each = function(array, iterator) {
149
- if (typeof array === 'function') {
150
- iterator = array;
151
- array = null
152
- } else {
153
- ensureArray(array, 'array');
154
- }
155
-
156
- ensureFunc(iterator, 'iterator');
157
-
158
- return function(next, array_) {
159
- var arr = array || array_;
160
-
161
- // Builds another JAM chain internally
162
- var chain = jam(jam.identity)
163
- , count = arr.length;
164
-
165
- for (var i = 0; i < count; i++) (function(element, i) {
166
- chain = chain(function(next) { iterator(next, element, i); });
167
- })(arr[i], i);
168
-
169
- chain = chain(function(next) { next(null, arr); });
170
- return chain(next);
171
- };
172
- };
173
-
174
- // ## jam.map( array, iterator( next, element, index ) )
175
-
176
- // Works exactly like the `each` helper but if a value is passed to the iterator's
177
- // `next` function, it is collected into a new array which will be passed to the next
178
- // function in the JAM chain after `map`.
179
- //
180
- // Like with `each`, you can omit the `array` input, in which case this method will
181
- // assume that the previous chain step returns something that looks like an array as
182
- // its first result.
183
- func.map = function(array, iterator) {
184
- if (typeof array === 'function') {
185
- iterator = array;
186
- array = null;
187
- } else {
188
- ensureArray(array, 'array');
189
- }
190
-
191
- ensureFunc(iterator, 'iterator');
192
-
193
- return function(next, array_) {
194
- var arr = array || array_;
195
-
196
- // Builds another JAM chain internally and collect results.
197
- // TODO: Dry with .each?
198
- var chain = jam(jam.identity)
199
- , count = arr.length
200
- , result = [];
201
-
202
- for (var i = 0; i < count; i++) (function(element, i) {
203
- chain = chain(function(next, previous) {
204
- result.push(previous);
205
- iterator(next, element, i);
206
- });
207
- })(arr[i], i);
208
-
209
- chain = chain(function(next, last) {
210
- result.push(last);
211
- result.shift(); // discard first undefined element
212
- next(null, result);
213
- });
214
-
215
- return chain(next);
216
- };
217
- };
218
-
219
- // ## jam.timeout( timeout )
220
-
221
- // Pauses the chain for the specified `timeout` using `setTimeout`. Useful for
222
- // inserting a delay in-between a long jam chain.
223
- func.timeout = function(timeout) {
224
- ensureNum(timeout, 'timeout');
225
-
226
- return function(next) {
227
- var args = replaceHead(arguments, null);
228
- setTimeout(function() { next.apply(this, args); }, timeout);
229
- };
230
- };
231
-
232
- // ## jam.promise( [chain] )
233
-
234
- // Returns a JAM promise, useful when you are starting an asynchronous call outside of
235
- // the JAM chain itself but wants the callback to call into the chain. In other words,
236
- // this allow you to put a 'waiting point' (aka promise?) into existing JAM chain that
237
- // waits for the initial call to finish and also pass any arguments passed to the
238
- // callback to the next step in the JAM chain as well.
239
- //
240
- // This function will returns a callback that automatically bridges into the JAM
241
- // chain. You can pass the returned callback to any asynchronous function and the JAM
242
- // chain (at the point of calling .promise()) will wait for that asynchronous function
243
- // to finish effectively creating a 'waiting point'.
244
- //
245
- // Additionally, any arguments passed to the callback are forwarded to the next call
246
- // in the JAM chain as well. If errors are passed, then it is fast-forwarded to the
247
- // last handler normally like normal JAM steps.
248
- func.promise = function(chain) {
249
- chain = typeof chain === 'function' ? chain : // chain is supplied
250
- typeof this === 'function' ? this : // called from the chain variable
251
- ensureFunc(chain, 'chain'); // fails
252
-
253
- if (typeof chain === 'undefined' && typeof this === 'function') {
254
- chain = this;
255
- }
256
-
257
- var args = null, next = null;
258
-
259
- chain(function(next_) {
260
- if (args) return next_.apply(this, args); // callback already called
261
- next = next_; // wait for callback
262
- });
263
-
264
- return function() {
265
- if (next) return next.apply(this, arguments); // chain promise already called
266
- args = arguments; // wait for chain to call the promise
267
- };
268
- };
269
-
270
- // TODO: noError() ? or absorbError()
271
- return func;
272
- };
273
-
274
- // ---
275
-
276
- // # JAM function
277
-
278
- // Exported function starts the asynchronous call chain.
279
- function jam(func, context) {
280
- ensureFunc(func, 'function');
281
-
282
- var steps = [];
283
-
284
- // ##### Chain resolver.
285
-
286
- // The resolver will execute all functions passed to the chain as soon as `nextTick`.
287
- // Thus jam will not works across async context where the chain is not built all at
288
- // once in a single event loop, which is not really a problem from my personal
289
- // experience.
290
- tick(function resolve(e) {
291
- var args = Array.prototype.slice.call(arguments);
292
-
293
- // Any errors passed to next() are (fast-)forwarded to the last function in the
294
- // chain skipping any functions that's left to be executed.
295
- if (e) return steps[steps.length - 1].apply(this, args);
296
-
297
- // Any parameters given to next() are passed as arguments to the next function in
298
- // the chain (except for errors, of course.)
299
- var next = steps.shift()
300
- , args = Array.prototype.slice.call(arguments)
301
-
302
- if (steps.length) {
303
- args.shift(); // error arg
304
- args.unshift(resolve); // next() function
305
- }
306
-
307
- return next.apply(this, args);
308
- });
309
-
310
- // ##### Chain context continuation.
311
-
312
- // Subsequent invocation of the function returned from the `jam` function simply adds
313
- // the given function to the chain.
314
- function continuable(func, context) {
315
- ensureFunc(func, 'function');
316
-
317
- if (context) { // TODO: Handle falsy things?
318
- func = bind(func, context);
319
- }
320
-
321
- steps.push(func);
322
- return continuable;
323
- };
324
-
325
- return includeHelpers(continuable(func, context));
326
- };
327
-
328
- // ---
329
-
330
- return includeHelpers(jam);
331
-
332
- })();
333
-