Skip to content

Commit

Permalink
v0.1.13
Browse files Browse the repository at this point in the history
* Fixed issue #68 where `matchUntilHalt` uses a lot of CPU
* Fixed issue #45, now compiled rules support `or` constraint with more than 2 inner constraints.
* Added new feature to address #76, now you can use `deleteFlows` to dispose all flows, or use `hasFlow` to check if a flow is already registred with `nools`.
  • Loading branch information
doug-martin committed Sep 24, 2013
1 parent 93edb98 commit 4aadfe6
Show file tree
Hide file tree
Showing 18 changed files with 784 additions and 451 deletions.
2 changes: 1 addition & 1 deletion benchmark/waltzDb/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var data = require("./data"),
nools = require("../../index");

var flow = nools.compile(__dirname + "/waltzDb.nools");
var items = data.load(flow).waltzdb4;
var items = data.load(flow).waltzdb8;
var session = flow.getSession.apply(flow, items);
session.assert(new (flow.getDefined("stage"))({value: "DUPLICATE"}));
var start = new Date();
Expand Down
6 changes: 6 additions & 0 deletions docs/History.html
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@



<h1>0.1.13</h1>
<ul>
<li>Fixed issue <a href="https://github.com/C2FO/nools/issues/68">#68</a> where <code>matchUntilHalt</code> uses a lot of CPU</li>
<li>Fixed issue <a href="https://github.com/C2FO/nools/issues/45">#45</a>, now compiled rules support <code>or</code> constraint with more than 2 inner constraints.</li>
<li>Added new feature to address <a href="https://github.com/C2FO/nools/issues/76">#76</a>, now you can use <code>deleteFlows</code> to dispose all flows, or use <code>hasFlow</code> to check if a flow is already registred with <code>nools</code>.</li>
</ul>
<h1>0.1.12</h1>
<ul>
<li>Fixed issue in node v0.6 where path.sep is not found.</li>
Expand Down
16 changes: 16 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ <h1>Usage</h1>
<li><a href="#firing">Firing</a> </li>
<li><a href="#disposing">Disposing</a></li>
<li><a href="#removing-flow">Removing A Flow</a></li>
<li><a href="#removing-flows">Removing All Flows</a></li>
<li><a href="#checking-for-flow">Checking If A Flow Exists</a></li>
<li><a href="#agenda-groups">Agenda Group</a><ul>
<li><a href="#agenda-groups-focus">Focus</a></li>
<li><a href="#agenda-groups-auto-focus">Auto Focus</a></li>
Expand Down Expand Up @@ -514,6 +516,20 @@ <h1>Removing a flow</h1>
nools.deleteFlow(myFlow); //returns nools for chaining

nools.getFlow(&quot;flow&quot;); //undefined</code></pre>
<p><a name="removing-flows"></a></p>
<h1>Removing All Flows</h1>
<p>To remove all flow from <code>nools</code> use the <code>deleteFlows</code> function.</p>
<pre class='prettyprint linenums lang-js'><code class="lang-javascript">var myFlow = nools.flow(&quot;flow&quot;);

nools.deleteFlows(); //returns nools for chaining

nools.getFlow(&quot;flow&quot;); //undefined</code></pre>
<p><a name="checking-for-flow"></a></p>
<h1>Checking If A Flow Exists</h1>
<p>To check if a flow currently is registering with <code>nools</code> use the <code>hasFlow</code> function;</p>
<pre class='prettyprint linenums lang-js'><code class="lang-javascript">var myFlow = nools.flow(&quot;flow&quot;);

