Skip to content

Commit ff4951d

Browse files
Wiki updated with newer additions into 3.0.0 version. Yet to document newer functions like loadJSON,toJSON,turn,prioritize,sync,register and init
1 parent ae1c8ae commit ff4951d

File tree

2 files changed

+98
-75
lines changed

2 files changed

+98
-75
lines changed

README.md

Lines changed: 84 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -5,129 +5,140 @@
55

66
Node-rules is a forward chaining Rules Engine, written on node.js.
77

8-
## How to install
8+
## Installation
99

10-
install this via
10+
install this via npm
1111

1212
npm install node-rules
1313

1414

1515
## Rules
1616

17-
Node-rules takes rules written in JSON format as input. These rules get applied on the specified iputs(facts) to the rule engine.
17+
Node-rules takes rules written in JSON friendly format as input. You can register different rules on the rule engine after initiating it. Once the rule engine is running with registered rule, you can feed it with different fact objects and the rule engine will process them with the various rules registred on it.
1818

19-
A Rules consist of
2019

21-
1. name - the name for the rule
20+
### 1. Defining a Rule
2221

23-
2. conditions - a function which takes inputs and upon returning its results the rule engine executes the corresponding consequence.
22+
A rule will consist of a condition and its corresponding consequence. If the fact you feed into the engine satisfies the condition, then the consequence will run. Also optionally user may choose to define the priority of a rule applied. The rule engine will be applying the rules on the fact according to the priority defined.
2423

25-
3. consequence - a function which gets executed accoring to the return value from a condititon after executed.
24+
Lets see how a sample rule will look like and then proceed to explain the different attributes of a rule.
2625

27-
4. description - the description for the rule
26+
{
27+
"name": "transaction minimum",
28+
"priority": 3,
29+
"on" : true,
30+
"condition": function(R) {
31+
R.when(this && (this.transactionTotal < 500));
32+
},
33+
"consequence": function(R) {
34+
this.result = false;
35+
R.stop();
36+
}
37+
}
2838

29-
5. priority - number which decides the order at which the rule gets applied on the supplied facts.
39+
Above is a sample rule which has mandatory as well as optional parameters. You can choose to use which all attributes you need to use while defining your rule. Now let look into the attributes one by one.
3040

31-
6. on - boolean telling whether or not the rule should be considered by the rule engine.
41+
##### A. condition
42+
Condition is a function where the user can do the checks on the fact provided. The fact varaiable will be available in `this` context of the condition function. Lets see a sample condition below.
3243

33-
## Example rule
44+
"condition": function(R) {
45+
R.when(this && (this.transactionTotal < 500));
46+
}
3447

48+
As you can see, the we have to pass an expression on to the `R.when` API. If the expression evaluates to true for a fact, the corresponding consequence will execute.
3549

36-
{
37-
"name": "transaction minimum",
38-
"description": "blocks transactions below value x",
39-
"priority": 3,
40-
"on":1,
41-
"condition":
42-
function(fact,cb) {
43-
cb(fact && (fact.transactionTotal < 500));
44-
},
45-
"consequence":
46-
function(cb) {
47-
console.log("Rule 1 matched for "+this.name+": blocks transactions below value 500. Rejecting payment.");
48-
this.result = false;
49-
this.process = true;
50-
cb();
51-
}
50+
Its mandatory to have this field.
51+
52+
##### B. consequnce
53+
The consequence is the part where the we define what happens when the condition evaluates to true for a particular fact. Just like in condition, fact varaiable will be available in `this` context. You may utilize it to add extra result attributes if needed.
54+
55+
"consequence": function(R) {
56+
this.result = false;
57+
R.stop();
5258
}
59+
In the above example we use an additional parameter `result` to communicate to the code outside the rule engine that the fact was succeeded. Also the Rule API provides a number of functions here to control the flow of the rule engine. They are `R.stop()`, `R.restart()` and `R.next()`. Stop refers to stop processing the rule engine. Restart tells the rule engine to start applying all the rules again to the fact. Next is to instruct the rule engine to continue applying the rest of the rules to the fact before stoping.
60+
61+
Its mandatory to have this field.
62+
63+
##### C. priority
64+
This field is used to specify the priority of a rule. The rules with higher priority will be applied on the fact first and then followed by lower priority rules. You can have multiple rules with same priority and the engine will not ensure the order in that case.
65+
66+
Its not mandatory to have this field.
67+
68+
##### D. on
69+
This is field is used to store the state of a rule. This is used to activate and diactivate rules at run time. Rules with `on` set to `false` will not be applied on the facts.
70+
71+
It is not mandatory to have this field.
72+
73+
##### E. add a unique attribute
74+
It is suggested that you should add a property which can be used as a unique identifier for a rule. Why it is because when you need to dynamically turn on/off or change priority of a rule, you will need a filter to select a rule from the engine via the APIs. That time you may use the unique property as a key for the filter for selection process.
75+
76+
Suppose that in the above example `name` is unique for each rule. Then for changing state or re prioritizing a rule at run time, you may use a filter like `{"name":"transaction minimum"}`.
5377

78+
Again its optional to add a unique identifier. You may ignore adding it to your rules if you are not changing rule states at run time.
5479

55-
## Facts
5680

57-
Facts are those input json values on which the rule engine applies its rule to obtain results. A fact can have multiple attributes.
81+
### 2. Defining a Fact
82+
Facts are those input json values on which the rule engine applies its rule to obtain results. A fact can have multiple attributes as you decide.
5883

59-
## Example Fact
84+
Example Fact may look like
6085

6186
{
6287
"userIP": "27.3.4.5",
6388
"name":"user4",
64-
"eventRiskFactor":8,
65-
"userCredibility":2,
6689
"application":"MOB2",
6790
"userLoggedIn":true,
6891
"transactionTotal":400,
6992
"cardType":"Credit Card",
70-
"cardIssuer":"VISA",
71-
72-
}
93+
}
7394

