-
Notifications
You must be signed in to change notification settings - Fork 181
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 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
1 parent
93edb98
commit 4aadfe6
Showing
18 changed files
with
784 additions
and
451 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
|
||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
Oops, something went wrong.