nools.hasFlow(&quot;flow&quot;); //true</code></pre>
<p><a name="agenda-groups"></a></p>
<h2>Agenda Groups</h2>
<p>Agenda groups allow for logical groups of rules within a flow.</p>
Expand Down
16 changes: 8 additions & 8 deletions docs/nools.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/counter/counter.nools
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ rule count {
$ctr: Counter $ctr.count % 1000 == 0 {count: $count}
}
then{
console.log("Imma countin...");
console.log("Imma countin... %d", $count);
modify($ctr, function(){this.count = $count + 1;});
}
}
Expand Down
5 changes: 5 additions & 0 deletions history.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#0.1.13
* Fixed issue [#68](https://github.com/C2FO/nools/issues/68) where `matchUntilHalt` uses a lot of CPU
* Fixed issue [#45](https://github.com/C2FO/nools/issues/45), now compiled rules support `or` constraint with more than 2 inner constraints.
* Added new feature to address [#76](https://github.com/C2FO/nools/issues/76), now you can use `deleteFlows` to dispose all flows, or use `hasFlow` to check if a flow is already registred with `nools`.

# 0.1.12
* Fixed issue in node v0.6 where path.sep is not found.

Expand Down
100 changes: 100 additions & 0 deletions lib/executionStrategy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
var extd = require("./extended"),
Promise = extd.Promise,
nextTick = require("./nextTick"),
isPromiseLike = extd.isPromiseLike;

Promise.extend({
instance: {

looping: false,

constructor: function (flow, matchUntilHalt) {
this._super([]);
this.flow = flow;
this.agenda = flow.agenda;
this.rootNode = flow.rootNode;
this.matchUntilHalt = !!(matchUntilHalt);
extd.bindAll(this, ["onAlter", "callNext"]);
},

halt: function () {
this.__halted = true;
if (!this.looping) {
this.callback();
}
},

onAlter: function () {
this.flowAltered = true;
if (!this.looping && this.matchUntilHalt && !this.__halted) {
this.callNext();
}
},

setup: function () {
var flow = this.flow;
this.rootNode.resetCounter();
flow.on("assert", this.onAlter);
flow.on("modify", this.onAlter);
flow.on("retract", this.onAlter);
},

tearDown: function () {
var flow = this.flow;
flow.removeListener("assert", this.onAlter);
flow.removeListener("modify", this.onAlter);
flow.removeListener("retract", this.onAlter);
},

__handleAsyncNext: function (next) {
var self = this;
return next.addCallback(function () {
self.looping = false;
if (self.flowAltered) {
self.rootNode.incrementCounter();
self.flowAltered = false;
if (!self.__halted) {
self.callNext();
} else {
self.callback();
}
} else if (!self.matchUntilHalt || self.__halted) {
self.callback();
}
self = null;
}).addErrback(this.errback);
},

__handleSyncNext: function (next) {
this.looping = false;
if (this.flowAltered) {
this.rootNode.incrementCounter();
this.flowAltered = false;
}
if (next && !this.__halted) {
nextTick(this.callNext);
} else if (!this.matchUntilHalt || this.__halted) {
this.callback();
}
return next;
},

callback: function () {
this.tearDown();
this._super(arguments);
},


callNext: function () {
this.looping = true;
var next = this.agenda.fireNext();
return isPromiseLike(next) ? this.__handleAsyncNext(next) : this.__handleSyncNext(next);
},

execute: function () {
this.setup();
this.callNext();
return this;
}
}
}).as(module);
98 changes: 98 additions & 0 deletions lib/flow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"use strict";
var extd = require("./extended"),
bind = extd.bind,
declare = extd.declare,
nodes = require("./nodes"),
EventEmitter = require("events").EventEmitter,
wm = require("./workingMemory"),
WorkingMemory = wm.WorkingMemory,
ExecutionStragegy = require("./executionStrategy"),
AgendaTree = require("./agenda");

module.exports = declare(EventEmitter, {

instance: {

name: null,

executionStrategy: null,

constructor: function (name) {
this.env = null;
this.name = name;
this.__rules = {};
this.workingMemory = new WorkingMemory();
this.agenda = new AgendaTree(this);
this.agenda.on("fire", bind(this, "emit", "fire"));
this.agenda.on("focused", bind(this, "emit", "focused"));
this.rootNode = new nodes.RootNode(this.workingMemory, this.agenda);
},

focus: function (focused) {
this.agenda.setFocus(focused);
return this;
},

halt: function () {
var strategy = this.executionStrategy;
if (strategy.matchUntilHalt) {
strategy.halt();
}
return this;
},

dispose: function () {
this.workingMemory.dispose();
this.agenda.dispose();
this.rootNode.dispose();
},

assert: function (fact) {
this.rootNode.assertFact(this.workingMemory.assertFact(fact));
this.emit("assert", fact);
return fact;
},

// This method is called to remove an existing fact from working memory
retract: function (fact) {
//fact = this.workingMemory.getFact(fact);
this.rootNode.retractFact(this.workingMemory.retractFact(fact));
this.emit("retract", fact);
return fact;
},

// This method is called to alter an existing fact. It is essentially a
// retract followed by an assert.
modify: function (fact, cb) {
//fact = this.workingMemory.getFact(fact);
this.rootNode.retractFact(this.workingMemory.retractFact(fact));
if ("function" === typeof cb) {
cb.call(fact, fact);
}
this.emit("modify", fact);
this.rootNode.assertFact(this.workingMemory.assertFact(fact));
return fact;
},

print: function () {
this.rootNode.print();
},

containsRule: function (name) {
return this.rootNode.containsRule(name);
},

rule: function (rule) {
this.rootNode.assertRule(rule);
},

matchUntilHalt: function (cb) {
return (this.executionStrategy = new ExecutionStragegy(this, true)).execute().classic(cb).promise();
},

match: function (cb) {
return (this.executionStrategy = new ExecutionStragegy(this)).execute().classic(cb).promise();
}

}
});
100 changes: 100 additions & 0 deletions lib/flowContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use strict";
var extd = require("./extended"),
instanceOf = extd.instanceOf,
forEach = extd.forEach,
declare = extd.declare,
InitialFact = require("./pattern").InitialFact,
rule = require("./rule"),
Flow = require("./flow");

var flows = {};
var FlowContainer = declare({

instance: {

constructor: function (name, cb) {
this.name = name;
this.cb = cb;
this.__rules = [];
this.__defined = {};
if (cb) {
cb.call(this, this);
}
if (!flows.hasOwnProperty(name)) {
flows[name] = this;
} else {
throw new Error("Flow with " + name + " already defined");
}
},

getDefined: function (name) {
var ret = this.__defined[name.toLowerCase()];
if (!ret) {
throw new Error(name + " flow class is not defined");
}
return ret;
},

addDefined: function (name, cls) {
//normalize
this.__defined[name.toLowerCase()] = cls;
return cls;
},

rule: function () {
this.__rules = this.__rules.concat(rule.createRule.apply(rule, arguments));
return this;
},

getSession: function () {
var flow = new Flow(this.name);
forEach(this.__rules, function (rule) {
flow.rule(rule);
});
flow.assert(new InitialFact());
for (var i = 0, l = arguments.length; i < l; i++) {
flow.assert(arguments[i]);
}
return flow;
},

containsRule: function (name) {
return extd.some(this.__rules, function (rule) {
return rule.name === name;
});
}

},

"static": {
getFlow: function (name) {
return flows[name];
},

hasFlow: function (name) {
return extd.has(flows, name);
},

deleteFlow: function (name) {
if (instanceOf(name, FlowContainer)) {
name = name.name;
}
delete flows[name];
return FlowContainer;
},

deleteFlows: function () {
for (var name in flows) {
if (name in flows) {
delete flows[name];
}
}
return FlowContainer;
},

create: function (name, cb) {
return new FlowContainer(name, cb);
}
}

}).as(module);
Loading

0 comments on commit 4aadfe6

Please sign in to comment.