74-
##Usage
95+
### 3. Using the Rule Engine
7596

76-
The example below shows how to use the rule engine to apply a sample rule on a specific fact.
97+
The example below shows how to use the rule engine to apply a sample rule on a specific fact. Rules fed into the rule engine may be as Array of rules or as individual rule objects.
7798

7899
``` js
79-
100+
//import the package
80101
var RuleEngine = require('node-rules');
81102

103+
//define the rules
82104
var rules = [{
83-
"name": "transaction minimum",
84-
"description": "blocks transactions below value x",
85-
"priority": 3,
86-
"on":1,
87-
"condition":
88-
function(fact,cb) {
89-
cb(fact && (fact.transactionTotal < 500));
90-
},
91-
"consequence":
92-
function(cb) {
93-
console.log("Rule 1 matched for "+this.name+": blocks transactions below value 500. Rejecting payment.");
94-
this.result = false;
95-
this.process = true;
96-
cb();
97-
}
98-
}];
99-
105+
"condition": function(R) {
106+
R.when(this && (this.transactionTotal < 500));
107+
},
108+
"consequence": function(R) {
109+
this.result = false;
110+
R.stop();
111+
}
112+
}];
113+
/*as you can see above we removed the priority and on properties for this example as they are optional.*/
114+
115+
//sample fact to run the rules on
100116
var fact = {
101-
"userIP": "27.3.4.5",
102-
"name":"user4",
103-
"eventRiskFactor":8,
104-
"userCredibility":2,
105-
"application":"MOB2",
106-
"userLoggedIn":true,
107-
"transactionTotal":400,
108-
"cardType":"Credit Card",
109-
"cardIssuer":"VISA",
110-
111-
};
112-
117+
"userIP": "27.3.4.5",
118+
"name":"user4",
119+
"application":"MOB2",
120+
"userLoggedIn":true,
121+
"transactionTotal":400,
122+
"cardType":"Credit Card",
123+
};
124+
125+
//initialize the rule engine
113126
var R = new RuleEngine(rules);
114127

128+
//Now pass the fact on to the rule engine for results
115129
R.execute(fact,function(result){
116130

117131
if(result.result)
118-
console.log("\n-----Payment Accepted for----\n");
132+
console.log("\n-----Payment Accepted----\n");
119133
else
120-
console.log("\n-----Payment Rejected for----\n");
121-
122-
console.log(result);
134+
console.log("\n-----Payment Rejected----\n");
123135

124136
});
125137
```
126138

127139

128-
129140
## Credits
130141

131-
Both the rules and the facts used in this module are based on the node module [jools](https://github.com/tdegrunt/jools).
142+
The JSON friendly rule formats used in this module were initially based on the node module [jools](https://github.com/tdegrunt/jools).
132143
Its a modified version of jools with a non blocking version of applying the rule engine on the facts.
133144
The rule engine logic was been modified sothat the rule executions on separate facts donot block each other.

lib/node-rules.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,25 @@
4545
RuleEngine.prototype.sync = function() {
4646

4747
this.activeRules = this.rules.filter(function(a) {
48-
if(a.on === 1) {
48+
49+
if(typeof(a.on) === "undefined"){
50+
a.on = true;
51+
}
52+
53+
if(a.on === true) {
4954
return a;
5055
}
56+
5157
});
5258

5359
this.activeRules.sort(function(a, b) {
54-
return b.priority - a.priority;
60+
61+
if(a.priority && b.priority) {
62+
return b.priority - a.priority;
63+
} else {
64+
return 0;
65+
}
66+
5567
});
5668

5769
};

0 commit comments

Comments
 (0)