jsrules

0.2.8 • Public • Published

jsrules

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.

build status Coverage Status Code Climate Codacy Badge

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). 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.

// 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:

// 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.

// 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

$ npm install jsrules

bower

$ bower install jsrules

Specs/tests

Execute specs (and code coverage) with either

$ grunt test

or

$ 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. 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
  2. Code coverage with istanbul.
  3. travis-ci integration.
  4. Complexity reports.
  5. Persistence: create examples where
  6. Rules are created, read, updated, and deleted (e.g., Redis or MongoDB)
  7. RuleContexts (facts) are retrieved from multiple data stores
  8. Universally-unique identifiers: create a uuid property for Rules, RuleContexts, and RuleElements (Propositions, Variables, and Operators)

Package Sidebar

Install

npm i jsrules

Weekly Downloads

3

Version

0.2.8

License

MIT

Last publish

Collaborators

  • gregswindle