README.md
# 🚨 `jsrules` is now<br>🚨 [`commonality/archetypes-rules`](https://github.com/commonality/archetypes-rules).
<details><summary>View the <strong>jsrules</strong> README anyway...</summary>
<hr>
`jsrules` is a JavaScript rule engine that models formal propositional logic. It allows you to separate conditional logic from source code and database triggers in a reusable package, where explicit rules can be independently defined and managed.
[![License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](http://www.opensource.org/licenses/MIT)
[![Build Status](https://travis-ci.org/gregswindle/jsrules.svg?style=flat&branch=master)](https://travis-ci.org/gregswindle/jsrules)
[![Coverage Status](https://coveralls.io/repos/github/gregswindle/jsrules/badge.svg?branch=master)](https://coveralls.io/github/gregswindle/jsrules?branch=master)
[![Code Climate](https://codeclimate.com/github/gregswindle/jsrules/badges/gpa.svg?style=flatl&branch=master)](https://codeclimate.com/github/gregswindle/jsrules)
[![Codacy Badge](https://api.codacy.com/project/badge/grade/b6e496204f604f0e9955ca169fc8a1d7)](https://www.codacy.com/app/greg_7/jsrules)
[![NSP Status](https://nodesecurity.io/orgs/gregswindle/projects/8f3b03ea-faaa-4844-ab12-d2bb32067f96/badge?style=flat)](https://nodesecurity.io/orgs/gregswindle/projects/8f3b03ea-faaa-4844-ab12-d2bb32067f96)
## Overview of `jsrules`
### What are `Rules`?
Rules are explicit constraints that govern actions.
Rules are defined and stored as JSON. They consist of three types of `RuleElements`:
* **Propositions**: statements that are either, `true`, `false`, or `null` (unknown)
* **Variables**: symbols that represent the value of something
* **Operators**: Boolean and quantifier operators
### `RuleContexts` (aka "facts") and `Rules`
`RuleContexts` are facts, stored in text files, databases, etc., that provide the informational context for the execution of `Rules`. `Rules` evaluate `RuleContexts`, returning a `Proposition` that tells us whether a given set of facts conform to the defined `Rule`.
`RuleElements` are evaluated using [Reverse Polish Notation (RPN)](https://en.wikipedia.org/wiki/Reverse_Polish_notation). See the examples below for details.
### Example 1: Is this customer eligible for a discount?
Executing a Rule is simple. Suppose we have a very simple rule that checks whether a customer is eligible for a discount. In order to be eligible, the customer simply needs to be a Gold Card holder.
```javascript
// Create the rule
var rule = new jsrules.Rule('eligibleForDiscount');
// Add a Proposition, i.e., a statement that has a value of true or false
rule.addProposition('customerIsGoldCardHolder', true);
// Create a RuleContext, i.e., a "Fact"
var ruleContext = new jsrules.RuleContext('eligibleForDiscountContext');
// Provide the truth statement as to whether the actual customer
// has a Gold Card
ruleContext.addProposition('customerIsGoldCardHolder', true);
// Evaluate
var result = rule.evaluate(ruleContext);
// Log the resulting Proposition
console.log(result.toString());
// Outputs
// Proposition statement = customerIsGoldCardHolder, value = true
```
### Example 2: Group discount for six or more people
Say you provide a discount to a group of six or more people:
```javascript
// Create the rule
var rule = new jsrules.Rule('eligibleForGroupDiscount');
// Declare a "placeholder" variable for the actual number of people
// (This value will be retrieved from the RuleContext)
rule.addVariable('actualNumPeople', null);
// Declare the minimun number of people required for discount
rule.addVariable('minNumPeople', 6);
// Compare the two, i.e.,
// actualNumPeople >= minNumPeople
rule.addOperator(jsrules.Operator.GREATER_THAN_OR_EQUAL_TO);
// Create a RuleContext, i.e., a "Fact"
var ruleContext = new jsrules.RuleContext('eligibleForGroupDiscountFact');
// How many people are there?
ruleContext.addVariable('actualNumPeople', 5);
// Declare the "placeholder" minimun number of people required for discount
// (This value will be retrieved from the Rule)
ruleContext.addVariable('minNumPeople', null);
// Evaluate
var result = rule.evaluate(ruleContext);
// Log the resulting Proposition
console.log(result.toString());
// OUTPUT:
// Proposition statement =
// (actualNumPeople >= minNumPeople), value = false
```
### Example 3: Is an airline passenger eligible for an upgrade?
In this example, we’re determining whether a given airline passenger is eligible to have their coach seat upgraded to a first-class seat. In order to be eligible, a passenger must:
* be in economy class now and either
* hold a Gold member card or
* hold a Silver member card and
* their carry-on luggage must be less than or equal to 15.0 pounds.
In order to determine this, we must compare a passenger’s facts with our rule.
```javascript
// Create the rule
var rule = new jsrules.Rule('eligibleForUpgrade');
// Populate the rule using method chaining
rule.addProposition('passengerIsEconomy', true)
.addProposition('passengerIsGoldCardHolder', true)
.addProposition('passengerIsSilverCardHolder', true)
.addOperator(jsrules.Operator.OR)
.addOperator(jsrules.Operator.AND)
.addVariable('passengerCarryOnBaggageWeight', null)
.addVariable('passengerCarryOnBaggageAllowance', 15.0)
.addOperator(jsrules.Operator.LESS_THAN_OR_EQUAL_TO)
.addOperator(jsrules.Operator.AND);
// Create the RuleContext
var fact = new jsrules.RuleContext('eligibleForUpgradeFact');
// Load it with the facts about the passenger
fact.addProposition('passengerIsEconomy', true)
.addProposition('passengerIsGoldCardHolder', true)
.addProposition('passengerIsSilverCardHolder', false)
.addVariable('passengerCarryOnBaggageWeight', 10.0)
.addVariable('passengerCarryOnBaggageAllowance', null);
// Log the resulting Proposition
console.log(rule.evaluate(fact));
// Outputs (as a single string; newlines added here for readability):
// Proposition statement = (
// (passengerIsEconomy AND
// (passengerIsGoldCardHolder OR passengerIsSilverCardHolder)
// ) AND (
// passengerCarryOnBaggageWeight <= passengerCarryOnBaggageAllowance
// )
// ), value = true
```
## Installation
### `npm`
``` bash
$ npm install jsrules
```
### `bower`
```bash
$ bower install jsrules
```
## Specs/tests
Execute specs (and code coverage) with either
```bash
$ grunt test
```
or
```bash
$ npm test
```
## The origin of `jsrules`: the Rule Archetype Pattern
For a detailed description of `jsrules`, please read chapter 12, “Rule archetype pattern,” in [_Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML_](https://www.google.com/search?q=Enterprise+Patterns+and+MDA%3A+Building+Better+Software+with+Archetype+Patterns+and+UML&rlz=1C1CHFX_enUS432US432&oq=Enterprise+Patterns+and+MDA%3A+Building+Better+Software+with+Archetype+Patterns+and+UML&aqs=chrome..69i57&sourceid=chrome&ie=UTF-8). I cannot recommend this book enough, and my thanks go to its authors — Jim Arlow and Ila Neustadt — for their permission to avail the “Rule Archetype Pattern” to JavaScript developers.
## Development roadmap
1. ~~Quality assurance~~
1. ~~Code coverage with `istanbul`.~~
2. ~~`travis-ci` integration.~~
3. ~~Complexity reports.~~
2. Add more operators from `lodash`, e.g., `includes`.
</details>