react 0.5.0 → 0.5.1

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/README.md CHANGED
@@ -35,7 +35,7 @@ It takes inspiration from several projects including:
35
35
  - object instance method calls
36
36
  - class method calls
37
37
  - selectFirst flow where the first task that returns defined, non-null value is used
38
- - promise style functions - also automatic resolution of promise inputs (optional require('react/promise-resolve');)
38
+ - promise style functions - also automatic resolution of promise inputs (optionally loaded with `react.resolvePromises();`)
39
39
  - use of resulting flow function as callback style or promise style (if no callback provided) (provided via plugin corresponding to the promise library used) See https://github.com/jeffbski/react-deferred
40
40
  - (planned) iteration on arrays, streams, sockets
41
41
  - (planned) event emitter integration
@@ -182,7 +182,7 @@ See the [Advanced React](https://github.com/jeffbski/react/blob/master/doc/advan
182
182
 
183
183
  ## Status
184
184
 
185
- - 2012-01-18 - Remove old DSL interfaces, improve plugin loading (v0.5.0)
185
+ - 2012-01-18 - Remove old DSL interfaces, improve plugin loading, log flow name with task name, ast.defined event, test with node 0.7.0 (v0.5.1)
186
186
  - 2012-01-17 - Additional documentation (v0.3.5)
187
187
  - 2012-01-16 - Refine events and create logging plugin (v0.3.3)
188
188
  - 2012-01-13 - Add promise tasks, promise resolution, refactor alternate DSL interfaces as optional requires (v0.3.0)
@@ -194,12 +194,12 @@ See the [Advanced React](https://github.com/jeffbski/react/blob/master/doc/advan
194
194
  ## Test Results
195
195
 
196
196
  ```bash
197
- ok ast.test.js .................... 10/10
197
+ ok ast.test.js .................... 15/15
198
198
  ok cb-task.test.js ................ 31/31
199
199
  ok core-deferred.test.js .......... 11/11
200
200
  ok core-promised.test.js .......... 11/11
201
201
  ok core-when.test.js ................ 6/6
202
- ok core.test.js ................. 104/104
202
+ ok core.test.js ................. 108/108
203
203
  ok dsl.test.js .................... 70/70
204
204
  ok event-manager.test.js .......... 13/13
205
205
  ok exec-options.test.js ............. 3/3
@@ -213,7 +213,7 @@ ok validate-cb-task.test.js ......... 6/6
213
213
  ok validate-ret-task.test.js ........ 7/7
214
214
  ok validate.test.js ............... 31/31
215
215
  ok vcon.test.js ................... 55/55
216
- total ........................... 457/457
216
+ total ........................... 466/466
217
217
 
218
218
  ok
219
219
  ```
package/doc/advanced.md CHANGED
@@ -133,6 +133,7 @@ react.trackTasks(); // turn on flow and task tracking events
133
133
 
134
134
  Available Events that can be consumed
135
135
 
136
+ - ast.defined - ast was defined (receives the ast)
136
137
  - flow.begin - flow execution has started (receives a flow env)
137
138
  - flow.complete - flow execution has successfully completed (receives a flow env)
138
139
  - flow.errored - flow execution has errored (receives a flow env)
@@ -159,3 +160,7 @@ collector.capture(flowFn, 'flow.*'); // add capture flow events on a flow
159
160
  var events = collector.list(); // retrieve the list of events
160
161
  collector.clear(); // clear the list of events;
161
162
  ```
163
+
164
+ ### External Plugins
165
+
166
+ - https://github.com/jeffbski/react-deferred - integrates jQuery style Deferred/Promises with react, providing automatic promise resolution and optional usage for react functions where by calling without a callback returns a promise.
File without changes
File without changes
@@ -1,5 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ Advanced example using the AST directly which most users will not do.
5
+ For general use, see other examples like simple.js
6
+ */
3
7
  var react = require('../'); // require('react');
4
8
 
5
9
  function load(res, cb) { setTimeout(cb, 100, null, res + '-loaded'); }
package/lib/core.js CHANGED
@@ -10,6 +10,7 @@ var VContext = require('./vcon.js');
10
10
  var EventManager = require('./event-manager.js');
11
11
  var inputParser = require('./input-parser.js');
12
12
  var idGenerator = require('./id.js');
13
+ var sprintf = require('sprintf').sprintf;
13
14
 
14
15
  var reactOptions = {
15
16
  stackTraceLimitMin: 30
@@ -27,6 +28,13 @@ function mergeOptions(parsedOptions) {
27
28
  }, parsedOptions);
28
29
  }
29
30
 
31
+ /**
32
+ generate a flow name when one is not provided
33
+ */
34
+ function generateFlowName() {
35
+ return sprintf('flow_%s', idGenerator.createUniqueId());
36
+ }
37
+
30
38
  /**
31
39
  Creates react function which the AST can be manipulated and then
32
40
  is ready to be executed. Can be used directly or a DSL can wrap this
@@ -64,13 +72,17 @@ function reactFactory() {
64
72
  function setAndValidateAST(newAST) { //set AST then validate, ret error[]
65
73
  Object.keys(newAST).forEach(function (k) { ast[k] = newAST[k]; }); // copy all properties
66
74
  var errors = validate(ast);
67
- if (!errors.length) tskutil.nameTasks(ast.tasks); //run this so names can be checked in ast
75
+ if (!errors.length) {
76
+ if (!ast.name) ast.name = generateFlowName();
77
+ tskutil.nameTasks(ast.tasks); //run this so names can be checked in ast
78
+ }
68
79
  if (Object.freeze) { //lets freeze the AST so plugin writers don't accidentally manip the ast
69
80
  Object.keys(newAST).forEach(function (k) {
70
81
  if (typeof(newAST[k]) === 'object') Object.freeze(newAST[k]);
71
82
  });
72
83
  Object.freeze(newAST);
73
84
  }
85
+ flowEmitter.emit(EventManager.TYPES.AST_DEFINED, ast);
74
86
  return errors;
75
87
  }
76
88
 
@@ -3,6 +3,7 @@
3
3
  var react = require('../'); // require('react');
4
4
  react.trackTasks(); // enable task tracking
5
5
 
6
+ var AST_EVENTS_RE = /^ast\./;
6
7
  var TASK_EVENTS_RE = /^task\./;
7
8
  var FLOW_EVENTS_RE = /^flow\./;
8
9
 
@@ -48,6 +49,8 @@ EventCollector.prototype.capture = function (flowFn, eventId) {
48
49
  eventObject.env = obj;
49
50
  } else if (TASK_EVENTS_RE.test(this.event)) {
50
51
  eventObject.task = obj;
52
+ } else if (AST_EVENTS_RE.test(this.event)) {
53
+ eventObject.ast = obj;
51
54
  }
52
55
  self.events.push(eventObject);
53
56
  }
@@ -10,6 +10,7 @@ var EVENT_EMITTER2_CONFIG = {
10
10
 
11
11
  var TYPES = {
12
12
  // Flow monitoring events and their params
13
+ AST_DEFINED: 'ast.defined', // ast
13
14
  FLOW_BEGIN: 'flow.begin', // env
14
15
  TASK_BEGIN: 'task.begin', // task
15
16
  TASK_COMPLETE: 'task.complete', // task
package/lib/id.js CHANGED
@@ -4,6 +4,7 @@ var startingId = 0;
4
4
 
5
5
  function createUniqueId() {
6
6
  startingId += 1;
7
+ if (startingId === Number.MAX_VALUE) startingId = 0; // if hits this start over //TODO need something better?
7
8
  return startingId;
8
9
  }
9
10
 
package/lib/log-events.js CHANGED
@@ -45,12 +45,12 @@ function taskLog(obj) {
45
45
  var eventTimeStr = time.toISOString();
46
46
  if (this.event === 'task.complete') {
47
47
  var task = obj;
48
- console.error('%s: %s \tmsecs: %s \n\targs: %s \n\tresults: %s\n',
49
- this.event, task.name, task.elapsedTime, util.inspect(argsNoCb), util.inspect(task.results));
48
+ console.error('%s: %s:%s \tmsecs: %s \n\targs: %s \n\tresults: %s\n',
49
+ this.event, task.env.name, task.name, task.elapsedTime, util.inspect(argsNoCb), util.inspect(task.results));
50
50
  } else {
51
51
  var name = obj.name;
52
52
  var args = obj.args;
53
- console.error('%s: %s \n\targs: %s\n', this.event, name, util.inspect(argsNoCb));
53
+ console.error('%s: %s:%s \n\targs: %s\n', this.event, obj.env.name, obj.name, util.inspect(argsNoCb));
54
54
  }
55
55
 
56
56
  }
package/lib/task.js CHANGED
@@ -20,6 +20,9 @@ var TASK_TYPES = {
20
20
  promise: PromiseTask,
21
21
  when: WhenTask
22
22
  };
23
+
24
+ var DEFAULT_TASK_NAME = 'task_%s'; // for unnamed tasks use task_idx, like task_0
25
+
23
26
  function taskTypeKeys() { return Object.keys(TASK_TYPES); }
24
27
 
25
28
  var OUT_TASK_TYPES = {
@@ -127,9 +130,10 @@ function validateLocalFunctions(inParams, taskDefs, locals) {
127
130
  }
128
131
 
129
132
  function fName(fn) {
130
- return (fn) ?
131
- ((fn.name) ? fn.name : fn) : // if defined, try name, otherwise toString()
132
- 'undefined'; // not defined, use undefined
133
+ if (typeof(fn) === 'function') {
134
+ return fn.name;
135
+ }
136
+ return (fn) ? fn : '';
133
137
  }
134
138
 
135
139
  /**
@@ -148,6 +152,7 @@ function nameTasks(tasks) { //name tasks that are not already named, validation
148
152
  tasks.forEach(function (t, idx) {
149
153
  if (!t.name) { //not already named
150
154
  var name = fName(t.f);
155
+ if (!name) name = sprintf(DEFAULT_TASK_NAME, idx);
151
156
  if (!name || namesMap[name]) {
152
157
  name = sprintf('%s_%s', name, idx); //if empty or already used, postfix with _idx
153
158
  }
package/lib/vcon.js CHANGED
@@ -71,7 +71,7 @@ VContext.create = function (args, inParams, locals, self) {
71
71
  var vContext = new VContext();
72
72
  vContext.values = args.reduce(function (vcon, x, idx) { // create vCon start with input args
73
73
  var param = inParams[idx];
74
- if (param) vcon[param] = x;
74
+ if (param) vcon[param] = (x !== undefined) ? x : null; // upgrade undefined to null
75
75
  return vcon;
76
76
  }, initValues);
77
77
  return vContext;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react",
3
3
  "description": "React is a javascript module implementing a lightweight rules engine to make it easier to work with asynchronous code, by reducing boilerplate code and improving error and exception handling while allowing variable and task dependencies when defining flow.",
4
- "version": "0.5.0",
4
+ "version": "0.5.1",
5
5
  "author": "Jeff Barczewski <jeff.barczewski@gmail.com>",
6
6
  "repository": { "type": "git", "url": "http://github.com/jeffbski/react.git" },
7
7
  "bugs" : { "url": "http://github.com/jeffbski/react/issues" },
package/test/ast.test.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  var test = require('tap').test;
4
4
 
5
- var react = require('../react');
5
+ var react = require('../'); // require('react');
6
+ var EventCollector = require('../lib/event-collector');
6
7
 
7
8
  function load(res, cb) { cb(null, res + '-loaded'); }
8
9
  function prefix(prefstr, str, cb) { cb(null, prefstr + str); }
@@ -38,6 +39,31 @@ test('mixed', function (t) {
38
39
  });
39
40
  });
40
41
 
42
+ test('ast.defined event called when ast is defined', function (t) {
43
+ var fn = react();
44
+ var collector = new EventCollector();
45
+ collector.capture(fn, 'ast.*');
46
+
47
+ var errors = fn.setAndValidateAST({
48
+ inParams: ['res', 'prefstr', 'poststr'],
49
+ tasks: [
50
+ { f: load, a: ['res'], out: ['lres'] },
51
+ { f: upper, a: ['lres'], out: ['ulres'], type: 'ret' },
52
+ { f: prefix, a: ['prefstr', 'ulres'], out: ['plres'] },
53
+ { f: postfix, a: ['plres', 'poststr'], out: ['plresp'] }
54
+ ],
55
+ outTask: { a: ['plresp'] }
56
+ });
57
+
58
+ var events = collector.list();
59
+ t.equal(events.length, 1);
60
+ t.type(events[0].ast, 'object');
61
+ t.ok(events[0].ast.inParams);
62
+ t.ok(events[0].ast.tasks);
63
+ t.ok(events[0].ast.outTask);
64
+ t.end();
65
+ });
66
+
41
67
  test('cb with err', function (t) {
42
68
  t.plan(5);
43
69
 
package/test/core.test.js CHANGED
@@ -10,6 +10,7 @@ function add(x, y, cb) { cb(null, x + y); }
10
10
  function badFunc(a, b, cb) { throw new Error('badFuncThrow'); }
11
11
  function badF2(a, b, cb) { cb('my-error'); }
12
12
  function fnRetsSum(a, b) { return a + b; }
13
+ var anonFn = function (a, b) { return a + b; };
13
14
 
14
15
  test('set and validate AST', function (t) {
15
16
  var fn = react();
@@ -42,16 +43,19 @@ test('unnamed tasks will be assigned unique names', function (t) {
42
43
  { f: multiply, a: ['a', 'b'], out: ['c'] },
43
44
  { f: multiply, a: ['a', 'b'], out: ['d'], name: 'multiply' },
44
45
  { f: multiply, a: ['a', 'b'], out: ['e'], name: 'times' },
46
+ { f: anonFn, a: ['a', 'b'], out: ['g'], type: 'ret' },
45
47
  { f: multiply, a: ['a', 'b'], out: ['f'] }
46
48
  ],
47
49
  outTask: { a: ['c'] }
48
50
  });
49
51
  t.deepEqual(errors, [], 'should set and validate as true');
52
+ t.equal(fn.ast.name.slice(0, 'flow_'.length), 'flow_', 'generated flow name should start with flow_');
50
53
  t.deepEqual(fn.ast.tasks, [
51
54
  { f: multiply, a: ['a', 'b'], out: ['c'], type: 'cb', name: 'multiply_0' },
52
55
  { f: multiply, a: ['a', 'b'], out: ['d'], name: 'multiply', type: 'cb' },
53
56
  { f: multiply, a: ['a', 'b'], out: ['e'], name: 'times', type: 'cb' },
54
- { f: multiply, a: ['a', 'b'], out: ['f'], type: 'cb', name: 'multiply_3' }
57
+ { f: anonFn, a: ['a', 'b'], out: ['g'], type: 'ret', name: 'task_3' },
58
+ { f: multiply, a: ['a', 'b'], out: ['f'], type: 'cb', name: 'multiply_4' }
55
59
  ]);
56
60
  t.end();
57
61
  });
@@ -431,6 +435,27 @@ test('using "this" in a sync function', function (t) {
431
435
  }]);
432
436
  });
433
437
 
438
+ test('undefined input arguments will be upgraded from undefined to null', function (t) {
439
+ var fn = react();
440
+ function concat(a, b) {
441
+ return '' + a + b;
442
+ }
443
+ var errors = fn.setAndValidateAST({
444
+ inParams: ['a', 'b'],
445
+ tasks: [
446
+ { f: concat, a: ['a', 'b'], out: ['c'], type: 'ret' }
447
+ ],
448
+ outTask: { a: ['c'] }
449
+ });
450
+ t.deepEqual(errors, [], 'no validation errors');
451
+ fn('first', undefined, function (err, c) { // undefined second param, upgrade to null
452
+ t.equal(err, null);
453
+ t.equal(c, 'firstnull');
454
+ t.end();
455
+ });
456
+ });
457
+
458
+
434
459
 
435
460
  // Select first tests
436
461
 
package/test/dsl.test.js CHANGED
@@ -16,7 +16,7 @@ test('module exports is a fn with properties', function (t) {
16
16
 
17
17
  test('no arguments -> empty name, inParams, tasks, outTask', function (t) {
18
18
  var r = react();
19
- t.equal(r.ast.name, undefined);
19
+ t.equal(r.ast.name.slice(0, 'flow_'.length), 'flow_', 'generated flow name should start with flow_');
20
20
  t.deepEqual(r.ast.inParams, []);
21
21
  t.deepEqual(r.ast.tasks, []);
22
22
  t.deepEqual(r.ast.outTask, { a: [], type: 'finalcb' });
@@ -26,7 +26,7 @@ test('no arguments -> empty name, inParams, tasks, outTask', function (t) {
26
26
 
27
27
  test('empty first string -> empty name, inParams, tasks, outTask', function (t) {
28
28
  var r = react('');
29
- t.equal(r.ast.name, '');
29
+ t.equal(r.ast.name.slice(0, 'flow_'.length), 'flow_', 'generated flow name should start with flow_');
30
30
  t.deepEqual(r.ast.inParams, []);
31
31
  t.deepEqual(r.ast.tasks, []);
32
32
  t.deepEqual(r.ast.outTask, { a: [], type: 'finalcb' });