Skip to content

Commit

Permalink
rename updated to accessedByActions
Browse files Browse the repository at this point in the history
  • Loading branch information
frankthelen committed Oct 17, 2021
1 parent e0833c7 commit 773103d
Show file tree
Hide file tree
Showing 13 changed files with 1,330 additions and 879 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Node.js CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 16.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run lint
- run: npm run test
- run: npm run coverage
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
111 changes: 73 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A small rule engine for Node.

[![Build Status](https://travis-ci.org/frankthelen/rools.svg?branch=master)](https://travis-ci.org/frankthelen/rools)
![main workflow](https://github.com/frankthelen/rools/actions/workflows/main.yml/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/frankthelen/rools/badge.svg?branch=master)](https://coveralls.io/github/frankthelen/rools?branch=master)
[![dependencies Status](https://david-dm.org/frankthelen/rools/status.svg)](https://david-dm.org/frankthelen/rools)
[![Maintainability](https://api.codeclimate.com/v1/badges/d1f858c321b03000fc63/maintainability)](https://codeclimate.com/github/frankthelen/rools/maintainability)
Expand Down Expand Up @@ -197,15 +197,6 @@ await rools1.evaluate(facts);
await rools2.evaluate(facts);
```

`evaluate()` returns an object which might be useful in this scenario.
`updated` lists the names of the fact segments that were actually updated during evaluation.
`fired` is the number of rules that were fired.

```javascript
const { updated, fired } = await rools1.evaluate(facts);
console.log(updated, fired); // e.g., ["user"] 26
```

### Optimization I

It is very common that different rules partially share the same premises.
Expand Down Expand Up @@ -271,24 +262,6 @@ const rule = new Rule({
});
```

One last thing. Look at the example below.
Rools will treat the two premises (`when`) as identical.
This is because `value` is a reference which is *not* evaluated at registration time (`register()`).
Later on, at evaluation time (`evaluate()`), both rules are clearly identical.

```javascript
let value = 2000;
const rule1 = new Rule({
when: (facts) => facts.user.salary >= value,
...
});
value = 3000;
const rule2 = new Rule({
when: (facts) => facts.user.salary >= value,
...
});
```

### Optimization II

When actions fire, changes are made to the facts.
Expand All @@ -313,6 +286,69 @@ await rools.evaluate(facts);
This optimization targets runtime performance.
It unfolds its full potential with a growing number of rules and fact segments.

## Dos and don'ts

### Be careful with non-local variables in premises

Ideally, premises (`when`) are "pure functions" referring to `facts` only.
They should not refer to any other non-local variables.

If they do so, however, please note that non-local variables are resolved at
evaluation time (`evaluate()`) and *not* at registration time (`register()`).

Furthermore, please make sure that non-local variables are constant/stable
during evaluation. Otherwise, premises are not working deterministically.

In the example below, Rools will treat the two premises as identical
assuming that both rules are referring to the exact same `value`.

```javascript
let value = 2000;
const rule1 = new Rule({
when: (facts) => facts.user.salary >= value,
...
});
value = 3000;
const rule2 = new Rule({
when: (facts) => facts.user.salary >= value,
...
});
```

### Don't "generate" rules / Don't create rules in closures

The example below does not work!
Rools would treat all premises (`when`) as identical
assuming that all rules are referring to the exact same `value`.

```javascript
const createRule = (value) => {
rules.push(new Rule({
name: `Rule evaluating ${value}`,
when: (facts) => facts.foo >= value,
then: (facts) => // ...
}));
};
```

### Don't mix premises and actions

Make sure not to mix premises and actions.
In the example below, the if condition should be in `when`, *not* in `then`.
If you have such cases, think about splitting rules or extending rules.

```javascript
const rule = new Rule({
name: "rule",
when: // ...
then: (facts) => {
if (facts.foo < 0) { // not good here!
// ...
}
},
});
```

## Interface

### Create rule engine: `new Rools()`
Expand Down Expand Up @@ -417,14 +453,16 @@ If you don't like the default 'ps', you can change the conflict resolution strat
await rools.evaluate(facts, { strategy: 'sp' });
```

`evaluate()` returns an object providing some information about the past evaluation run.
`updated` lists the names of the fact segments that were actually updated during evaluation.
`fired` is the number of rules that were fired.
`elapsed` is the number of milliseconds needed.
`evaluate()` returns an object providing some debug information about the past evaluation run:

* `fired` -- the number of rules that were fired.
* `elapsed` -- the number of milliseconds needed.
* `accessedByPremises` -- the fact segments that were accessed by premises (`when`).
* `accessedByActions` -- the fact segments that were accessed by actions (`then`). Formerly `updated` but renamed for clarification (but still provided for backward compatibility).

```javascript
const { updated, fired, elapsed } = await rools.evaluate(facts);
console.log(updated, fired, elapsed); // e.g., ["user"] 26 187
const { accessedByActions, fired, elapsed } = await rools.evaluate(facts);
console.log(accessedByActions, fired, elapsed); // e.g., ["user"] 26 187
```

### Logging
Expand Down Expand Up @@ -503,10 +541,7 @@ await rools.register([rule1, rule2, rule3]);
```

`evaluate()` does not return the facts anymore - which was only for convenience anyway.
Instead, it returns an object with some useful information about what it was actually doing.
`updated` lists the names of the fact segments that were actually updated during evaluation.
`fired` is the number of rules that were fired.
`elapsed` is the number of milliseconds needed.
Instead, it returns an object with some useful information.

```javascript
const rools = new Rools();
Expand Down
Loading

0 comments on commit 773103d

Please sign in to comment.