Skip to content

Commit

Permalink
Merge pull request #143 from raymondfeng/feature/enable-session-halt
Browse files Browse the repository at this point in the history
Allow session.halt even for `match()`
  • Loading branch information
doug-martin committed Feb 25, 2015
2 parents 61d427f + a510303 commit d4a2705
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 46 deletions.
17 changes: 17 additions & 0 deletions lib/constraint.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,5 +236,22 @@ Constraint.extend({
}
}).as(exports, "FromConstraint");

Constraint.extend({
instance: {
constructor: function(func, options) {
this.type = "custom";
this.fn = func;
this.options = options;
},

equal: function(constraint) {
return instanceOf(constraint, this._static) && this.fn === constraint.constraint;
},

"assert": function(fact, fh) {
return this.fn(fact, fh);
}
}
}).as(exports, "CustomConstraint");


3 changes: 3 additions & 0 deletions lib/constraintMatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ exports.getSourceMatcher = function (rule, options, equality) {
};

exports.toConstraints = function (constraint, options) {
if(typeof constraint === 'function') {
return [new atoms.CustomConstraint(constraint, options)];
}
//constraint.split("&&")
return lang.toConstraints(constraint, options);
};
Expand Down
16 changes: 15 additions & 1 deletion lib/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ module.exports = declare(EventEmitter, {
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);
extd.bindAll(this, "halt", "assert", "retract", "modify", "focus", "emit", "getFacts");
extd.bindAll(this, "halt", "assert", "retract", "modify", "focus",
"emit", "getFacts", "getFact");
},

getFacts: function (Type) {
Expand All @@ -40,16 +41,29 @@ module.exports = declare(EventEmitter, {
return ret;
},

getFact: function (Type) {
var ret;
if (Type) {
ret = this.workingMemory.getFactsByType(Type);
} else {
ret = this.workingMemory.getFacts();
}
return ret && ret[0];
},

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

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

Expand Down
107 changes: 63 additions & 44 deletions lib/rule.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ var extd = require("./extended"),
FromExistsPattern = pattern.FromExistsPattern,
CompositePattern = pattern.CompositePattern;

var parseConstraint = function(constraint) {
if (typeof constraint === 'function') {
// No parsing is needed for constraint functions
return constraint;
}
return parser.parseConstraint(constraint);
};

var parseExtra = extd
.switcher()
.isUndefinedOrNull(function () {
Expand Down Expand Up @@ -66,55 +74,63 @@ var normailizeConstraint = extd
})
.switcher();


var getParamTypeSwitch = extd
var getParamType = function getParamType(type, scope) {
scope = scope || {};
var getParamTypeSwitch = extd
.switcher()
.isEq("string", function () {
return String;
.isEq("string", function() {
return String;
})
.isEq("date", function () {
return Date;
.isEq("date", function() {
return Date;
})
.isEq("array", function () {
return Array;
.isEq("array", function() {
return Array;
})
.isEq("boolean", function () {
return Boolean;
.isEq("boolean", function() {
return Boolean;
})
.isEq("regexp", function () {
return RegExp;
.isEq("regexp", function() {
return RegExp;
})
.isEq("number", function () {
return Number;
.isEq("number", function() {
return Number;
})
.isEq("object", function () {
return Object;
.isEq("object", function() {
return Object;
})
.isEq("hash", function () {
return Object;
.isEq("hash", function() {
return Object;
})
.def(function (param) {
throw new TypeError("invalid param type " + param);
.def(function(param) {
throw new TypeError("invalid param type " + param);
})
.switcher();


var getParamType = extd
var _getParamType = extd
.switcher()
.isString(function (param) {
.isString(function(param) {
var t = scope[param];
if(!t) {
return getParamTypeSwitch(param.toLowerCase());
} else {
return t;
}
})
.isFunction(function (func) {
return func;
.isFunction(function(func) {
return func;
})
.deepEqual([], function () {
return Array;
.deepEqual([], function() {
return Array;
})
.def(function (param) {
throw new Error("invalid param type " + param);
.def(function(param) {
throw new Error("invalid param type " + param);
})
.switcher();

return _getParamType(type);
};

var parsePattern = extd
.switcher()
.containsAt("or", 0, function (condition) {
Expand All @@ -130,20 +146,20 @@ var parsePattern = extd
if (condition[4] && condition[4].from) {
return [
new FromNotPattern(
getParamType(condition[0]),
getParamType(condition[0], condition.scope),
condition[1] || "m",
parser.parseConstraint(condition[2] || "true"),
parseConstraint(condition[2] || "true"),
condition[3] || {},
parser.parseConstraint(condition[4].from),
parseConstraint(condition[4].from),
{scope: condition.scope, pattern: condition[2]}
)
];
} else {
return [
new NotPattern(
getParamType(condition[0]),
getParamType(condition[0], condition.scope),
condition[1] || "m",
parser.parseConstraint(condition[2] || "true"),
parseConstraint(condition[2] || "true"),
condition[3] || {},
{scope: condition.scope, pattern: condition[2]}
)
Expand All @@ -156,45 +172,48 @@ var parsePattern = extd
if (condition[4] && condition[4].from) {
return [
new FromExistsPattern(
getParamType(condition[0]),
getParamType(condition[0], condition.scope),
condition[1] || "m",
parser.parseConstraint(condition[2] || "true"),
parseConstraint(condition[2] || "true"),
condition[3] || {},
parser.parseConstraint(condition[4].from),
parseConstraint(condition[4].from),
{scope: condition.scope, pattern: condition[2]}
)
];
} else {
return [
new ExistsPattern(
getParamType(condition[0]),
getParamType(condition[0], condition.scope),
condition[1] || "m",
parser.parseConstraint(condition[2] || "true"),
parseConstraint(condition[2] || "true"),
condition[3] || {},
{scope: condition.scope, pattern: condition[2]}
)
];
}
})
.def(function (condition) {
if (typeof condition === 'function') {
return [condition];
}
condition = normailizeConstraint(condition);
if (condition[4] && condition[4].from) {
return [
new FromPattern(
getParamType(condition[0]),
getParamType(condition[0], condition.scope),
condition[1] || "m",
parser.parseConstraint(condition[2] || "true"),
parseConstraint(condition[2] || "true"),
condition[3] || {},
parser.parseConstraint(condition[4].from),
parseConstraint(condition[4].from),
{scope: condition.scope, pattern: condition[2]}
)
];
} else {
return [
new ObjectPattern(
getParamType(condition[0]),
getParamType(condition[0], condition.scope),
condition[1] || "m",
parser.parseConstraint(condition[2] || "true"),
parseConstraint(condition[2] || "true"),
condition[3] || {},
{scope: condition.scope, pattern: condition[2]}
)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"author": "Doug Martin (http://c2fo.com)",
"main": "index.js",
"scripts": {
"test": "it -r dot",
"test": "it -r spec",
"create-doc": "rm -rf docs/* && coddoc -d ./lib -f multi-html"
},
"directories": {
Expand Down
2 changes: 2 additions & 0 deletions test/flow.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
require('./flow/index');
1 change: 1 addition & 0 deletions test/flow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ require("./events.test");
require("./exists.test");
require("./from.test");
require("./matchUntil.halt");
require("./match.halt");
require("./not.test");
require("./or.test");
require("./rule.test");
Expand Down
36 changes: 36 additions & 0 deletions test/flow/match.halt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use strict";
var it = require("it"),
nools = require("../../"),
assert = require("assert");

it.describe("#matchHalt", function (it) {

function Count(c) {
this.count = c;
}

var session, flow = nools.flow("Match with halt Flow", function (flow) {

flow.rule("Stop", [Count, "c", "c.count == 6"], function () {
this.halt();
});

flow.rule("Inc", [Count, "c"], function (facts) {
facts.c.count++;
this.modify(facts.c);
});

});

it.beforeEach(function () {
session = flow.getSession(new Count(0));
});

it.should("stop match with halt", function () {
return session.match().then(function (err) {
assert.isUndefinedOrNull(err);
assert.equal(session.getFacts(Count)[0].count, 6);
});

});
});
45 changes: 45 additions & 0 deletions test/rules.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,51 @@ it.describe("Rule", function (it) {
});
});

it.describe("custom function as constraints", function (it) {

var MyConstraint = function(fact) {
return true;
};

it.should("create for String function with custom constraint", function() {
var rule = rules.createRule("My Rule", [String, "s", MyConstraint], cb);
assert.isNotNull(rule);
assert.lengthOf(rule, 1);
rule = rule[0];
assert.equal(rule.name, "My Rule");
assert.isNotNull(rule.pattern);
var pattern = rule.pattern;
assert.equal(pattern.alias, "s");
assert.lengthOf(pattern.constraints, 2);
assert.instanceOf(pattern.constraints[0], constraints.ObjectConstraint);
assert.equal(pattern.constraints[0].constraint, String);
assert.instanceOf(pattern.constraints[1], constraints.CustomConstraint);
assert.strictEqual(rule.cb, cb);
});
});

it.describe("custom type via scope", function (it) {

var MyType = function(name) {
this.name = name;
};

it.should("create for String function with custom constraint", function() {
var rule = rules.createRule("My Rule", {scope: {MyType: MyType}}, ['MyType', "s", "s.name === 'X'"], cb);
assert.isNotNull(rule);
assert.lengthOf(rule, 1);
rule = rule[0];
assert.equal(rule.name, "My Rule");
assert.isNotNull(rule.pattern);
var pattern = rule.pattern;
assert.equal(pattern.alias, "s");
assert.lengthOf(pattern.constraints, 2);
assert.instanceOf(pattern.constraints[0], constraints.ObjectConstraint);
assert.equal(pattern.constraints[0].constraint, MyType);
assert.strictEqual(rule.cb, cb);
});
});

it.should("create a composite rule", function () {
var rule = rules.createRule("My Rule", [
["string", "s"],
Expand Down

0 comments on commit d4a2705

Please sign in to comment.